chiark / gitweb /
Mines: show the number of safe squares left, if it's small.
authorSimon Tatham <anakin@pobox.com>
Mon, 4 Sep 2017 18:50:43 +0000 (19:50 +0100)
committerSimon Tatham <anakin@pobox.com>
Mon, 4 Sep 2017 18:50:43 +0000 (19:50 +0100)
This is intended to make life easier for the _really_ dense grids in
which the generator algorithm falls back to a bare clearing, a tightly
packed section round the edges, and a fringe of deductions required in
between.

In that situation, you can deduce _in principle_ from the remaining-
mines counter that there are (say) one, or two, squares left to be
uncovered before everything remaining has to be a mine. And often the
game will require that deduction in order to solve it all by pure
logic. But actually doing it requires counting up the huge number of
covered squares in an irregularly shaped area and subtracting the mine
count in the status line, which is a real pain.

In fact, people failing to do that are the biggest source of (wrong)
bug reports about Mines games having no solution, so with any luck
this will make my own life easier.

mines.c

diff --git a/mines.c b/mines.c
index 6a5ce029a0c46af5cf6ccbb29663505fc2d8adc6..57f778a168890a7532928614c8890e08ef253a3d 100644 (file)
--- a/mines.c
+++ b/mines.c
@@ -2961,7 +2961,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
                         float animtime, float flashtime)
 {
     int x, y;
-    int mines, markers, bg;
+    int mines, markers, closed, bg;
     int cx = -1, cy = -1, cmoved;
 
     if (flashtime) {
@@ -3011,13 +3011,15 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
 
     /*
      * 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])
@@ -3076,7 +3078,42 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
             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),