mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-20 15:41:30 -07:00
latin_solver_alloc: handle clashing numbers in input grid.
In the setup phase of the centralised latin.c solver, we start by going over the input grid containing already-placed clue numbers, and calling latin_solver_place to enter each on into the solver's data structure. This has the side effect of ruling out each number from the rest of the row and column, and _also_ checking by assertion that the number being placed is not ruled out. Those are a bad combination, because it means that if you give an obviously inconsistent input grid to latin_solver_alloc (e.g. with two identical numbers in a row already), it will fail an assertion. In that situation, you want the solver run as a whole to return diff_impossible so that the error is reported cleanly. This assertion failure could be provoked by giving either Towers or Group a manually-constructed game description inconsistent in that way, and hitting Solve. Worse, it could be provoked during live play in Unequal, by filling in a number clashing with a clue and then pressing 'h' to get hints.
This commit is contained in:
29
latin.c
29
latin.c
@ -563,7 +563,7 @@ void latin_solver_free_scratch(struct latin_solver_scratch *scratch)
|
|||||||
sfree(scratch);
|
sfree(scratch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o)
|
bool latin_solver_alloc(struct latin_solver *solver, digit *grid, int o)
|
||||||
{
|
{
|
||||||
int x, y;
|
int x, y;
|
||||||
|
|
||||||
@ -577,14 +577,23 @@ void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o)
|
|||||||
memset(solver->row, 0, o*o);
|
memset(solver->row, 0, o*o);
|
||||||
memset(solver->col, 0, o*o);
|
memset(solver->col, 0, o*o);
|
||||||
|
|
||||||
for (x = 0; x < o; x++)
|
|
||||||
for (y = 0; y < o; y++)
|
|
||||||
if (grid[y*o+x])
|
|
||||||
latin_solver_place(solver, x, y, grid[y*o+x]);
|
|
||||||
|
|
||||||
#ifdef STANDALONE_SOLVER
|
#ifdef STANDALONE_SOLVER
|
||||||
solver->names = NULL;
|
solver->names = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
for (x = 0; x < o; x++) {
|
||||||
|
for (y = 0; y < o; y++) {
|
||||||
|
int n = grid[y*o+x];
|
||||||
|
if (n) {
|
||||||
|
if (cube(x, y, n))
|
||||||
|
latin_solver_place(solver, x, y, n);
|
||||||
|
else
|
||||||
|
return false; /* puzzle is already inconsistent */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void latin_solver_free(struct latin_solver *solver)
|
void latin_solver_free(struct latin_solver *solver)
|
||||||
@ -810,15 +819,17 @@ static int latin_solver_recurse
|
|||||||
} else {
|
} else {
|
||||||
newctx = ctx;
|
newctx = ctx;
|
||||||
}
|
}
|
||||||
latin_solver_alloc(&subsolver, outgrid, o);
|
|
||||||
#ifdef STANDALONE_SOLVER
|
#ifdef STANDALONE_SOLVER
|
||||||
subsolver.names = solver->names;
|
subsolver.names = solver->names;
|
||||||
#endif
|
#endif
|
||||||
|
if (latin_solver_alloc(&subsolver, outgrid, o))
|
||||||
ret = latin_solver_top(&subsolver, diff_recursive,
|
ret = latin_solver_top(&subsolver, diff_recursive,
|
||||||
diff_simple, diff_set_0, diff_set_1,
|
diff_simple, diff_set_0, diff_set_1,
|
||||||
diff_forcing, diff_recursive,
|
diff_forcing, diff_recursive,
|
||||||
usersolvers, valid, newctx,
|
usersolvers, valid, newctx,
|
||||||
ctxnew, ctxfree);
|
ctxnew, ctxfree);
|
||||||
|
else
|
||||||
|
ret = diff_impossible;
|
||||||
latin_solver_free(&subsolver);
|
latin_solver_free(&subsolver);
|
||||||
if (ctxnew)
|
if (ctxnew)
|
||||||
ctxfree(newctx);
|
ctxfree(newctx);
|
||||||
@ -1059,11 +1070,13 @@ int latin_solver(digit *grid, int o, int maxdiff,
|
|||||||
struct latin_solver solver;
|
struct latin_solver solver;
|
||||||
int diff;
|
int diff;
|
||||||
|
|
||||||
latin_solver_alloc(&solver, grid, o);
|
if (latin_solver_alloc(&solver, grid, o))
|
||||||
diff = latin_solver_main(&solver, maxdiff,
|
diff = latin_solver_main(&solver, maxdiff,
|
||||||
diff_simple, diff_set_0, diff_set_1,
|
diff_simple, diff_set_0, diff_set_1,
|
||||||
diff_forcing, diff_recursive,
|
diff_forcing, diff_recursive,
|
||||||
usersolvers, valid, ctx, ctxnew, ctxfree);
|
usersolvers, valid, ctx, ctxnew, ctxfree);
|
||||||
|
else
|
||||||
|
diff = diff_impossible;
|
||||||
latin_solver_free(&solver);
|
latin_solver_free(&solver);
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
9
latin.h
9
latin.h
@ -61,10 +61,13 @@ int latin_solver_forcing(struct latin_solver *solver,
|
|||||||
/* --- Solver allocation --- */
|
/* --- Solver allocation --- */
|
||||||
|
|
||||||
/* Fills in (and allocates members for) a latin_solver struct.
|
/* Fills in (and allocates members for) a latin_solver struct.
|
||||||
* Will allocate members of snew, but not snew itself
|
* Will allocate members of solver, but not solver itself
|
||||||
* (allowing 'struct latin_solver' to be the first element in a larger
|
* (allowing 'struct latin_solver' to be the first element in a larger
|
||||||
* struct, for example). */
|
* struct, for example).
|
||||||
void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o);
|
*
|
||||||
|
* latin_solver_alloc returns false if the digits already in the grid
|
||||||
|
* could not be legally placed. */
|
||||||
|
bool latin_solver_alloc(struct latin_solver *solver, digit *grid, int o);
|
||||||
void latin_solver_free(struct latin_solver *solver);
|
void latin_solver_free(struct latin_solver *solver);
|
||||||
|
|
||||||
/* Allocates scratch space (for _set and _forcing) */
|
/* Allocates scratch space (for _set and _forcing) */
|
||||||
|
10
unequal.c
10
unequal.c
@ -890,13 +890,14 @@ static int solver_state(game_state *state, int maxdiff)
|
|||||||
struct latin_solver solver;
|
struct latin_solver solver;
|
||||||
int diff;
|
int diff;
|
||||||
|
|
||||||
latin_solver_alloc(&solver, state->nums, state->order);
|
if (!latin_solver_alloc(&solver, state->nums, state->order))
|
||||||
|
|
||||||
diff = latin_solver_main(&solver, maxdiff,
|
diff = latin_solver_main(&solver, maxdiff,
|
||||||
DIFF_LATIN, DIFF_SET, DIFF_EXTREME,
|
DIFF_LATIN, DIFF_SET, DIFF_EXTREME,
|
||||||
DIFF_EXTREME, DIFF_RECURSIVE,
|
DIFF_EXTREME, DIFF_RECURSIVE,
|
||||||
unequal_solvers, unequal_valid, ctx,
|
unequal_solvers, unequal_valid, ctx,
|
||||||
clone_ctx, free_ctx);
|
clone_ctx, free_ctx);
|
||||||
|
else
|
||||||
|
diff = DIFF_IMPOSSIBLE;
|
||||||
|
|
||||||
memcpy(state->hints, solver.cube, state->order*state->order*state->order);
|
memcpy(state->hints, solver.cube, state->order*state->order*state->order);
|
||||||
|
|
||||||
@ -2256,13 +2257,14 @@ static int solve(game_params *p, char *desc, int debug)
|
|||||||
solver_show_working = debug;
|
solver_show_working = debug;
|
||||||
game_debug(state);
|
game_debug(state);
|
||||||
|
|
||||||
latin_solver_alloc(&solver, state->nums, state->order);
|
if (latin_solver_alloc(&solver, state->nums, state->order))
|
||||||
|
|
||||||
diff = latin_solver_main(&solver, DIFF_RECURSIVE,
|
diff = latin_solver_main(&solver, DIFF_RECURSIVE,
|
||||||
DIFF_LATIN, DIFF_SET, DIFF_EXTREME,
|
DIFF_LATIN, DIFF_SET, DIFF_EXTREME,
|
||||||
DIFF_EXTREME, DIFF_RECURSIVE,
|
DIFF_EXTREME, DIFF_RECURSIVE,
|
||||||
unequal_solvers, unequal_valid, ctx,
|
unequal_solvers, unequal_valid, ctx,
|
||||||
clone_ctx, free_ctx);
|
clone_ctx, free_ctx);
|
||||||
|
else
|
||||||
|
diff = DIFF_IMPOSSIBLE;
|
||||||
|
|
||||||
free_ctx(ctx);
|
free_ctx(ctx);
|
||||||
|
|
||||||
|
@ -580,13 +580,11 @@ static int solver(const game_params *params, digit *grid, int maxdiff)
|
|||||||
int w = params->w;
|
int w = params->w;
|
||||||
int ret;
|
int ret;
|
||||||
struct latin_solver solver;
|
struct latin_solver solver;
|
||||||
|
|
||||||
#ifdef STANDALONE_SOLVER
|
#ifdef STANDALONE_SOLVER
|
||||||
char *p, text[100], *names[50];
|
char *p, text[100], *names[50];
|
||||||
int i;
|
int i;
|
||||||
#endif
|
|
||||||
|
|
||||||
latin_solver_alloc(&solver, grid, w);
|
|
||||||
#ifdef STANDALONE_SOLVER
|
|
||||||
for (i = 0, p = text; i < w; i++) {
|
for (i = 0, p = text; i < w; i++) {
|
||||||
names[i] = p;
|
names[i] = p;
|
||||||
*p++ = TOCHAR(i+1, params->id);
|
*p++ = TOCHAR(i+1, params->id);
|
||||||
@ -595,10 +593,13 @@ static int solver(const game_params *params, digit *grid, int maxdiff)
|
|||||||
solver.names = names;
|
solver.names = names;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (latin_solver_alloc(&solver, grid, w))
|
||||||
ret = latin_solver_main(&solver, maxdiff,
|
ret = latin_solver_main(&solver, maxdiff,
|
||||||
DIFF_TRIVIAL, DIFF_HARD, DIFF_EXTREME,
|
DIFF_TRIVIAL, DIFF_HARD, DIFF_EXTREME,
|
||||||
DIFF_EXTREME, DIFF_UNREASONABLE,
|
DIFF_EXTREME, DIFF_UNREASONABLE,
|
||||||
group_solvers, group_valid, NULL, NULL, NULL);
|
group_solvers, group_valid, NULL, NULL, NULL);
|
||||||
|
else
|
||||||
|
ret = diff_impossible;
|
||||||
|
|
||||||
latin_solver_free(&solver);
|
latin_solver_free(&solver);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user