Don't allow moves that change the constraints in Unequal

Unequal has a flags word per cell.  Some of those flags are fixed,
like the locations of the ">" signs, but others indicate errors and
are used to allow the player to mark clues as "spent".  Move strings
beginning with "F" allow the user to change the "spent" flags, but
they shouldn't allow the user to change any other flags, especially
those marking the constraints.

Without this fix, the following save file gives a "solver_nminmax:
Assertion `x >= 0 && y >= 0 && x < o && y < o' failed" after it adds a
clue that points off the board:

SAVEFILE:41:Simon Tatham's Portable Puzzle Collection
GAME    :7:Unequal
PARAMS  :3:3e0
CPARAMS :3:3e0
DESC    :17:0,0,0,0,0,0,0,0,0
NSTATES :2:3
STATEPOS:1:3
MOVE    :6:F2,0,4
MOVE    :1:H
This commit is contained in:
Ben Harris
2023-02-11 22:49:36 +00:00
parent 896a73bd7f
commit 97b03cc67a

View File

@ -84,6 +84,7 @@ struct game_params {
#define ADJ_TO_SPENT(x) ((x) << 9) #define ADJ_TO_SPENT(x) ((x) << 9)
#define F_ERROR_MASK (F_ERROR|F_ERROR_UP|F_ERROR_RIGHT|F_ERROR_DOWN|F_ERROR_LEFT) #define F_ERROR_MASK (F_ERROR|F_ERROR_UP|F_ERROR_RIGHT|F_ERROR_DOWN|F_ERROR_LEFT)
#define F_SPENT_MASK (F_SPENT_UP|F_SPENT_RIGHT|F_SPENT_DOWN|F_SPENT_LEFT)
struct game_state { struct game_state {
int order; int order;
@ -1706,7 +1707,8 @@ static game_state *execute_move(const game_state *state, const char *move)
check_complete(ret->nums, ret, true); check_complete(ret->nums, ret, true);
return ret; return ret;
} else if (move[0] == 'F' && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 && } else if (move[0] == 'F' && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 &&
x >= 0 && x < state->order && y >= 0 && y < state->order) { x >= 0 && x < state->order && y >= 0 && y < state->order &&
(n & ~F_SPENT_MASK) == 0) {
ret = dup_game(state); ret = dup_game(state);
GRID(ret, flags, x, y) ^= n; GRID(ret, flags, x, y) ^= n;
return ret; return ret;