shithub: puzzles

Download patch

ref: a4fca3286f3aa630a3641e50a8e1f44ab1504a29
parent: ec2e2f37703e1da4bb097c27ae5e7f1fa368624b
author: Simon Tatham <anakin@pobox.com>
date: Fri Apr 21 11:30:41 EDT 2023

Pass a game_ui to compute_size, print_size and print.

I'm about to move some of the bodgy getenv-based options so that they
become fields in game_ui. So these functions, which could previously
access those options directly via getenv, will now need to be given a
game_ui where they can look them up.

--- a/blackbox.c
+++ b/blackbox.c
@@ -1149,7 +1149,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Border is ts/2, to make things easier.
      * Thus we have (width) + 2 (firing range*2) + 1 (border*2) tiles
--- a/bridges.c
+++ b/bridges.c
@@ -2665,7 +2665,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -3203,17 +3203,19 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
     /* 10mm squares by default. */
-    game_compute_size(params, 1000, &pw, &ph);
+    game_compute_size(params, 1000, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int ts)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int ts)
 {
     int ink = print_mono_colour(dr, 0);
     int paper = print_mono_colour(dr, 1);
--- a/cube.c
+++ b/cube.c
@@ -1489,7 +1489,7 @@
     ((int)(((bb).d - (bb).u + 2*(solid)->border) * gs))
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     struct bbox bb = find_bbox(params);
 
--- a/devel.but
+++ b/devel.but
@@ -1181,7 +1181,7 @@
 \S{backend-compute-size} \cw{compute_size()}
 
 \c void (*compute_size)(const game_params *params, int tilesize,
-\c                      int *x, int *y);
+\c                      const game_ui *ui, int *x, int *y);
 
 This function is passed a \c{game_params} structure and a tile size.
 It returns, in \c{*x} and \c{*y}, the size in pixels of the drawing
@@ -1497,7 +1497,8 @@
 
 \S{backend-print-size} \cw{print_size()}
 
-\c void (*print_size)(const game_params *params, float *x, float *y);
+\c void (*print_size)(const game_params *params, const game_ui *ui,
+\c                    float *x, float *y);
 
 This function is passed a \c{game_params} structure and a tile size.
 It returns, in \c{*x} and \c{*y}, the preferred size in
@@ -1508,7 +1509,8 @@
 
 \S{backend-print} \cw{print()}
 
-\c void (*print)(drawing *dr, const game_state *state, int tilesize);
+\c void (*print)(drawing *dr, const game_state *state,
+\c               const game_ui *ui, int tilesize);
 
 This function is called when a puzzle is to be printed out on paper.
 It should use the drawing API functions (see \k{drawing}) to print
--- a/dominosa.c
+++ b/dominosa.c
@@ -3031,7 +3031,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     int n = params->n, w = n+2, h = n+1;
 
@@ -3371,7 +3371,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -3378,12 +3379,13 @@
     /*
      * I'll use 6mm squares by default.
      */
-    game_compute_size(params, 600, &pw, &ph);
+    game_compute_size(params, 600, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->w, h = state->h;
     int c, x, y;
--- a/fifteen.c
+++ b/fifteen.c
@@ -804,7 +804,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
--- a/filling.c
+++ b/filling.c
@@ -1652,7 +1652,7 @@
 };
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     *x = (params->w + 1) * tilesize;
     *y = (params->h + 1) * tilesize;
