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:
Simon Tatham
2023-02-05 10:29:42 +00:00
parent 517b14e666
commit 5030d87903
4 changed files with 60 additions and 41 deletions

View File

@ -890,13 +890,14 @@ static int solver_state(game_state *state, int maxdiff)
struct latin_solver solver;
int diff;
latin_solver_alloc(&solver, state->nums, state->order);
diff = latin_solver_main(&solver, maxdiff,
DIFF_LATIN, DIFF_SET, DIFF_EXTREME,
DIFF_EXTREME, DIFF_RECURSIVE,
unequal_solvers, unequal_valid, ctx,
clone_ctx, free_ctx);
if (!latin_solver_alloc(&solver, state->nums, state->order))
diff = latin_solver_main(&solver, maxdiff,
DIFF_LATIN, DIFF_SET, DIFF_EXTREME,
DIFF_EXTREME, DIFF_RECURSIVE,
unequal_solvers, unequal_valid, ctx,
clone_ctx, free_ctx);
else
diff = DIFF_IMPOSSIBLE;
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;
game_debug(state);
latin_solver_alloc(&solver, state->nums, state->order);
diff = latin_solver_main(&solver, DIFF_RECURSIVE,
DIFF_LATIN, DIFF_SET, DIFF_EXTREME,
DIFF_EXTREME, DIFF_RECURSIVE,
unequal_solvers, unequal_valid, ctx,
clone_ctx, free_ctx);
if (latin_solver_alloc(&solver, state->nums, state->order))
diff = latin_solver_main(&solver, DIFF_RECURSIVE,
DIFF_LATIN, DIFF_SET, DIFF_EXTREME,
DIFF_EXTREME, DIFF_RECURSIVE,
unequal_solvers, unequal_valid, ctx,
clone_ctx, free_ctx);
else
diff = DIFF_IMPOSSIBLE;
free_ctx(ctx);