`Solve' operation is relatively simple in Mines.
[sgt/puzzles] / mines.c
diff --git a/mines.c b/mines.c
index e0add2a..725fdcf 100644 (file)
--- a/mines.c
+++ b/mines.c
@@ -31,7 +31,7 @@
 #include "puzzles.h"
 
 enum {
-    COL_BACKGROUND,
+    COL_BACKGROUND, COL_BACKGROUND2,
     COL_1, COL_2, COL_3, COL_4, COL_5, COL_6, COL_7, COL_8,
     COL_MINE, COL_BANG, COL_CROSS, COL_FLAG, COL_FLAGBASE, COL_QUERY,
     COL_HIGHLIGHT, COL_LOWLIGHT,
@@ -70,6 +70,7 @@ struct mine_layout {
 
 struct game_state {
     int w, h, n, dead, won;
+    int used_solve, just_used_solve;
     struct mine_layout *layout;               /* real mine positions */
     signed char *grid;                        /* player knowledge */
     /*
@@ -2062,6 +2063,7 @@ static game_state *new_game(midend_data *me, game_params *params, char *desc)
     state->h = params->h;
     state->n = params->n;
     state->dead = state->won = FALSE;
+    state->used_solve = state->just_used_solve = FALSE;
 
     wh = state->w * state->h;
 
@@ -2089,6 +2091,8 @@ static game_state *new_game(midend_data *me, game_params *params, char *desc)
        state->layout->me = me;
 
     } else {
+       state->layout->rs = NULL;
+       state->layout->me = NULL;
 
        state->layout->mines = snewn(wh, char);
        x = atoi(desc);
@@ -2154,6 +2158,8 @@ static game_state *dup_game(game_state *state)
     ret->n = state->n;
     ret->dead = state->dead;
     ret->won = state->won;
+    ret->used_solve = state->used_solve;
+    ret->just_used_solve = state->just_used_solve;
     ret->layout = state->layout;
     ret->layout->refcount++;
     ret->grid = snewn(ret->w * ret->h, char);
@@ -2177,7 +2183,43 @@ static void free_game(game_state *state)
 static game_state *solve_game(game_state *state, game_aux_info *aux,
                              char **error)
 {
-    return NULL;
+    /*
+     * Simply expose the entire grid as if it were a completed
+     * solution.
+     */
+    game_state *ret;
+    int yy, xx;
+
+    if (!state->layout->mines) {
+        *error = "Game has not been started yet";
+        return NULL;
+    }
+
+    ret = dup_game(state);
+    for (yy = 0; yy < ret->h; yy++)
+        for (xx = 0; xx < ret->w; xx++) {
+
+            if (ret->layout->mines[yy*ret->w+xx]) {
+                ret->grid[yy*ret->w+xx] = -1;
+            } else {
+                int dx, dy, v;
+
+                v = 0;
+
+                for (dx = -1; dx <= +1; dx++)
+                    for (dy = -1; dy <= +1; dy++)
+                        if (xx+dx >= 0 && xx+dx < ret->w &&
+                            yy+dy >= 0 && yy+dy < ret->h &&
+                            ret->layout->mines[(yy+dy)*ret->w+(xx+dx)])
+                            v++;
+
+                ret->grid[yy*ret->w+xx] = v;
+            }
+        }
+    ret->used_solve = ret->just_used_solve = TRUE;
+    ret->won = TRUE;
+
+    return ret;
 }
 
 static char *game_text_format(game_state *state)
@@ -2227,8 +2269,8 @@ static void free_ui(game_ui *ui)
     sfree(ui);
 }
 
-static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
-                            int button)
+static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds,
+                             int x, int y, int button)
 {
     game_state *ret;
     int cx, cy;
@@ -2269,6 +2311,7 @@ static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
            return NULL;
 
        ret = dup_game(from);
+        ret->just_used_solve = FALSE;
        ret->grid[cy * from->w + cx] ^= (-2 ^ -1);
 
        return ret;
@@ -2291,6 +2334,7 @@ static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
        if (from->grid[cy * from->w + cx] == -2 ||
            from->grid[cy * from->w + cx] == -3) {
            ret = dup_game(from);
+            ret->just_used_solve = FALSE;
            open_square(ret, cx, cy);
            return ret;
        }
@@ -2316,6 +2360,7 @@ static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
 
            if (n == from->grid[cy * from->w + cx]) {
                ret = dup_game(from);
+                ret->just_used_solve = FALSE;
                for (dy = -1; dy <= +1; dy++)
                    for (dx = -1; dx <= +1; dx++)
                        if (cx+dx >= 0 && cx+dx < ret->w &&
@@ -2364,6 +2409,10 @@ static float *game_colours(frontend *fe, game_state *state, int *ncolours)
 
     frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
 
+    ret[COL_BACKGROUND2 * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 19.0 / 20.0;
+    ret[COL_BACKGROUND2 * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 19.0 / 20.0;
+    ret[COL_BACKGROUND2 * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 19.0 / 20.0;
+
     ret[COL_1 * 3 + 0] = 0.0F;
     ret[COL_1 * 3 + 1] = 0.0F;
     ret[COL_1 * 3 + 2] = 1.0F;
@@ -2464,7 +2513,8 @@ static void draw_tile(frontend *fe, int x, int y, int v, int bg)
            /*
             * Omit the highlights in this case.
             */
-           draw_rect(fe, x, y, TILE_SIZE, TILE_SIZE, bg);
+           draw_rect(fe, x, y, TILE_SIZE, TILE_SIZE,
+                      bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg);
            draw_line(fe, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
            draw_line(fe, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
        } else {
@@ -2532,7 +2582,8 @@ static void draw_tile(frontend *fe, int x, int y, int v, int bg)
         * on), we clear the square to COL_BANG.
         */
         draw_rect(fe, x, y, TILE_SIZE, TILE_SIZE,
-                 (v == 65 ? COL_BANG : bg));
+                 (v == 65 ? COL_BANG :
+                   bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg));
        draw_line(fe, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
        draw_line(fe, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
 
@@ -2696,7 +2747,10 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
        if (state->dead) {
            sprintf(statusbar, "GAME OVER!");
        } else if (state->won) {
-           sprintf(statusbar, "COMPLETED!");
+            if (state->used_solve)
+                sprintf(statusbar, "Auto-solved.");
+            else
+                sprintf(statusbar, "COMPLETED!");
        } else {
            sprintf(statusbar, "Mines marked: %d / %d", markers, mines);
        }
@@ -2713,6 +2767,9 @@ static float game_anim_length(game_state *oldstate, game_state *newstate,
 static float game_flash_length(game_state *oldstate, game_state *newstate,
                               int dir, game_ui *ui)
 {
+    if (oldstate->used_solve || newstate->used_solve)
+        return 0.0F;
+
     if (dir > 0 && !oldstate->dead && !oldstate->won) {
        if (newstate->dead) {
            ui->flash_is_death = TRUE;
@@ -2758,7 +2815,7 @@ const struct game thegame = {
     new_game,
     dup_game,
     free_game,
-    FALSE, solve_game,
+    TRUE, solve_game,
     TRUE, game_text_format,
     new_ui,
     free_ui,