@@ -2092,7 +2092,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+			    float *x, float *y)
 {
     int pw, ph;
 
@@ -2099,12 +2100,13 @@
     /*
      * I'll use 6mm squares by default.
      */
-    game_compute_size(params, 600, &pw, &ph);
+    game_compute_size(params, 600, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+		       int tilesize)
 {
     const int w = state->shared->params.w;
     const int h = state->shared->params.h;
--- a/flip.c
+++ b/flip.c
@@ -1055,7 +1055,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
--- a/flood.c
+++ b/flood.c
@@ -974,7 +974,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
--- a/galaxies.c
+++ b/galaxies.c
@@ -3405,7 +3405,7 @@
  */
 
 static void game_compute_size(const game_params *params, int sz,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     struct { int tilesize, w, h; } ads, *ds = &ads;
 
@@ -3926,7 +3926,8 @@
 }
 
 #ifndef EDITOR
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
    int pw, ph;
 
@@ -3934,12 +3935,13 @@
     * 8mm squares by default. (There isn't all that much detail
     * that needs to go in each square.)
     */
-   game_compute_size(params, 800, &pw, &ph);
+   game_compute_size(params, 800, ui, &pw, &ph);
    *x = pw / 100.0F;
    *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int sz)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int sz)
 {
     int w = state->w, h = state->h;
     int white, black, blackish;
--- a/guess.c
+++ b/guess.c
@@ -999,7 +999,7 @@
 #define BORDER    0.5
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     double hmul, vmul_c, vmul_g, vmul;
     int hintw = (params->npegs+1)/2;
@@ -1043,7 +1043,8 @@
     guessh = ((ds->pegsz + ds->gapsz) * params->nguesses);      /* guesses */
     guessh += ds->gapsz + ds->pegsz;                            /* solution */
 
-    game_compute_size(params, tilesize, &ds->w, &ds->h);
+    /* We know we don't need anything from the game_ui we haven't got */
+    game_compute_size(params, tilesize, NULL, &ds->w, &ds->h);
     ds->colx = ds->border;
     ds->coly = (ds->h - colh) / 2;
 
--- a/inertia.c
+++ b/inertia.c
@@ -1768,7 +1768,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
--- a/keen.c
+++ b/keen.c
@@ -1866,7 +1866,7 @@
 #define SIZE(w) ((w) * TILESIZE + 2*BORDER)
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -2222,7 +2222,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -2229,7 +2230,7 @@
     /*
      * We use 9mm squares by default, like Solo.
      */
-    game_compute_size(params, 900, &pw, &ph);
+    game_compute_size(params, 900, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
@@ -2365,7 +2366,8 @@
     sfree(coords);
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->par.w;
     int ink = print_mono_colour(dr, 0);
--- a/lightup.c
+++ b/lightup.c
@@ -2021,7 +2021,7 @@
 
 /* XXX entirely cloned from fifteen.c; separate out? */
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -2247,7 +2247,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -2254,12 +2255,13 @@
     /*
      * I'll use 6mm squares by default.
      */
-    game_compute_size(params, 600, &pw, &ph);
+    game_compute_size(params, 600, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->w, h = state->h;
     int ink = print_mono_colour(dr, 0);
--- a/loopy.c
+++ b/loopy.c
@@ -883,7 +883,7 @@
 }
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     int grid_width, grid_height, rendered_width, rendered_height;
     int g_tilesize;
@@ -3554,7 +3554,8 @@
     return state->solved ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -3561,12 +3562,13 @@
     /*
      * I'll use 7mm "squares" by default.
      */
-    game_compute_size(params, 700, &pw, &ph);
+    game_compute_size(params, 700, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int ink = print_mono_colour(dr, 0);
     int i;
--- a/magnets.c
+++ b/magnets.c
@@ -1965,7 +1965,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -2341,7 +2341,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -2348,12 +2349,13 @@
     /*
      * I'll use 6mm squares by default.
      */
-    game_compute_size(params, 600, &pw, &ph);
+    game_compute_size(params, 600, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->w, h = state->h;
     int ink = print_mono_colour(dr, 0);
--- a/map.c
+++ b/map.c
@@ -2630,7 +2630,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -3093,7 +3093,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -3102,12 +3103,13 @@
      * compute this size is to compute the pixel puzzle size at a
      * given tile size and then scale.
      */
-    game_compute_size(params, 400, &pw, &ph);
+    game_compute_size(params, 400, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n;
     int ink, c[FOUR], i;
--- a/midend.c
+++ b/midend.c
@@ -303,7 +303,7 @@
      * anyway yet.
      */
     if (me->tilesize > 0) {
-	me->ourgame->compute_size(me->params, me->tilesize,
+	me->ourgame->compute_size(me->params, me->tilesize, me->ui,
 				  &me->winwidth, &me->winheight);
 	me->ourgame->set_size(me->drawing, me->drawstate,
 			      me->params, me->tilesize);
@@ -328,7 +328,7 @@
 
     defaults = me->ourgame->default_params();
 
-    me->ourgame->compute_size(defaults, old_tilesize, &x, &y);
+    me->ourgame->compute_size(defaults, old_tilesize, me->ui, &x, &y);
     x *= new_dpr / old_dpr;
     y *= new_dpr / old_dpr;
 
@@ -335,12 +335,12 @@
     min = max = 1;
     do {
         max *= 2;
-        me->ourgame->compute_size(defaults, max, &rx, &ry);
+        me->ourgame->compute_size(defaults, max, me->ui, &rx, &ry);
     } while (rx <= x && ry <= y);
 
     while (max - min > 1) {
 	int mid = (max + min) / 2;
-	me->ourgame->compute_size(defaults, mid, &rx, &ry);
+	me->ourgame->compute_size(defaults, mid, me->ui, &rx, &ry);
 	if (rx <= x && ry <= y)
 	    min = mid;
 	else
@@ -382,7 +382,7 @@
 	max = 1;
 	do {
 	    max *= 2;
-	    me->ourgame->compute_size(me->params, max, &rx, &ry);
+	    me->ourgame->compute_size(me->params, max, me->ui, &rx, &ry);
 	} while (rx <= *x && ry <= *y);
     } else
 	max = convert_tilesize(me, me->preferred_tilesize,
@@ -398,7 +398,7 @@
      */
     while (max - min > 1) {
 	int mid = (max + min) / 2;
-	me->ourgame->compute_size(me->params, mid, &rx, &ry);
+	me->ourgame->compute_size(me->params, mid, me->ui, &rx, &ry);
 	if (rx <= *x && ry <= *y)
 	    min = mid;
 	else
--- a/mines.c
+++ b/mines.c
@@ -2694,7 +2694,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
--- a/mosaic.c
+++ b/mosaic.c
@@ -1398,7 +1398,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     *x = (params->width + 1) * tilesize;
     *y = (params->height + 1) * tilesize;
--- a/net.c
+++ b/net.c
@@ -2488,7 +2488,7 @@
 }
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -3112,7 +3112,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -3119,7 +3120,7 @@
     /*
      * I'll use 8mm squares by default.
      */
-    game_compute_size(params, 800, &pw, &ph);
+    game_compute_size(params, 800, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
@@ -3170,7 +3171,8 @@
     }
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->width, h = state->height;
     int ink = print_mono_colour(dr, 0);
--- a/netslide.c
+++ b/netslide.c
@@ -1223,7 +1223,7 @@
 }
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
--- a/nullgame.c
+++ b/nullgame.c
@@ -148,7 +148,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     *x = *y = 10 * tilesize;	       /* FIXME */
 }
--- a/palisade.c
+++ b/palisade.c
@@ -1043,7 +1043,7 @@
 /* --- Drawing routines --------------------------------------------- */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     *x = (params->w + 1) * tilesize;
     *y = (params->h + 1) * tilesize;
@@ -1291,11 +1291,12 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
-    game_compute_size(params, 700, &pw, &ph); /* 7mm, like loopy */
+    game_compute_size(params, 700, ui, &pw, &ph); /* 7mm, like loopy */
 
     *x = pw / 100.0F;
     *y = ph / 100.0F;
@@ -1314,7 +1315,8 @@
     } else draw_line(dr, x1, y1, x2, y2, colour);
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->shared->params.w, h = state->shared->params.h;
     int ink = print_mono_colour(dr, 0);
--- a/pattern.c
+++ b/pattern.c
@@ -1669,7 +1669,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -1990,7 +1990,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -1997,12 +1998,13 @@
     /*
      * I'll use 5mm squares by default.
      */
-    game_compute_size(params, 500, &pw, &ph);
+    game_compute_size(params, 500, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->common->w, h = state->common->h;
     int ink = print_mono_colour(dr, 0);
--- a/pearl.c
+++ b/pearl.c
@@ -2344,7 +2344,7 @@
 #define FLASH_TIME 0.5F
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int halfsz; } ads, *ds = &ads;
@@ -2633,7 +2633,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -2640,12 +2641,13 @@
     /*
      * I'll use 6mm squares by default.
      */
-    game_compute_size(params, 600, &pw, &ph);
+    game_compute_size(params, 600, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->shared->w, h = state->shared->h, x, y;
     int black = print_mono_colour(dr, 0);
--- a/pegs.c
+++ b/pegs.c
@@ -1048,7 +1048,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
--- a/printing.c
+++ b/printing.c
@@ -96,7 +96,11 @@
     float ww, hh, ourscale;
 
     /* Get the preferred size of the game, in mm. */
-    pz->game->print_size(pz->par, &ww, &hh);
+    {
+        game_ui *ui = pz->game->new_ui(pz->st);
+        pz->game->print_size(pz->par, ui, &ww, &hh);
+        pz->game->free_ui(ui);
+    }
 
     /* Adjust for user-supplied scale factor. */
     ourscale = doc->userscale;
@@ -270,9 +274,14 @@
          * permit each game to choose its own?)
          */
         tilesize = 512;
-        pz->game->compute_size(pz->par, tilesize, &pixw, &pixh);
-        print_begin_puzzle(dr, xm, xc, ym, yc, pixw, pixh, w, scale);
-        pz->game->print(dr, pass == 0 ? pz->st : pz->st2, tilesize);
+        {
+            game_ui *ui = pz->game->new_ui(pz->st);
+            pz->game->compute_size(pz->par, tilesize, ui,
+                                   &pixw, &pixh);
+            print_begin_puzzle(dr, xm, xc, ym, yc, pixw, pixh, w, scale);
+            pz->game->print(dr, pass == 0 ? pz->st : pz->st2, ui, tilesize);
+            pz->game->free_ui(ui);
+        }
         print_end_puzzle(dr);
     }
 
--- a/puzzles.h
+++ b/puzzles.h
@@ -689,7 +689,7 @@
     game_state *(*execute_move)(const game_state *state, const char *move);
     int preferred_tilesize;
     void (*compute_size)(const game_params *params, int tilesize,
-                         int *x, int *y);
+                         const game_ui *ui, int *x, int *y);
     void (*set_size)(drawing *dr, game_drawstate *ds,
 		     const game_params *params, int tilesize);
     float *(*colours)(frontend *fe, int *ncolours);
@@ -709,8 +709,10 @@
                                 int *x, int *y, int *w, int *h);
     int (*status)(const game_state *state);
     bool can_print, can_print_in_colour;
-    void (*print_size)(const game_params *params, float *x, float *y);
-    void (*print)(drawing *dr, const game_state *state, int tilesize);
+    void (*print_size)(const game_params *params, const game_ui *ui,
+                       float *x, float *y);
+    void (*print)(drawing *dr, const game_state *state, const game_ui *ui,
+                  int tilesize);
     bool wants_statusbar;
     bool is_timed;
     bool (*timing_state)(const game_state *state, game_ui *ui);
--- a/range.c
+++ b/range.c
@@ -1623,7 +1623,7 @@
 };
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     *x = (1 + params->w) * tilesize;
     *y = (1 + params->h) * tilesize;
@@ -1766,15 +1766,17 @@
  * User interface: print
  */
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int print_width, print_height;
-    game_compute_size(params, 800, &print_width, &print_height);
+    game_compute_size(params, 800, ui, &print_width, &print_height);
     *x = print_width  / 100.0F;
     *y = print_height / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int const w = state->params.w, h = state->params.h;
     game_drawstate ds_obj, *ds = &ds_obj;
--- a/rect.c
+++ b/rect.c
@@ -2630,7 +2630,7 @@
 #define MAX4(x,y,z,w) ( max(max(x,y),max(z,w)) )
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -2907,7 +2907,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -2914,12 +2915,13 @@
     /*
      * I'll use 5mm squares by default.
      */
-    game_compute_size(params, 500, &pw, &ph);
+    game_compute_size(params, 500, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->w, h = state->h;
     int ink = print_mono_colour(dr, 0);
--- a/samegame.c
+++ b/samegame.c
@@ -1373,7 +1373,7 @@
 }
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up tile size variables for macro expansion purposes */
     game_drawstate ads, *ds = &ads;
--- a/signpost.c
+++ b/signpost.c
@@ -1659,7 +1659,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize, order; } ads, *ds = &ads;
@@ -2220,16 +2220,18 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
-    game_compute_size(params, 1300, &pw, &ph);
+    game_compute_size(params, 1300, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int ink = print_mono_colour(dr, 0);
     int x, y;
--- a/singles.c
+++ b/singles.c
@@ -1594,7 +1594,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -1783,17 +1783,19 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
     /* 8mm squares by default. */
-    game_compute_size(params, 800, &pw, &ph);
+    game_compute_size(params, 800, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int ink = print_mono_colour(dr, 0);
     int paper = print_mono_colour(dr, 1);
--- a/sixteen.c
+++ b/sixteen.c
@@ -802,7 +802,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
--- a/slant.c
+++ b/slant.c
@@ -1785,7 +1785,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* fool the macros */
     struct dummy { int tilesize; } dummy, *ds = &dummy;
@@ -2084,7 +2084,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -2091,12 +2092,13 @@
     /*
      * I'll use 6mm squares by default.
      */
-    game_compute_size(params, 600, &pw, &ph);
+    game_compute_size(params, 600, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->p.w, h = state->p.h, W = w+1;
     int ink = print_mono_colour(dr, 0);
--- a/solo.c
+++ b/solo.c
@@ -4810,7 +4810,7 @@
 #define GETTILESIZE(cr, w) ( (double)(w-1) / (double)(cr+1) )
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -5330,7 +5330,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -5339,7 +5340,7 @@
      * for this game, because players will want to jot down no end
      * of pencil marks in the squares.
      */
-    game_compute_size(params, 900, &pw, &ph);
+    game_compute_size(params, 900, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
@@ -5513,7 +5514,8 @@
     sfree(coords);
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int cr = state->cr;
     int ink = print_mono_colour(dr, 0);
--- a/tents.c
+++ b/tents.c
@@ -1905,7 +1905,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* fool the macros */
     struct dummy { int tilesize; } dummy, *ds = &dummy;
@@ -2596,7 +2596,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -2603,12 +2604,13 @@
     /*
      * I'll use 6mm squares by default.
      */
-    game_compute_size(params, 600, &pw, &ph);
+    game_compute_size(params, 600, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int c;
 
--- a/towers.c
+++ b/towers.c
@@ -1574,7 +1574,7 @@
 #define SIZE(w) ((w) * TILESIZE + 2*BORDER)
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -1954,7 +1954,8 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -1961,12 +1962,13 @@
     /*
      * We use 9mm squares by default, like Solo.
      */
-    game_compute_size(params, 900, &pw, &ph);
+    game_compute_size(params, 900, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->par.w;
     int ink = print_mono_colour(dr, 0);
--- a/tracks.c
+++ b/tracks.c
@@ -2479,7 +2479,7 @@
 #define FLASH_TIME 0.5F
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->sz6' and `ds->border` for macro expansion purposes */
     struct {
@@ -2976,17 +2976,19 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
     /* The Times uses 7mm squares */
-    game_compute_size(params, 700, &pw, &ph);
+    game_compute_size(params, 700, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->p.w, h = state->p.h;
     int black = print_mono_colour(dr, 0), grey = print_grey_colour(dr, 0.5F);
--- a/twiddle.c
+++ b/twiddle.c
@@ -800,7 +800,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
--- a/undead.c
+++ b/undead.c
@@ -2138,7 +2138,7 @@
 #define PREFERRED_TILE_SIZE 64
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
--- a/unequal.c
+++ b/unequal.c
@@ -1720,7 +1720,7 @@
 #define DRAW_SIZE (TILE_SIZE*ds->order + GAP_SIZE*(ds->order-1) + BORDER*2)
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize, order; } ads, *ds = &ads;
@@ -2083,17 +2083,19 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
     /* 10mm squares by default, roughly the same as Grauniad. */
-    game_compute_size(params, 1000, &pw, &ph);
+    game_compute_size(params, 1000, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int ink = print_mono_colour(dr, 0);
     int x, y, o = state->order, ox, oy, n;
--- a/unfinished/group.c
+++ b/unfinished/group.c
@@ -1807,7 +1807,7 @@
 #define SIZE(w) ((w) * TILESIZE + 2*BORDER + LEGEND)
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -2224,7 +2224,8 @@
     return true;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
@@ -2231,12 +2232,13 @@
     /*
      * We use 9mm squares by default, like Solo.
      */
-    game_compute_size(params, 900, &pw, &ph);
+    game_compute_size(params, 900, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w = state->par.w;
     int ink = print_mono_colour(dr, 0);
--- a/unfinished/separate.c
+++ b/unfinished/separate.c
@@ -731,7 +731,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     *x = *y = 10 * tilesize;	       /* FIXME */
 }
@@ -804,11 +804,13 @@
     return true;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
 }
 
--- a/unfinished/slide.c
+++ b/unfinished/slide.c
@@ -1594,7 +1594,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* fool the macros */
     struct dummy { int tilesize; } dummy, *ds = &dummy;
@@ -2297,11 +2297,13 @@
     return true;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
 }
 
--- a/unfinished/sokoban.c
+++ b/unfinished/sokoban.c
@@ -1178,7 +1178,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
     struct { int tilesize; } ads, *ds = &ads;
@@ -1419,11 +1419,13 @@
     return true;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
 }
 
--- a/unruly.c
+++ b/unruly.c
@@ -1727,7 +1727,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     *x = tilesize * (params->w2 + 1);
     *y = tilesize * (params->h2 + 1);
@@ -1965,17 +1965,19 @@
     return state->completed ? +1 : 0;
 }
 
-static void game_print_size(const game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, const game_ui *ui,
+                            float *x, float *y)
 {
     int pw, ph;
 
     /* Using 7mm squares */
-    game_compute_size(params, 700, &pw, &ph);
+    game_compute_size(params, 700, ui, &pw, &ph);
     *x = pw / 100.0F;
     *y = ph / 100.0F;
 }
 
-static void game_print(drawing *dr, const game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
+                       int tilesize)
 {
     int w2 = state->w2, h2 = state->h2;
     int x, y;
--- a/untangle.c
+++ b/untangle.c
@@ -1183,7 +1183,7 @@
  */
 
 static void game_compute_size(const game_params *params, int tilesize,
-                              int *x, int *y)
+                              const game_ui *ui, int *x, int *y)
 {
     *x = *y = COORDLIMIT(params->n) * tilesize;
 }
@@ -1341,7 +1341,7 @@
     ds->dragpoint = ui->dragpoint;
     ds->bg = bg;
 
-    game_compute_size(&state->params, ds->tilesize, &w, &h);
+    game_compute_size(&state->params, ds->tilesize, ui, &w, &h);
     draw_rect(dr, 0, 0, w, h, bg);
 
     /*