chiark / gitweb /
Unruly, Group: reference-count the 'immutable' array.
authorSimon Tatham <anakin@pobox.com>
Tue, 13 Nov 2018 21:58:14 +0000 (21:58 +0000)
committerSimon Tatham <anakin@pobox.com>
Tue, 13 Nov 2018 21:58:14 +0000 (21:58 +0000)
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.

unfinished/group.c
unruly.c

index e5aa81fb4712cd4601a7ba50a356beafabf8270e..ef7ffba3493854ec29555e7b806e8295309e45f4 100644 (file)
@@ -82,11 +82,16 @@ struct game_params {
     bool id;
 };
 
+typedef struct group_common {
+    int refcount;
+    bool *immutable;
+} group_common;
+
 struct game_state {
     game_params par;
     digit *grid;
-    bool *immutable;
     int *pencil;                      /* bitmaps using bits 1<<1..1<<n */
+    group_common *common;
     bool completed, cheated;
     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->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);
     for (i = 0; i < a; i++) {
        state->grid[i] = 0;
-       state->immutable[i] = false;
+       state->common->immutable[i] = false;
        state->pencil[i] = 0;
     }
     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);
     for (i = 0; i < a; i++)
        if (state->grid[i] != 0)
-           state->immutable[i] = true;
+           state->common->immutable[i] = true;
 
     state->completed = false;
     state->cheated = false;
@@ -883,12 +890,12 @@ static game_state *dup_game(const game_state *state)
     ret->par = state->par;            /* structure copy */
 
     ret->grid = snewn(a, digit);
-    ret->immutable = snewn(a, bool);
+    ret->common = state->common;
+    ret->common->refcount++;
     ret->pencil = snewn(a, int);
     ret->sequence = snewn(w, digit);
     ret->dividers = snewn(w, int);
     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->sequence, state->sequence, w*sizeof(digit));
     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)
 {
     sfree(state->grid);
-    sfree(state->immutable);
+    if (--state->common->refcount == 0) {
+        sfree(state->common->immutable);
+        sfree(state->common);
+    }
     sfree(state->pencil);
     sfree(state->sequence);
     sfree(state);
@@ -1318,7 +1328,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
                     ui->ohy = oty;
                     ui->odx = ui->ody = 0;
                     ui->odn = 1;
-                    ui->hshow = !state->immutable[ty*w+tx];
+                    ui->hshow = !state->common->immutable[ty*w+tx];
                     ui->hpencil = 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)
                 /* OK even if it is immutable */;
-            else if (state->immutable[index])
+            else if (state->common->immutable[index])
                 return NULL;
         }
 
@@ -1487,7 +1497,8 @@ static game_state *execute_move(const game_state *from, const char *move)
                 free_game(ret);
                 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;
 
             if (move[0] == 'P' && n > 0) {
@@ -1900,7 +1911,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
            else
                pencil = (long)state->pencil[sy*w+sx];
 
-           if (state->immutable[sy*w+sx])
+           if (state->common->immutable[sy*w+sx])
                tile |= DF_IMMUTABLE;
 
             if ((ui->drag == 5 && ui->dragnum == sy) ||
index bccddb3f48c726bff10fbf9d0c64f8beac2967b8..e69c31b6b94a354b06066bc5f53882a2ac33b741 100644 (file)
--- a/unruly.c
+++ b/unruly.c
@@ -133,11 +133,16 @@ enum {
 #define FF_FLASH2         0x0800
 #define FF_IMMUTABLE      0x1000
 
+typedef struct unruly_common {
+    int refcount;
+    bool *immutable;
+} unruly_common;
+
 struct game_state {
     int w2, h2;
     bool unique;
     char *grid;
-    bool *immutable;
+    unruly_common *common;
 
     bool completed, cheated;
 };
@@ -353,10 +358,12 @@ static game_state *blank_state(int w2, int h2, bool unique)
     state->h2 = h2;
     state->unique = unique;
     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->immutable, 0, s*sizeof(bool));
+    memset(state->common->immutable, 0, s*sizeof(bool));
 
     state->completed = state->cheated = false;
 
@@ -379,14 +386,14 @@ static game_state *new_game(midend *me, const game_params *params,
             pos += (*p - 'a');
             if (pos < s) {
                 state->grid[pos] = N_ZERO;
-                state->immutable[pos] = true;
+                state->common->immutable[pos] = true;
             }
             pos++;
         } else if (*p >= 'A' && *p < 'Z') {
             pos += (*p - 'A');
             if (pos < s) {
                 state->grid[pos] = N_ONE;
-                state->immutable[pos] = true;
+                state->common->immutable[pos] = true;
             }
             pos++;
         } 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);
 
     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->cheated = state->cheated;
@@ -420,7 +428,10 @@ static game_state *dup_game(const game_state *state)
 static void free_game(game_state *state)
 {
     sfree(state->grid);
-    sfree(state->immutable);
+    if (--state->common->refcount == 0) {
+        sfree(state->common->immutable);
+        sfree(state->common);
+    }
 
     sfree(state);
 }
@@ -1539,7 +1550,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
         char buf[80];
         char c, i;
 
-        if (state->immutable[hy * w2 + hx])
+        if (state->common->immutable[hy * w2 + hx])
             return NULL;
 
         c = '-';
@@ -1604,7 +1615,7 @@ static game_state *execute_move(const game_state *state, const char *move)
         ret = dup_game(state);
         i = y * w2 + x;
 
-        if (state->immutable[i]) {
+        if (state->common->immutable[i]) {
             free_game(ret);
             return NULL;
         }
@@ -1820,7 +1831,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
 
             tile |= flash;
 
-            if (state->immutable[i])
+            if (state->common->immutable[i])
                 tile |= FF_IMMUTABLE;
 
             if (ui->cursor && ui->cx == x && ui->cy == y)