mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
Fix loophole in Palisade completion checker.
A user pointed out that if you construct a 'solution' in which no clue square has too _many_ borders but at least one has too few, and then bring those clues up to their count by adding extra stray border lines _inside_ a connected component (avoiding actually dividing any component completely into two), then the game checker treats that as solved for victory-flash purposes, on the grounds that (a) the grid is divided into components of the right size and (b) all clues are satisfied. A small example is 4x4n4:22a2b2c33, with the non-solution of dividing the grid into four 2x2 square blocks and then adding a spurious extra edge between the two 3 clues. The old Palisade completion check would flash for victory _at the same time_ as highlighting the spurious edge in COL_ERROR. Fixed by enforcing in is_solved() that every border line must separate two distinct connected components.
This commit is contained in:
32
palisade.c
32
palisade.c
@ -511,10 +511,20 @@ static void dfs_dsf(int i, int w, borderflag *border, int *dsf, int black)
|
||||
static int is_solved(const game_params *params, clue *clues,
|
||||
borderflag *border)
|
||||
{
|
||||
int wh = params->w * params->h, k = params->k, *dsf = snew_dsf(wh), i;
|
||||
int w = params->w, h = params->h, wh = w*h, k = params->k;
|
||||
int i, x, y;
|
||||
int *dsf = snew_dsf(wh);
|
||||
|
||||
assert (dsf[0] == UNVISITED); /* check: UNVISITED and dsf.c match up */
|
||||
|
||||
/*
|
||||
* A game is solved if:
|
||||
*
|
||||
* - the borders drawn on the grid divide it into connected
|
||||
* components such that every square is in a component of the
|
||||
* correct size
|
||||
* - the borders also satisfy the clue set
|
||||
*/
|
||||
for (i = 0; i < wh; ++i) {
|
||||
if (dsf[i] == UNVISITED) dfs_dsf(i, params->w, border, dsf, TRUE);
|
||||
if (dsf_size(dsf, i) != k) goto error;
|
||||
@ -522,6 +532,26 @@ static int is_solved(const game_params *params, clue *clues,
|
||||
if (clues[i] != bitcount[border[i] & BORDER_MASK]) goto error;
|
||||
}
|
||||
|
||||
/*
|
||||
* ... and thirdly:
|
||||
*
|
||||
* - there are no *stray* borders, in that every border is
|
||||
* actually part of the division between two components.
|
||||
* Otherwise you could cheat by finding a subdivision which did
|
||||
* not *exceed* any clue square's counter, and then adding a
|
||||
* few extra edges.
|
||||
*/
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = 0; x < w; x++) {
|
||||
if (x+1 < w && (border[y*w+x] & BORDER_R) &&
|
||||
dsf_canonify(dsf, y*w+x) == dsf_canonify(dsf, y*w+(x+1)))
|
||||
goto error;
|
||||
if (y+1 < h && (border[y*w+x] & BORDER_D) &&
|
||||
dsf_canonify(dsf, y*w+x) == dsf_canonify(dsf, (y+1)*w+x))
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
sfree(dsf);
|
||||
return TRUE;
|
||||
|
||||
|
Reference in New Issue
Block a user