shithub: puzzles

Download patch

ref: 69773d855b517ea356c3c02add97893201de2066
parent: 6da8dc91a2c1ecd5cc7e02bc63d1404bf80382f9
author: Simon Tatham <anakin@pobox.com>
date: Sat Oct 28 07:36:47 EDT 2017

Solo: remove some overzealous assertions in the solver.

There were a couple of places where we enforced by assertion that our
solver state had not become inconsistent, on the assumption that some
previous piece of solver would have detected that the puzzle was
impossible before getting to that place in the code.

But in fact the combination of Killer and Unreasonable modes falsified
at least two of those assumptions: 'solo --test-solve --generate 100
3x3kdu#12345' triggered an assertion failure in solver_set, and with
that one fixed, the same command triggered a second failure in
solver_killer_sums.

In both cases, the fix is simply to return -1 for 'puzzle is
inconsistent', which will cause the Unreasonable recursive solver to
abandon that branch of its search tree, backtrack, and try a different
guess at some previous square.

Thanks to Anders Höglund for the report.

--- a/solo.c
+++ b/solo.c
@@ -1013,12 +1013,23 @@
 
 	/*
 	 * If count == 0, then there's a row with no 1s at all and
-	 * the puzzle is internally inconsistent. However, we ought
-	 * to have caught this already during the simpler reasoning
-	 * methods, so we can safely fail an assertion if we reach
-	 * this point here.
+	 * the puzzle is internally inconsistent.
 	 */
-	assert(count > 0);
+        if (count == 0) {
+#ifdef STANDALONE_SOLVER
+            if (solver_show_working) {
+                va_list ap;
+                printf("%*s", solver_recurse_depth*4,
+                       "");
+                va_start(ap, fmt);
+                vprintf(fmt, ap);
+                va_end(ap);
+                printf(":\n%*s  solver_set: impossible on entry\n",
+                       solver_recurse_depth*4, "");
+            }
+#endif
+            return -1;
+        }
         if (count == 1)
             rowidx[i] = colidx[first] = FALSE;
     }
@@ -1465,7 +1476,14 @@
 	assert(nsquares == 0);
 	return 0;
     }
-    assert(nsquares > 0);
+    if (nsquares == 0) {
+#ifdef STANDALONE_SOLVER
+        if (solver_show_working)
+            printf("%*skiller: cage has no usable squares left\n",
+                   solver_recurse_depth*4, "");
+#endif
+        return -1;
+    }
 
     if (nsquares < 2 || nsquares > 4)
 	return 0;