Ahem; forgot about recursion. Recursive solving now shows its

working as well.

[originally from svn r6245]
This commit is contained in:
Simon Tatham
2005-08-31 12:43:14 +00:00
parent f2ff444fca
commit 068a092cd5

116
map.c
View File

@ -804,14 +804,17 @@ static void fourcolour(int *graph, int n, int ngraph, int *colouring,
struct solver_scratch { struct solver_scratch {
unsigned char *possible; /* bitmap of colours for each region */ unsigned char *possible; /* bitmap of colours for each region */
int *graph; int *graph;
int n;
int ngraph;
int *bfsqueue; int *bfsqueue;
int *bfscolour; int *bfscolour;
#ifdef SOLVER_DIAGNOSTICS #ifdef SOLVER_DIAGNOSTICS
int *bfsprev; int *bfsprev;
#endif #endif
int n;
int ngraph;
int depth; int depth;
}; };
@ -870,15 +873,22 @@ static int place_colour(struct solver_scratch *sc,
int *graph = sc->graph, n = sc->n, ngraph = sc->ngraph; int *graph = sc->graph, n = sc->n, ngraph = sc->ngraph;
int j, k; 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 */ return FALSE; /* can't do it */
}
sc->possible[index] = 1 << colour; sc->possible[index] = 1 << colour;
colouring[index] = colour; colouring[index] = colour;
#ifdef SOLVER_DIAGNOSTICS #ifdef SOLVER_DIAGNOSTICS
if (verbose) 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 #endif
/* /*
@ -889,7 +899,8 @@ static int place_colour(struct solver_scratch *sc,
k = graph[j] - index*n; k = graph[j] - index*n;
#ifdef SOLVER_DIAGNOSTICS #ifdef SOLVER_DIAGNOSTICS
if (verbose && (sc->possible[k] & (1 << colour))) 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 #endif
sc->possible[k] &= ~(1 << colour); sc->possible[k] &= ~(1 << colour);
} }
@ -925,6 +936,7 @@ static int map_solver(struct solver_scratch *sc,
{ {
int i; int i;
if (sc->depth == 0) {
/* /*
* Initialise scratch space. * Initialise scratch space.
*/ */
@ -940,9 +952,16 @@ static int map_solver(struct solver_scratch *sc,
#ifdef SOLVER_DIAGNOSTICS #ifdef SOLVER_DIAGNOSTICS
, "initial clue:" , "initial clue:"
#endif #endif
)) )) {
#ifdef SOLVER_DIAGNOSTICS
if (verbose)
printf("%*sinitial clue set is inconsistent\n",
2*sc->depth, "");
#endif
return 0; /* the clues aren't even consistent! */ return 0; /* the clues aren't even consistent! */
} }
}
}
/* /*
* Now repeatedly loop until we find nothing further to do. * Now repeatedly loop until we find nothing further to do.
@ -960,21 +979,35 @@ static int map_solver(struct solver_scratch *sc,
for (i = 0; i < n; i++) if (colouring[i] < 0) { for (i = 0; i < n; i++) if (colouring[i] < 0) {
int p = sc->possible[i]; 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 */ return 0; /* puzzle is inconsistent */
}
if ((p & (p-1)) == 0) { /* p is a power of two */ if ((p & (p-1)) == 0) { /* p is a power of two */
int c; int c, ret;
for (c = 0; c < FOUR; c++) for (c = 0; c < FOUR; c++)
if (p == (1 << c)) if (p == (1 << c))
break; break;
assert(c < FOUR); assert(c < FOUR);
if (!place_colour(sc, colouring, i, c ret = place_colour(sc, colouring, i, c
#ifdef SOLVER_DIAGNOSTICS #ifdef SOLVER_DIAGNOSTICS
, "placing" , "placing"
#endif #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; done_something = TRUE;
} }
} }
@ -1041,11 +1074,12 @@ static int map_solver(struct solver_scratch *sc,
if (verbose) { if (verbose) {
char buf[80]; char buf[80];
if (!started) if (!started)
printf("adjacent regions %d,%d share colours %s\n", printf("%*sadjacent regions %d,%d share colours"
j1, j2, colourset(buf, v)); " %s\n", 2*sc->depth, "", j1, j2,
colourset(buf, v));
started = TRUE; started = TRUE;
printf(" ruling out %s in region %d\n", printf("%*s ruling out %s in region %d\n",2*sc->depth,
colourset(buf, sc->possible[k] & v), k); "", colourset(buf, sc->possible[k] & v), k);
} }
#endif #endif
sc->possible[k] &= ~v; sc->possible[k] &= ~v;
@ -1176,13 +1210,15 @@ static int map_solver(struct solver_scratch *sc,
char buf[80], *sep = ""; char buf[80], *sep = "";
int r; int r;
printf("forcing chain, colour %s, ", printf("%*sforcing chain, colour %s, ",
2*sc->depth, "",
colourset(buf, origc)); colourset(buf, origc));
for (r = j; r != -1; r = sc->bfsprev[r]) { for (r = j; r != -1; r = sc->bfsprev[r]) {
printf("%s%d", sep, r); printf("%s%d", sep, r);
sep = "-"; 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); colourset(buf, origc), k);
} }
#endif #endif
@ -1206,14 +1242,25 @@ static int map_solver(struct solver_scratch *sc,
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
if (colouring[i] < 0) if (colouring[i] < 0)
break; break;
if (i == n) if (i == n) {
#ifdef SOLVER_DIAGNOSTICS
if (verbose)
printf("%*sone solution found\n", 2*sc->depth, "");
#endif
return 1; /* success! */ return 1; /* success! */
}
/* /*
* If recursion is not permissible, we now give up. * 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 */ return 2; /* unable to complete */
}
/* /*
* Now we've got to do something recursive. So first hunt for a * Now we've got to do something recursive. So first hunt for a
@ -1247,6 +1294,11 @@ static int map_solver(struct solver_scratch *sc,
assert(best >= 0); /* or we'd be solved already */ 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. * Now iterate over the possible colours for this region.
*/ */
@ -1262,11 +1314,27 @@ static int map_solver(struct solver_scratch *sc,
if (!(sc->possible[best] & (1 << i))) if (!(sc->possible[best] & (1 << i)))
continue; continue;
memcpy(rsc->possible, sc->possible, n);
memcpy(subcolouring, origcolouring, n * sizeof(int)); 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, subret = map_solver(rsc, graph, n, ngraph,
subcolouring, difficulty); 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 * If this possibility turned up more than one valid
* solution, or if it turned up one and we already had * solution, or if it turned up one and we already had
@ -1296,6 +1364,14 @@ static int map_solver(struct solver_scratch *sc,
sfree(subcolouring); sfree(subcolouring);
free_scratch(rsc); 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; return ret;
} }
} }