mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
Unreasonable mode for Map.
[originally from svn r6229]
This commit is contained in:
101
map.c
101
map.c
@ -42,7 +42,8 @@ static float flash_length;
|
|||||||
*/
|
*/
|
||||||
#define DIFFLIST(A) \
|
#define DIFFLIST(A) \
|
||||||
A(EASY,Easy,e) \
|
A(EASY,Easy,e) \
|
||||||
A(NORMAL,Normal,n)
|
A(NORMAL,Normal,n) \
|
||||||
|
A(RECURSE,Unreasonable,u)
|
||||||
#define ENUM(upper,title,lower) DIFF_ ## upper,
|
#define ENUM(upper,title,lower) DIFF_ ## upper,
|
||||||
#define TITLE(upper,title,lower) #title,
|
#define TITLE(upper,title,lower) #title,
|
||||||
#define ENCODE(upper,title,lower) #lower
|
#define ENCODE(upper,title,lower) #lower
|
||||||
@ -789,6 +790,7 @@ struct solver_scratch {
|
|||||||
int *graph;
|
int *graph;
|
||||||
int n;
|
int n;
|
||||||
int ngraph;
|
int ngraph;
|
||||||
|
int depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct solver_scratch *new_scratch(int *graph, int n, int ngraph)
|
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->n = n;
|
||||||
sc->ngraph = ngraph;
|
sc->ngraph = ngraph;
|
||||||
sc->possible = snewn(n, unsigned char);
|
sc->possible = snewn(n, unsigned char);
|
||||||
|
sc->depth = 0;
|
||||||
|
|
||||||
return sc;
|
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++)
|
for (i = 0; i < n; i++)
|
||||||
if (colouring[i] < 0)
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
|
@ -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
|
regions. However, it will always be possible without having to
|
||||||
guess or backtrack.
|
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}
|
\C{loopy} \i{Loopy}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user