Unreasonable mode for Map.

[originally from svn r6229]
This commit is contained in:
Simon Tatham
2005-08-28 14:29:19 +00:00
parent e483fc513b
commit 2975ae2811
2 changed files with 106 additions and 4 deletions

101
map.c
View File

@ -42,7 +42,8 @@ static float flash_length;
*/
#define DIFFLIST(A) \
A(EASY,Easy,e) \
A(NORMAL,Normal,n)
A(NORMAL,Normal,n) \
A(RECURSE,Unreasonable,u)
#define ENUM(upper,title,lower) DIFF_ ## upper,
#define TITLE(upper,title,lower) #title,
#define ENCODE(upper,title,lower) #lower
@ -789,6 +790,7 @@ struct solver_scratch {
int *graph;
int n;
int ngraph;
int depth;
};
static struct solver_scratch *new_scratch(int *graph, int n, int ngraph)
@ -800,6 +802,7 @@ static struct solver_scratch *new_scratch(int *graph, int n, int ngraph)
sc->n = n;
sc->ngraph = ngraph;
sc->possible = snewn(n, unsigned char);
sc->depth = 0;
return sc;
}
@ -957,13 +960,103 @@ static int map_solver(struct solver_scratch *sc,
}
/*
* We've run out of things to deduce. See if we've got the lot.
* See if we've got a complete solution, and return if so.
*/
for (i = 0; i < n; i++)
if (colouring[i] < 0)
return 2;
break;
if (i == n)
return 1; /* success! */
return 1; /* success! */
/*
* If recursion is not permissible, we now give up.
*/
if (difficulty < DIFF_RECURSE)
return 2; /* unable to complete */
/*
* Now we've got to do something recursive. So first hunt for a
* currently-most-constrained region.
*/
{
int best, bestc;
struct solver_scratch *rsc;
int *subcolouring, *origcolouring;
int ret, subret;
int we_already_got_one;
best = -1;
bestc = FIVE;
for (i = 0; i < n; i++) if (colouring[i] < 0) {
int p = sc->possible[i];
enum { compile_time_assertion = 1 / (FOUR <= 4) };
int c;
/* Count the set bits. */
c = (p & 5) + ((p >> 1) & 5);
c = (c & 3) + ((c >> 2) & 3);
assert(c > 1); /* or colouring[i] would be >= 0 */
if (c < bestc) {
best = i;
bestc = c;
}
}
assert(best >= 0); /* or we'd be solved already */
/*
* Now iterate over the possible colours for this region.
*/
rsc = new_scratch(graph, n, ngraph);
rsc->depth = sc->depth + 1;
origcolouring = snewn(n, int);
memcpy(origcolouring, colouring, n * sizeof(int));
subcolouring = snewn(n, int);
we_already_got_one = FALSE;
ret = 0;
for (i = 0; i < FOUR; i++) {
if (!(sc->possible[best] & (1 << i)))
continue;
memcpy(subcolouring, origcolouring, n * sizeof(int));
subcolouring[best] = i;
subret = map_solver(rsc, graph, n, ngraph,
subcolouring, difficulty);
/*
* If this possibility turned up more than one valid
* solution, or if it turned up one and we already had
* one, we're definitely ambiguous.
*/
if (subret == 2 || (subret == 1 && we_already_got_one)) {
ret = 2;
break;
}
/*
* If this possibility turned up one valid solution and
* it's the first we've seen, copy it into the output.
*/
if (subret == 1) {
memcpy(colouring, subcolouring, n * sizeof(int));
we_already_got_one = TRUE;
ret = 1;
}
/*
* Otherwise, this guess led to a contradiction, so we
* do nothing.
*/
}
sfree(subcolouring);
free_scratch(rsc);
return ret;
}
}
/* ----------------------------------------------------------------------

View File

@ -1656,6 +1656,15 @@ will have to use more complex logic to deduce the colour of some
regions. However, it will always be possible without having to
guess or backtrack.
\lcont{
In \q{Unreasonable} mode, the program will feel free to generate
puzzles which are as hard as it can possibly make them: the only
constraint is that they should still have a unique solution. Solving
Unreasonable puzzles may require guessing and backtracking.
}
\C{loopy} \i{Loopy}