chiark / gitweb /
Net: fix assertion failure on insoluble puzzles.
authorSimon Tatham <anakin@pobox.com>
Thu, 24 Aug 2017 18:38:29 +0000 (19:38 +0100)
committerSimon Tatham <anakin@pobox.com>
Thu, 24 Aug 2017 18:38:29 +0000 (19:38 +0100)
The solver code still had an assumption, which must have dated before
the Solve menu option was introduced, that all puzzles presented to it
had at least one valid solution, and was enforcing that assumption by
assert(). Now the solver returns a more sensible failure code which
solve_game() can convert into a proper error message.

net.c

diff --git a/net.c b/net.c
index de51f82fd7c0e176f6c9bbe2bff3f67cf272b3e9..57d91d3581c5af92029ad219e505fa7db3f3c22f 100644 (file)
--- a/net.c
+++ b/net.c
@@ -459,6 +459,11 @@ static int todo_get(struct todo *todo) {
     return ret;
 }
 
+/*
+ * Return values: -1 means puzzle was proved inconsistent, 0 means we
+ * failed to narrow down to a unique solution, +1 means we solved it
+ * fully.
+ */
 static int net_solver(int w, int h, unsigned char *tiles,
                      unsigned char *barriers, int wrapping)
 {
@@ -733,7 +738,11 @@ static int net_solver(int w, int h, unsigned char *tiles,
 #endif
            }
 
-           assert(j > 0);             /* we can't lose _all_ possibilities! */
+           if (j == 0) {
+                /* If we've ruled out all possible orientations for a
+                 * tile, then our puzzle has no solution at all. */
+                return -1;
+            }
 
            if (j < i) {
                done_something = TRUE;
@@ -813,14 +822,14 @@ static int net_solver(int w, int h, unsigned char *tiles,
     /*
      * Mark all completely determined tiles as locked.
      */
-    j = TRUE;
+    j = +1;
     for (i = 0; i < w*h; i++) {
        if (tilestate[i * 4 + 1] == 255) {
            assert(tilestate[i * 4 + 0] != 255);
            tiles[i] = tilestate[i * 4] | LOCKED;
        } else {
            tiles[i] &= ~LOCKED;
-           j = FALSE;
+           j = 0;
        }
     }
 
@@ -1334,7 +1343,7 @@ static char *new_game_desc(const game_params *params, random_state *rs,
        /*
         * Run the solver to check unique solubility.
         */
-       while (!net_solver(w, h, tiles, NULL, params->wrapping)) {
+       while (net_solver(w, h, tiles, NULL, params->wrapping) != 1) {
            int n = 0;
 
            /*
@@ -1758,9 +1767,17 @@ static char *solve_game(const game_state *state, const game_state *currstate,
         * Run the internal solver on the provided grid. This might
         * not yield a complete solution.
         */
+        int solver_result;
+
        memcpy(tiles, state->tiles, state->width * state->height);
-       net_solver(state->width, state->height, tiles,
-                  state->barriers, state->wrapping);
+       solver_result = net_solver(state->width, state->height, tiles,
+                                   state->barriers, state->wrapping);
+
+        if (solver_result < 0) {
+            *error = "No solution exists for this puzzle";
+            sfree(tiles);
+            return NULL;
+        }
     } else {
         for (i = 0; i < state->width * state->height; i++) {
             int c = aux[i];