shithub: puzzles

Download patch

ref: 47cec547e59ac8c5012f6091394dcb4304d64fc3
parent: cdc0563123951822b2f5f514336f8890ee6df522
author: Simon Tatham <anakin@pobox.com>
date: Tue Nov 13 16:58:14 EST 2018

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.

--- a/unfinished/group.c
+++ b/unfinished/group.c
@@ -82,11 +82,16 @@
     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 @@
 
     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 @@
     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 @@
     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 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 @@
                     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 @@
              */
             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 @@
                 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 @@
 	    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) ||
--- a/unruly.c
+++ b/unruly.c
@@ -133,11 +133,16 @@
 #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 @@
     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,7 +386,7 @@
             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') {
@@ -386,7 +393,7 @@
             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 @@
     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 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 @@
         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 @@
         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 @@
 
             tile |= flash;
 
-            if (state->immutable[i])
+            if (state->common->immutable[i])
                 tile |= FF_IMMUTABLE;
 
             if (ui->cursor && ui->cx == x && ui->cy == y)