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

146
map.c
View File

@ -804,14 +804,17 @@ static void fourcolour(int *graph, int n, int ngraph, int *colouring,
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,15 +873,22 @@ static int place_colour(struct solver_scratch *sc,
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;
#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 @@ static int place_colour(struct solver_scratch *sc,
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 @@ static int map_solver(struct solver_scratch *sc,
{
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 @@ static int map_solver(struct solver_scratch *sc,
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 @@ static int map_solver(struct solver_scratch *sc,
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 @@ static int map_solver(struct solver_scratch *sc,
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 @@ static int map_solver(struct solver_scratch *sc,
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 @@ static int map_solver(struct solver_scratch *sc,
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 @@ static int map_solver(struct solver_scratch *sc,
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 @@ static int map_solver(struct solver_scratch *sc,
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;
}
}