mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
check_valid() wasn't checking that Killer cages contain at most one
of each digit, and - perhaps more importantly - the display code wasn't highlighting violations of that rule as an error. Fix both. [originally from svn r8540]
This commit is contained in:
86
solo.c
86
solo.c
@ -2933,8 +2933,8 @@ static int gridgen(int cr, struct block_structure *blocks,
|
|||||||
/*
|
/*
|
||||||
* Check whether a grid contains a valid complete puzzle.
|
* Check whether a grid contains a valid complete puzzle.
|
||||||
*/
|
*/
|
||||||
static int check_valid(int cr, struct block_structure *blocks, int xtype,
|
static int check_valid(int cr, struct block_structure *blocks,
|
||||||
digit *grid)
|
struct block_structure *kblocks, int xtype, digit *grid)
|
||||||
{
|
{
|
||||||
unsigned char *used;
|
unsigned char *used;
|
||||||
int x, y, i, j, n;
|
int x, y, i, j, n;
|
||||||
@ -2987,6 +2987,25 @@ static int check_valid(int cr, struct block_structure *blocks, int xtype,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that each Killer cage, if any, contains at most one of
|
||||||
|
* everything.
|
||||||
|
*/
|
||||||
|
if (kblocks) {
|
||||||
|
for (i = 0; i < kblocks->nr_blocks; i++) {
|
||||||
|
memset(used, FALSE, cr);
|
||||||
|
for (j = 0; j < kblocks->nr_squares[i]; j++)
|
||||||
|
if (grid[kblocks->blocks[i][j]] > 0 &&
|
||||||
|
grid[kblocks->blocks[i][j]] <= cr) {
|
||||||
|
if (used[grid[kblocks->blocks[i][j]]-1]) {
|
||||||
|
sfree(used);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
used[grid[kblocks->blocks[i][j]]-1] = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that each diagonal contains precisely one of everything.
|
* Check that each diagonal contains precisely one of everything.
|
||||||
*/
|
*/
|
||||||
@ -3528,7 +3547,7 @@ static char *new_game_desc(game_params *params, random_state *rs,
|
|||||||
|
|
||||||
if (!gridgen(cr, blocks, kblocks, params->xtype, grid, rs, area*area))
|
if (!gridgen(cr, blocks, kblocks, params->xtype, grid, rs, area*area))
|
||||||
continue;
|
continue;
|
||||||
assert(check_valid(cr, blocks, params->xtype, grid));
|
assert(check_valid(cr, blocks, kblocks, params->xtype, grid));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save the solved grid in aux.
|
* Save the solved grid in aux.
|
||||||
@ -4409,7 +4428,7 @@ struct game_drawstate {
|
|||||||
unsigned char *pencil;
|
unsigned char *pencil;
|
||||||
unsigned char *hl;
|
unsigned char *hl;
|
||||||
/* This is scratch space used within a single call to game_redraw. */
|
/* This is scratch space used within a single call to game_redraw. */
|
||||||
int *entered_items;
|
int nregions, *entered_items;
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
|
static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
|
||||||
@ -4553,8 +4572,8 @@ static game_state *execute_move(game_state *from, char *move)
|
|||||||
* We've made a real change to the grid. Check to see
|
* We've made a real change to the grid. Check to see
|
||||||
* if the game has been completed.
|
* if the game has been completed.
|
||||||
*/
|
*/
|
||||||
if (!ret->completed && check_valid(cr, ret->blocks, ret->xtype,
|
if (!ret->completed && check_valid(cr, ret->blocks, ret->kblocks,
|
||||||
ret->grid)) {
|
ret->xtype, ret->grid)) {
|
||||||
ret->completed = TRUE;
|
ret->completed = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4643,7 +4662,15 @@ static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
|
|||||||
memset(ds->pencil, 0, cr*cr*cr);
|
memset(ds->pencil, 0, cr*cr*cr);
|
||||||
ds->hl = snewn(cr*cr, unsigned char);
|
ds->hl = snewn(cr*cr, unsigned char);
|
||||||
memset(ds->hl, 0, cr*cr);
|
memset(ds->hl, 0, cr*cr);
|
||||||
ds->entered_items = snewn(cr*cr, int);
|
/*
|
||||||
|
* ds->entered_items needs one row of cr entries per entity in
|
||||||
|
* which digits may not be duplicated. That's one for each row,
|
||||||
|
* each column, each block, each diagonal, and each Killer cage.
|
||||||
|
*/
|
||||||
|
ds->nregions = cr*3 + 2;
|
||||||
|
if (state->kblocks)
|
||||||
|
ds->nregions += state->kblocks->nr_blocks;
|
||||||
|
ds->entered_items = snewn(cr * ds->nregions, int);
|
||||||
ds->tilesize = 0; /* not decided yet */
|
ds->tilesize = 0; /* not decided yet */
|
||||||
return ds;
|
return ds;
|
||||||
}
|
}
|
||||||
@ -4970,21 +4997,36 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
|
|||||||
* This array is used to keep track of rows, columns and boxes
|
* This array is used to keep track of rows, columns and boxes
|
||||||
* which contain a number more than once.
|
* which contain a number more than once.
|
||||||
*/
|
*/
|
||||||
for (x = 0; x < cr * cr; x++)
|
for (x = 0; x < cr * ds->nregions; x++)
|
||||||
ds->entered_items[x] = 0;
|
ds->entered_items[x] = 0;
|
||||||
for (x = 0; x < cr; x++)
|
for (x = 0; x < cr; x++)
|
||||||
for (y = 0; y < cr; y++) {
|
for (y = 0; y < cr; y++) {
|
||||||
digit d = state->grid[y*cr+x];
|
digit d = state->grid[y*cr+x];
|
||||||
if (d) {
|
if (d) {
|
||||||
int box = state->blocks->whichblock[y*cr+x];
|
int box, kbox;
|
||||||
ds->entered_items[x*cr+d-1] |= ((ds->entered_items[x*cr+d-1] & 1) << 1) | 1;
|
|
||||||
ds->entered_items[y*cr+d-1] |= ((ds->entered_items[y*cr+d-1] & 4) << 1) | 4;
|
/* Rows */
|
||||||
ds->entered_items[box*cr+d-1] |= ((ds->entered_items[box*cr+d-1] & 16) << 1) | 16;
|
ds->entered_items[x*cr+d-1]++;
|
||||||
|
|
||||||
|
/* Columns */
|
||||||
|
ds->entered_items[(y+cr)*cr+d-1]++;
|
||||||
|
|
||||||
|
/* Blocks */
|
||||||
|
box = state->blocks->whichblock[y*cr+x];
|
||||||
|
ds->entered_items[(box+2*cr)*cr+d-1]++;
|
||||||
|
|
||||||
|
/* Diagonals */
|
||||||
if (ds->xtype) {
|
if (ds->xtype) {
|
||||||
if (ondiag0(y*cr+x))
|
if (ondiag0(y*cr+x))
|
||||||
ds->entered_items[d-1] |= ((ds->entered_items[d-1] & 64) << 1) | 64;
|
ds->entered_items[(3*cr)*cr+d-1]++;
|
||||||
if (ondiag1(y*cr+x))
|
if (ondiag1(y*cr+x))
|
||||||
ds->entered_items[cr+d-1] |= ((ds->entered_items[cr+d-1] & 64) << 1) | 64;
|
ds->entered_items[(3*cr+1)*cr+d-1]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Killer cages */
|
||||||
|
if (state->kblocks) {
|
||||||
|
kbox = state->kblocks->whichblock[y*cr+x];
|
||||||
|
ds->entered_items[(kbox+3*cr+2)*cr+d-1]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -5008,11 +5050,17 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
|
|||||||
|
|
||||||
/* Mark obvious errors (ie, numbers which occur more than once
|
/* Mark obvious errors (ie, numbers which occur more than once
|
||||||
* in a single row, column, or box). */
|
* in a single row, column, or box). */
|
||||||
if (d && ((ds->entered_items[x*cr+d-1] & 2) ||
|
if (d && (ds->entered_items[x*cr+d-1] > 1 ||
|
||||||
(ds->entered_items[y*cr+d-1] & 8) ||
|
ds->entered_items[(y+cr)*cr+d-1] > 1 ||
|
||||||
(ds->entered_items[state->blocks->whichblock[y*cr+x]*cr+d-1] & 32) ||
|
ds->entered_items[(state->blocks->whichblock[y*cr+x]
|
||||||
(ds->xtype && ((ondiag0(y*cr+x) && (ds->entered_items[d-1] & 128)) ||
|
+2*cr)*cr+d-1] > 1 ||
|
||||||
(ondiag1(y*cr+x) && (ds->entered_items[cr+d-1] & 128))))))
|
(ds->xtype && ((ondiag0(y*cr+x) &&
|
||||||
|
ds->entered_items[(3*cr)*cr+d-1] > 1) ||
|
||||||
|
(ondiag1(y*cr+x) &&
|
||||||
|
ds->entered_items[(3*cr+1)*cr+d-1]>1)))||
|
||||||
|
(state->kblocks &&
|
||||||
|
ds->entered_items[(state->kblocks->whichblock[y*cr+x]
|
||||||
|
+3*cr+2)*cr+d-1] > 1)))
|
||||||
highlight |= 16;
|
highlight |= 16;
|
||||||
|
|
||||||
if (d && state->kblocks) {
|
if (d && state->kblocks) {
|
||||||
|
Reference in New Issue
Block a user