mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-22 16:32:13 -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:
47
latin.c
47
latin.c
@ -563,7 +563,7 @@ void latin_solver_free_scratch(struct latin_solver_scratch *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;
|
||||
|
||||
@ -577,14 +577,23 @@ void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o)
|
||||
memset(solver->row, 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
|
||||
solver->names = NULL;
|
||||
#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)
|
||||
@ -810,15 +819,17 @@ static int latin_solver_recurse
|
||||
} else {
|
||||
newctx = ctx;
|
||||
}
|
||||
latin_solver_alloc(&subsolver, outgrid, o);
|
||||
#ifdef STANDALONE_SOLVER
|
||||
subsolver.names = solver->names;
|
||||
#endif
|
||||
ret = latin_solver_top(&subsolver, diff_recursive,
|
||||
diff_simple, diff_set_0, diff_set_1,
|
||||
diff_forcing, diff_recursive,
|
||||
usersolvers, valid, newctx,
|
||||
ctxnew, ctxfree);
|
||||
if (latin_solver_alloc(&subsolver, outgrid, o))
|
||||
ret = latin_solver_top(&subsolver, diff_recursive,
|
||||
diff_simple, diff_set_0, diff_set_1,
|
||||
diff_forcing, diff_recursive,
|
||||
usersolvers, valid, newctx,
|
||||
ctxnew, ctxfree);
|
||||
else
|
||||
ret = diff_impossible;
|
||||
latin_solver_free(&subsolver);
|
||||
if (ctxnew)
|
||||
ctxfree(newctx);
|
||||
@ -1059,11 +1070,13 @@ int latin_solver(digit *grid, int o, int maxdiff,
|
||||
struct latin_solver solver;
|
||||
int diff;
|
||||
|
||||
latin_solver_alloc(&solver, grid, o);
|
||||
diff = latin_solver_main(&solver, maxdiff,
|
||||
diff_simple, diff_set_0, diff_set_1,
|
||||
diff_forcing, diff_recursive,
|
||||
usersolvers, valid, ctx, ctxnew, ctxfree);
|
||||
if (latin_solver_alloc(&solver, grid, o))
|
||||
diff = latin_solver_main(&solver, maxdiff,
|
||||
diff_simple, diff_set_0, diff_set_1,
|
||||
diff_forcing, diff_recursive,
|
||||
usersolvers, valid, ctx, ctxnew, ctxfree);
|
||||
else
|
||||
diff = diff_impossible;
|
||||
latin_solver_free(&solver);
|
||||
return diff;
|
||||
}
|
||||
|
Reference in New Issue
Block a user