ref: 068a092cd54e33497e4fff01445a5d927794c76e
parent: f2ff444fca4da3f63fe0473fc660bb3a5429c2bc
author: Simon Tatham <anakin@pobox.com>
date: Wed Aug 31 08:43:14 EDT 2005
Ahem; forgot about recursion. Recursive solving now shows its working as well. [originally from svn r6245]
--- a/map.c
+++ b/map.c
@@ -804,14 +804,17 @@
struct solver_scratch {
unsigned char *possible; /* bitmap of colours for each region */
+
int *graph;
+ int n;
+ int ngraph;
+
int *bfsqueue;
int *bfscolour;
#ifdef SOLVER_DIAGNOSTICS
int *bfsprev;
#endif
- int n;
- int ngraph;
+
int depth;
};
@@ -870,8 +873,14 @@
int *graph = sc->graph, n = sc->n, ngraph = sc->ngraph;
int j, k;
- if (!(sc->possible[index] & (1 << colour)))
+ if (!(sc->possible[index] & (1 << colour))) {
+#ifdef SOLVER_DIAGNOSTICS
+ if (verbose)
+ printf("%*scannot place %c in region %d\n", 2*sc->depth, "",
+ colnames[colour], index);
+#endif
return FALSE; /* can't do it */
+ }
sc->possible[index] = 1 << colour;
colouring[index] = colour;
@@ -878,7 +887,8 @@
#ifdef SOLVER_DIAGNOSTICS
if (verbose)
- printf("%s %c in region %d\n", verb, colnames[colour], index);
+ printf("%*s%s %c in region %d\n", 2*sc->depth, "",
+ verb, colnames[colour], index);
#endif
/*
@@ -889,7 +899,8 @@
k = graph[j] - index*n;
#ifdef SOLVER_DIAGNOSTICS
if (verbose && (sc->possible[k] & (1 << colour)))
- printf(" ruling out %c in region %d\n", colnames[colour], k);
+ printf("%*s ruling out %c in region %d\n", 2*sc->depth, "",
+ colnames[colour], k);
#endif
sc->possible[k] &= ~(1 << colour);
}
@@ -925,24 +936,32 @@
{
int i;
- /*
- * Initialise scratch space.
- */
- for (i = 0; i < n; i++)
- sc->possible[i] = (1 << FOUR) - 1;
+ if (sc->depth == 0) {
+ /*
+ * Initialise scratch space.
+ */
+ for (i = 0; i < n; i++)
+ sc->possible[i] = (1 << FOUR) - 1;
- /*
- * Place clues.
- */
- for (i = 0; i < n; i++)
- if (colouring[i] >= 0) {
- if (!place_colour(sc, colouring, i, colouring[i]
+ /*
+ * Place clues.
+ */
+ for (i = 0; i < n; i++)
+ if (colouring[i] >= 0) {
+ if (!place_colour(sc, colouring, i, colouring[i]
#ifdef SOLVER_DIAGNOSTICS
- , "initial clue:"
+ , "initial clue:"
#endif
- ))
- return 0; /* the clues aren't even consistent! */
- }
+ )) {
+#ifdef SOLVER_DIAGNOSTICS
+ if (verbose)
+ printf("%*sinitial clue set is inconsistent\n",
+ 2*sc->depth, "");
+#endif
+ return 0; /* the clues aren't even consistent! */
+ }
+ }
+ }
/*
* Now repeatedly loop until we find nothing further to do.
@@ -960,21 +979,35 @@
for (i = 0; i < n; i++) if (colouring[i] < 0) {
int p = sc->possible[i];
- if (p == 0)
+ if (p == 0) {
+#ifdef SOLVER_DIAGNOSTICS
+ if (verbose)
+ printf("%*sregion %d has no possible colours left\n",
+ 2*sc->depth, "", i);
+#endif
return 0; /* puzzle is inconsistent */
+ }
if ((p & (p-1)) == 0) { /* p is a power of two */
- int c;
+ int c, ret;
for (c = 0; c < FOUR; c++)
if (p == (1 << c))
break;
assert(c < FOUR);
- if (!place_colour(sc, colouring, i, c
+ ret = place_colour(sc, colouring, i, c
#ifdef SOLVER_DIAGNOSTICS
- , "placing"
+ , "placing"
#endif
- ))
- return 0; /* found puzzle to be inconsistent */
+ );
+ /*
+ * place_colour() can only fail if colour c was not
+ * even a _possibility_ for region i, and we're
+ * pretty sure it was because we checked before
+ * calling place_colour(). So we can safely assert
+ * here rather than having to return a nice
+ * friendly error code.
+ */
+ assert(ret);
done_something = TRUE;
}
}
@@ -1041,11 +1074,12 @@
if (verbose) {
char buf[80];
if (!started)
- printf("adjacent regions %d,%d share colours %s\n",
- j1, j2, colourset(buf, v));
+ printf("%*sadjacent regions %d,%d share colours"
+ " %s\n", 2*sc->depth, "", j1, j2,
+ colourset(buf, v));
started = TRUE;
- printf(" ruling out %s in region %d\n",
- colourset(buf, sc->possible[k] & v), k);
+ printf("%*s ruling out %s in region %d\n",2*sc->depth,
+ "", colourset(buf, sc->possible[k] & v), k);
}
#endif
sc->possible[k] &= ~v;
@@ -1176,13 +1210,15 @@
char buf[80], *sep = "";
int r;
- printf("forcing chain, colour %s, ",
+ printf("%*sforcing chain, colour %s, ",
+ 2*sc->depth, "",
colourset(buf, origc));
for (r = j; r != -1; r = sc->bfsprev[r]) {
printf("%s%d", sep, r);
sep = "-";
}
- printf("\n ruling out %s in region %d\n",
+ printf("\n%*s ruling out %s in region"
+ " %d\n", 2*sc->depth, "",
colourset(buf, origc), k);
}
#endif
@@ -1206,14 +1242,25 @@
for (i = 0; i < n; i++)
if (colouring[i] < 0)
break;
- if (i == n)
+ if (i == n) {
+#ifdef SOLVER_DIAGNOSTICS
+ if (verbose)
+ printf("%*sone solution found\n", 2*sc->depth, "");
+#endif
return 1; /* success! */
+ }
/*
* If recursion is not permissible, we now give up.
*/
- if (difficulty < DIFF_RECURSE)
+ if (difficulty < DIFF_RECURSE) {
+#ifdef SOLVER_DIAGNOSTICS
+ if (verbose)
+ printf("%*sunable to proceed further without recursion\n",
+ 2*sc->depth, "");
+#endif
return 2; /* unable to complete */
+ }
/*
* Now we've got to do something recursive. So first hunt for a
@@ -1247,6 +1294,11 @@
assert(best >= 0); /* or we'd be solved already */
+#ifdef SOLVER_DIAGNOSTICS
+ if (verbose)
+ printf("%*srecursing on region %d\n", 2*sc->depth, "", best);
+#endif
+
/*
* Now iterate over the possible colours for this region.
*/
@@ -1262,11 +1314,27 @@
if (!(sc->possible[best] & (1 << i)))
continue;
+ memcpy(rsc->possible, sc->possible, n);
memcpy(subcolouring, origcolouring, n * sizeof(int));
- subcolouring[best] = i;
+
+ place_colour(rsc, subcolouring, best, i
+#ifdef SOLVER_DIAGNOSTICS
+ , "trying"
+#endif
+ );
+
subret = map_solver(rsc, graph, n, ngraph,
subcolouring, difficulty);
+#ifdef SOLVER_DIAGNOSTICS
+ if (verbose) {
+ printf("%*sretracting %c in region %d; found %s\n",
+ 2*sc->depth, "", colnames[i], best,
+ subret == 0 ? "no solutions" :
+ subret == 1 ? "one solution" : "multiple solutions");
+ }
+#endif
+
/*
* If this possibility turned up more than one valid
* solution, or if it turned up one and we already had
@@ -1296,6 +1364,14 @@
sfree(subcolouring);
free_scratch(rsc);
+#ifdef SOLVER_DIAGNOSTICS
+ if (verbose && sc->depth == 0) {
+ printf("%*s%s found\n",
+ 2*sc->depth, "",
+ ret == 0 ? "no solutions" :
+ ret == 1 ? "one solution" : "multiple solutions");
+ }
+#endif
return ret;
}
}