Unruly, Group: reference-count the 'immutable' array.

I noticed this during the bool trawl: both of these games have an
array of flags indicating which grid squares are immutable starting
clues, and copy it in every call to dup_game, which is completely
unnecessary because it doesn't change during play. So now each one
lives in a reference-counted structure, as per my usual practice in
similar cases elsewhere.
This commit is contained in:
Simon Tatham
2018-11-13 21:58:14 +00:00
parent cdc0563123
commit 47cec547e5
2 changed files with 43 additions and 21 deletions

View File

@ -82,11 +82,16 @@ struct game_params {
bool id; bool id;
}; };
typedef struct group_common {
int refcount;
bool *immutable;
} group_common;
struct game_state { struct game_state {
game_params par; game_params par;
digit *grid; digit *grid;
bool *immutable;
int *pencil; /* bitmaps using bits 1<<1..1<<n */ int *pencil; /* bitmaps using bits 1<<1..1<<n */
group_common *common;
bool completed, cheated; bool completed, cheated;
digit *sequence; /* sequence of group elements shown */ digit *sequence; /* sequence of group elements shown */
@ -850,11 +855,13 @@ static game_state *new_game(midend *me, const game_params *params,
state->par = *params; /* structure copy */ state->par = *params; /* structure copy */
state->grid = snewn(a, digit); state->grid = snewn(a, digit);
state->immutable = snewn(a, bool); state->common = snew(group_common);
state->common->refcount = 1;
state->common->immutable = snewn(a, bool);
state->pencil = snewn(a, int); state->pencil = snewn(a, int);
for (i = 0; i < a; i++) { for (i = 0; i < a; i++) {
state->grid[i] = 0; state->grid[i] = 0;
state->immutable[i] = false; state->common->immutable[i] = false;
state->pencil[i] = 0; state->pencil[i] = 0;
} }
state->sequence = snewn(w, digit); state->sequence = snewn(w, digit);
@ -867,7 +874,7 @@ static game_state *new_game(midend *me, const game_params *params,
desc = spec_to_grid(desc, state->grid, a); desc = spec_to_grid(desc, state->grid, a);
for (i = 0; i < a; i++) for (i = 0; i < a; i++)
if (state->grid[i] != 0) if (state->grid[i] != 0)
state->immutable[i] = true; state->common->immutable[i] = true;
state->completed = false; state->completed = false;
state->cheated = false; state->cheated = false;
@ -883,12 +890,12 @@ static game_state *dup_game(const game_state *state)
ret->par = state->par; /* structure copy */ ret->par = state->par; /* structure copy */
ret->grid = snewn(a, digit); ret->grid = snewn(a, digit);
ret->immutable = snewn(a, bool); ret->common = state->common;
ret->common->refcount++;
ret->pencil = snewn(a, int); ret->pencil = snewn(a, int);
ret->sequence = snewn(w, digit); ret->sequence = snewn(w, digit);
ret->dividers = snewn(w, int); ret->dividers = snewn(w, int);
memcpy(ret->grid, state->grid, a*sizeof(digit)); memcpy(ret->grid, state->grid, a*sizeof(digit));
memcpy(ret->immutable, state->immutable, a*sizeof(bool));
memcpy(ret->pencil, state->pencil, a*sizeof(int)); memcpy(ret->pencil, state->pencil, a*sizeof(int));
memcpy(ret->sequence, state->sequence, w*sizeof(digit)); memcpy(ret->sequence, state->sequence, w*sizeof(digit));
memcpy(ret->dividers, state->dividers, w*sizeof(int)); memcpy(ret->dividers, state->dividers, w*sizeof(int));
@ -902,7 +909,10 @@ static game_state *dup_game(const game_state *state)
static void free_game(game_state *state) static void free_game(game_state *state)
{ {
sfree(state->grid); sfree(state->grid);
sfree(state->immutable); if (--state->common->refcount == 0) {
sfree(state->common->immutable);
sfree(state->common);
}
sfree(state->pencil); sfree(state->pencil);
sfree(state->sequence); sfree(state->sequence);
sfree(state); sfree(state);
@ -1318,7 +1328,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
ui->ohy = oty; ui->ohy = oty;
ui->odx = ui->ody = 0; ui->odx = ui->ody = 0;
ui->odn = 1; ui->odn = 1;
ui->hshow = !state->immutable[ty*w+tx]; ui->hshow = !state->common->immutable[ty*w+tx];
ui->hpencil = false; ui->hpencil = false;
} }
ui->hcursor = false; ui->hcursor = false;
@ -1423,7 +1433,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
*/ */
if (!ui->hpencil && state->grid[index] == n) if (!ui->hpencil && state->grid[index] == n)
/* OK even if it is immutable */; /* OK even if it is immutable */;
else if (state->immutable[index]) else if (state->common->immutable[index])
return NULL; return NULL;
} }
@ -1487,7 +1497,8 @@ static game_state *execute_move(const game_state *from, const char *move)
free_game(ret); free_game(ret);
return NULL; return NULL;
} }
if (from->immutable[y*w+x] && !(!pencil && from->grid[y*w+x] == n)) if (from->common->immutable[y*w+x] &&
!(!pencil && from->grid[y*w+x] == n))
return NULL; return NULL;
if (move[0] == 'P' && n > 0) { if (move[0] == 'P' && n > 0) {
@ -1900,7 +1911,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
else else
pencil = (long)state->pencil[sy*w+sx]; pencil = (long)state->pencil[sy*w+sx];
if (state->immutable[sy*w+sx]) if (state->common->immutable[sy*w+sx])
tile |= DF_IMMUTABLE; tile |= DF_IMMUTABLE;
if ((ui->drag == 5 && ui->dragnum == sy) || if ((ui->drag == 5 && ui->dragnum == sy) ||

View File

@ -133,11 +133,16 @@ enum {
#define FF_FLASH2 0x0800 #define FF_FLASH2 0x0800
#define FF_IMMUTABLE 0x1000 #define FF_IMMUTABLE 0x1000
typedef struct unruly_common {
int refcount;
bool *immutable;
} unruly_common;
struct game_state { struct game_state {
int w2, h2; int w2, h2;
bool unique; bool unique;
char *grid; char *grid;
bool *immutable; unruly_common *common;
bool completed, cheated; bool completed, cheated;
}; };
@ -353,10 +358,12 @@ static game_state *blank_state(int w2, int h2, bool unique)
state->h2 = h2; state->h2 = h2;
state->unique = unique; state->unique = unique;
state->grid = snewn(s, char); state->grid = snewn(s, char);
state->immutable = snewn(s, bool); state->common = snew(unruly_common);
state->common->refcount = 1;
state->common->immutable = snewn(s, bool);
memset(state->grid, EMPTY, s); memset(state->grid, EMPTY, s);
memset(state->immutable, 0, s*sizeof(bool)); memset(state->common->immutable, 0, s*sizeof(bool));
state->completed = state->cheated = false; state->completed = state->cheated = false;
@ -379,14 +386,14 @@ static game_state *new_game(midend *me, const game_params *params,
pos += (*p - 'a'); pos += (*p - 'a');
if (pos < s) { if (pos < s) {
state->grid[pos] = N_ZERO; state->grid[pos] = N_ZERO;
state->immutable[pos] = true; state->common->immutable[pos] = true;
} }
pos++; pos++;
} else if (*p >= 'A' && *p < 'Z') { } else if (*p >= 'A' && *p < 'Z') {
pos += (*p - 'A'); pos += (*p - 'A');
if (pos < s) { if (pos < s) {
state->grid[pos] = N_ONE; state->grid[pos] = N_ONE;
state->immutable[pos] = true; state->common->immutable[pos] = true;
} }
pos++; pos++;
} else if (*p == 'Z' || *p == 'z') { } else if (*p == 'Z' || *p == 'z') {
@ -409,7 +416,8 @@ static game_state *dup_game(const game_state *state)
game_state *ret = blank_state(w2, h2, state->unique); game_state *ret = blank_state(w2, h2, state->unique);
memcpy(ret->grid, state->grid, s); memcpy(ret->grid, state->grid, s);
memcpy(ret->immutable, state->immutable, s*sizeof(bool)); ret->common = state->common;
ret->common->refcount++;
ret->completed = state->completed; ret->completed = state->completed;
ret->cheated = state->cheated; ret->cheated = state->cheated;
@ -420,7 +428,10 @@ static game_state *dup_game(const game_state *state)
static void free_game(game_state *state) static void free_game(game_state *state)
{ {
sfree(state->grid); sfree(state->grid);
sfree(state->immutable); if (--state->common->refcount == 0) {
sfree(state->common->immutable);
sfree(state->common);
}
sfree(state); sfree(state);
} }
@ -1539,7 +1550,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
char buf[80]; char buf[80];
char c, i; char c, i;
if (state->immutable[hy * w2 + hx]) if (state->common->immutable[hy * w2 + hx])
return NULL; return NULL;
c = '-'; c = '-';
@ -1604,7 +1615,7 @@ static game_state *execute_move(const game_state *state, const char *move)
ret = dup_game(state); ret = dup_game(state);
i = y * w2 + x; i = y * w2 + x;
if (state->immutable[i]) { if (state->common->immutable[i]) {
free_game(ret); free_game(ret);
return NULL; return NULL;
} }
@ -1820,7 +1831,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
tile |= flash; tile |= flash;
if (state->immutable[i]) if (state->common->immutable[i])
tile |= FF_IMMUTABLE; tile |= FF_IMMUTABLE;
if (ui->cursor && ui->cx == x && ui->cy == y) if (ui->cursor && ui->cx == x && ui->cy == y)