mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
Ahem; forgot about recursion. Recursive solving now shows its
working as well. [originally from svn r6245]
This commit is contained in:
116
map.c
116
map.c
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user