Net: fix assertion failure on insoluble puzzles.

The solver code still had an assumption, which must have dated before
the Solve menu option was introduced, that all puzzles presented to it
had at least one valid solution, and was enforcing that assumption by
assert(). Now the solver returns a more sensible failure code which
solve_game() can convert into a proper error message.
This commit is contained in:
Simon Tatham
2017-08-24 19:38:29 +01:00
parent 272beef5f9
commit cb5e49ef1d

29
net.c
View File

@ -459,6 +459,11 @@ static int todo_get(struct todo *todo) {
return ret; return ret;
} }
/*
* Return values: -1 means puzzle was proved inconsistent, 0 means we
* failed to narrow down to a unique solution, +1 means we solved it
* fully.
*/
static int net_solver(int w, int h, unsigned char *tiles, static int net_solver(int w, int h, unsigned char *tiles,
unsigned char *barriers, int wrapping) unsigned char *barriers, int wrapping)
{ {
@ -733,7 +738,11 @@ static int net_solver(int w, int h, unsigned char *tiles,
#endif #endif
} }
assert(j > 0); /* we can't lose _all_ possibilities! */ if (j == 0) {
/* If we've ruled out all possible orientations for a
* tile, then our puzzle has no solution at all. */
return -1;
}
if (j < i) { if (j < i) {
done_something = TRUE; done_something = TRUE;
@ -813,14 +822,14 @@ static int net_solver(int w, int h, unsigned char *tiles,
/* /*
* Mark all completely determined tiles as locked. * Mark all completely determined tiles as locked.
*/ */
j = TRUE; j = +1;
for (i = 0; i < w*h; i++) { for (i = 0; i < w*h; i++) {
if (tilestate[i * 4 + 1] == 255) { if (tilestate[i * 4 + 1] == 255) {
assert(tilestate[i * 4 + 0] != 255); assert(tilestate[i * 4 + 0] != 255);
tiles[i] = tilestate[i * 4] | LOCKED; tiles[i] = tilestate[i * 4] | LOCKED;
} else { } else {
tiles[i] &= ~LOCKED; tiles[i] &= ~LOCKED;
j = FALSE; j = 0;
} }
} }
@ -1334,7 +1343,7 @@ static char *new_game_desc(const game_params *params, random_state *rs,
/* /*
* Run the solver to check unique solubility. * Run the solver to check unique solubility.
*/ */
while (!net_solver(w, h, tiles, NULL, params->wrapping)) { while (net_solver(w, h, tiles, NULL, params->wrapping) != 1) {
int n = 0; int n = 0;
/* /*
@ -1758,9 +1767,17 @@ static char *solve_game(const game_state *state, const game_state *currstate,
* Run the internal solver on the provided grid. This might * Run the internal solver on the provided grid. This might
* not yield a complete solution. * not yield a complete solution.
*/ */
int solver_result;
memcpy(tiles, state->tiles, state->width * state->height); memcpy(tiles, state->tiles, state->width * state->height);
net_solver(state->width, state->height, tiles, solver_result = net_solver(state->width, state->height, tiles,
state->barriers, state->wrapping); state->barriers, state->wrapping);
if (solver_result < 0) {
*error = "No solution exists for this puzzle";
sfree(tiles);
return NULL;
}
} else { } else {
for (i = 0; i < state->width * state->height; i++) { for (i = 0; i < state->width * state->height; i++) {
int c = aux[i]; int c = aux[i];