sfree(params);
}
-static game_params *dup_params(game_params *params)
+static game_params *dup_params(const game_params *params)
{
game_params *ret = snew(game_params);
*ret = *params; /* structure copy */
}
}
-static char *encode_params(game_params *params, int full)
+static char *encode_params(const game_params *params, int full)
{
char ret[400];
int len;
return dupstr(ret);
}
-static config_item *game_configure(game_params *params)
+static config_item *game_configure(const game_params *params)
{
config_item *ret;
char buf[80];
return ret;
}
-static game_params *custom_params(config_item *cfg)
+static game_params *custom_params(const config_item *cfg)
{
game_params *ret = snew(game_params);
return ret;
}
-static char *validate_params(game_params *params, int full)
+static char *validate_params(const game_params *params, int full)
{
/*
* Lower limit on grid size: each dimension must be at least 3.
return grid;
}
-static char *new_game_desc(game_params *params, random_state *rs,
+static char *new_game_desc(const game_params *params, random_state *rs,
char **aux, int interactive)
{
/*
}
}
-static char *validate_desc(game_params *params, char *desc)
+static char *validate_desc(const game_params *params, const char *desc)
{
int wh = params->w * params->h;
int x, y;
return 0;
}
-static game_state *new_game(midend *me, game_params *params, char *desc)
+static game_state *new_game(midend *me, const game_params *params,
+ const char *desc)
{
game_state *state = snew(game_state);
int i, wh, x, y, masked;
return state;
}
-static game_state *dup_game(game_state *state)
+static game_state *dup_game(const game_state *state)
{
game_state *ret = snew(game_state);
sfree(state);
}
-static char *solve_game(game_state *state, game_state *currstate,
- char *aux, char **error)
+static char *solve_game(const game_state *state, const game_state *currstate,
+ const char *aux, char **error)
{
if (!state->layout->mines) {
*error = "Game has not been started yet";
return dupstr("S");
}
-static int game_can_format_as_text_now(game_params *params)
+static int game_can_format_as_text_now(const game_params *params)
{
return TRUE;
}
-static char *game_text_format(game_state *state)
+static char *game_text_format(const game_state *state)
{
char *ret;
int x, y;
int cur_x, cur_y, cur_visible;
};
-static game_ui *new_ui(game_state *state)
+static game_ui *new_ui(const game_state *state)
{
game_ui *ui = snew(game_ui);
ui->hx = ui->hy = -1;
sfree(ui);
}
-static char *encode_ui(game_ui *ui)
+static char *encode_ui(const game_ui *ui)
{
char buf[80];
/*
return dupstr(buf);
}
-static void decode_ui(game_ui *ui, char *encoding)
+static void decode_ui(game_ui *ui, const char *encoding)
{
int p= 0;
sscanf(encoding, "D%d%n", &ui->deaths, &p);
ui->completed = TRUE;
}
-static void game_changed_state(game_ui *ui, game_state *oldstate,
- game_state *newstate)
+static void game_changed_state(game_ui *ui, const game_state *oldstate,
+ const game_state *newstate)
{
if (newstate->won)
ui->completed = TRUE;
int cur_x, cur_y; /* -1, -1 for no cursor displayed. */
};
-static char *interpret_move(game_state *from, game_ui *ui, const game_drawstate *ds,
- int x, int y, int button)
+static char *interpret_move(const game_state *from, game_ui *ui,
+ const game_drawstate *ds,
+ int x, int y, int button)
{
int cx, cy;
char buf[256];
}
}
-static game_state *execute_move(game_state *from, char *move)
+static game_state *execute_move(const game_state *from, const char *move)
{
int cy, cx;
game_state *ret;
* Drawing routines.
*/
-static void game_compute_size(game_params *params, int tilesize,
- int *x, int *y)
+static void game_compute_size(const game_params *params, int tilesize,
+ int *x, int *y)
{
/* Ick: fake up `ds->tilesize' for macro expansion purposes */
struct { int tilesize; } ads, *ds = &ads;
}
static void game_set_size(drawing *dr, game_drawstate *ds,
- game_params *params, int tilesize)
+ const game_params *params, int tilesize)
{
ds->tilesize = tilesize;
}
return ret;
}
-static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
+static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
{
struct game_drawstate *ds = snew(struct game_drawstate);
draw_update(dr, x, y, TILE_SIZE, TILE_SIZE);
}
-static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
- game_state *state, int dir, game_ui *ui,
- float animtime, float flashtime)
+static void game_redraw(drawing *dr, game_drawstate *ds,
+ const game_state *oldstate, const game_state *state,
+ int dir, const game_ui *ui,
+ float animtime, float flashtime)
{
int x, y;
- int mines, markers, bg;
+ int mines, markers, closed, bg;
int cx = -1, cy = -1, cmoved;
if (flashtime) {
/*
* Now draw the tiles. Also in this loop, count up the number
- * of mines and mine markers.
+ * of mines, mine markers, and closed squares.
*/
- mines = markers = 0;
+ mines = markers = closed = 0;
for (y = 0; y < ds->h; y++)
for (x = 0; x < ds->w; x++) {
int v = state->grid[y*ds->w+x], cc = 0;
+ if (v < 0)
+ closed++;
if (v == -1)
markers++;
if (state->layout->mines && state->layout->mines[y*ds->w+x])
else
sprintf(statusbar, "COMPLETED!");
} else {
+ int safe_closed = closed - mines;
sprintf(statusbar, "Marked: %d / %d", markers, mines);
+ if (safe_closed > 0 && safe_closed <= 9) {
+ /*
+ * In the situation where there's a very small number
+ * of _non_-mine squares left unopened, it's helpful
+ * to mention that number in the status line, to save
+ * the player from having to count it up
+ * painstakingly. This is particularly important if
+ * the player has turned up the mine density to the
+ * point where game generation resorts to its weird
+ * pathological fallback of a very dense mine area
+ * with a clearing in the middle, because that often
+ * leads to a deduction you can only make by knowing
+ * that there is (say) exactly one non-mine square to
+ * find, and it's a real pain to have to count up two
+ * large numbers of squares and subtract them to get
+ * that value of 1.
+ *
+ * The threshold value of 8 for displaying this
+ * information is because that's the largest number of
+ * non-mine squares that might conceivably fit around
+ * a single central square, and the most likely way to
+ * _use_ this information is to observe that if all
+ * the remaining safe squares are adjacent to _this_
+ * square then everything else can be immediately
+ * flagged as a mine.
+ */
+ if (safe_closed == 1) {
+ sprintf(statusbar + strlen(statusbar),
+ " (1 safe square remains)");
+ } else {
+ sprintf(statusbar + strlen(statusbar),
+ " (%d safe squares remain)", safe_closed);
+ }
+ }
}
if (ui->deaths)
sprintf(statusbar + strlen(statusbar),
}
}
-static float game_anim_length(game_state *oldstate, game_state *newstate,
- int dir, game_ui *ui)
+static float game_anim_length(const game_state *oldstate,
+ const game_state *newstate, int dir, game_ui *ui)
{
return 0.0F;
}
-static float game_flash_length(game_state *oldstate, game_state *newstate,
- int dir, game_ui *ui)
+static float game_flash_length(const game_state *oldstate,
+ const game_state *newstate, int dir, game_ui *ui)
{
if (oldstate->used_solve || newstate->used_solve)
return 0.0F;
return 0.0F;
}
-static int game_status(game_state *state)
+static int game_status(const game_state *state)
{
/*
* We report the game as lost only if the player has used the
return state->won ? (state->used_solve ? -1 : +1) : 0;
}
-static int game_timing_state(game_state *state, game_ui *ui)
+static int game_timing_state(const game_state *state, game_ui *ui)
{
if (state->dead || state->won || ui->completed || !state->layout->mines)
return FALSE;
return TRUE;
}
-static void game_print_size(game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, float *x, float *y)
{
}
-static void game_print(drawing *dr, game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, int tilesize)
{
}
const struct game thegame = {
"Mines", "games.mines", "mines",
default_params,
- game_fetch_preset,
+ game_fetch_preset, NULL,
decode_params,
encode_params,
free_params,