shithub: puzzles

Download patch

ref: ac6fd11ddad3cc52adeeb16a49f71666549fa547
parent: ff8a9fbc541b714e64fc089f75ec712a04cbd90f
author: Simon Tatham <anakin@pobox.com>
date: Tue Sep 9 10:20:10 EDT 2014

Improve connectedness-error highlighting in Range.

The previous approach of scanning the grid by depth-first search was
fine for deciding whether it was connected, but not so good for
pointing out where the mistake was in the grid. Replaced that code
with a dsf-based version, which identifies all connected components so
that an easy followup pass can highlight all but the largest as
erroneous.

[originally from svn r10223]

--- a/range.R
+++ b/range.R
@@ -1,10 +1,12 @@
 # -*- makefile -*-
 
-range    : [X] GTK COMMON range range-icon|no-icon
+RANGE_EXTRA = dsf
 
-range    : [G] WINDOWS COMMON range range.res|noicon.res
+range    : [X] GTK COMMON range RANGE_EXTRA range-icon|no-icon
 
-ALL += range[COMBINED]
+range    : [G] WINDOWS COMMON range RANGE_EXTRA range.res|noicon.res
+
+ALL += range[COMBINED] RANGE_EXTRA
 
 !begin am gtk
 GAMES += range
--- a/range.c
+++ b/range.c
@@ -1364,6 +1364,7 @@
 static int find_errors(const game_state *state, int *report)
 {
     int const w = state->params.w, h = state->params.h, n = w * h;
+    int *dsf;
 
     int r, c, i;
 
@@ -1415,14 +1416,50 @@
             }
         }
 
-    for (i = 0; i < n; ++i) if (dup->grid[i] != BLACK) dup->grid[i] = WHITE;
-    if (nblack + dfs_count_white(dup, any_white_cell) < n) {
+    /*
+     * Check that all the white cells form a single connected component.
+     */
+    dsf = snew_dsf(n);
+    for (r = 0; r < h-1; ++r)
+        for (c = 0; c < w; ++c)
+            if (state->grid[r*w+c] != BLACK &&
+                state->grid[(r+1)*w+c] != BLACK)
+                dsf_merge(dsf, r*w+c, (r+1)*w+c);
+    for (r = 0; r < h; ++r)
+        for (c = 0; c < w-1; ++c)
+            if (state->grid[r*w+c] != BLACK &&
+                state->grid[r*w+(c+1)] != BLACK)
+                dsf_merge(dsf, r*w+c, r*w+(c+1));
+    if (nblack + dsf_size(dsf, any_white_cell) < n) {
+        int biggest, canonical;
+
         if (!report) {
             printf("dfs fail at %d\n", any_white_cell);
             goto found_error;
         }
-        for (i = 0; i < n; ++i) if (state->grid[i] != BLACK) report[i] = TRUE;
+
+        /*
+         * Report this error by choosing one component to be the
+         * canonical one (we pick the largest, arbitrarily
+         * tie-breaking towards lower array indices) and highlighting
+         * as an error any square in a different component.
+         */
+        canonical = -1;
+        biggest = 0;
+        for (i = 0; i < n; ++i)
+            if (state->grid[i] != BLACK) {
+                int size = dsf_size(dsf, i);
+                if (size > biggest) {
+                    biggest = size;
+                    canonical = dsf_canonify(dsf, i);
+                }
+            }
+
+        for (i = 0; i < n; ++i)
+            if (state->grid[i] != BLACK && dsf_canonify(dsf, i) != canonical)
+                report[i] = TRUE;
     }
+    sfree(dsf);
 
     free_game(dup);
     return FALSE; /* if report != NULL, this is ignored */