chiark / gitweb /
Substantial infrastructure upheaval. I've separated the drawing API
[sgt-puzzles.git] / net.c
diff --git a/net.c b/net.c
index a788d4692cd65fa8745390c656e3094665278afb..e205341a11dc6d5e6b7c1e428dedd59191197540 100644 (file)
--- a/net.c
+++ b/net.c
@@ -382,29 +382,6 @@ static char *validate_params(game_params *params, int full)
  * avoidance is required.
  */
 
-static int dsf_canonify(int *dsf, int val)
-{
-    int v2 = val;
-
-    while (dsf[val] != val)
-       val = dsf[val];
-
-    while (v2 != val) {
-       int tmp = dsf[v2];
-       dsf[v2] = val;
-       v2 = tmp;
-    }
-
-    return val;
-}
-
-static void dsf_merge(int *dsf, int v1, int v2)
-{
-    v1 = dsf_canonify(dsf, v1);
-    v2 = dsf_canonify(dsf, v2);
-    dsf[v2] = v1;
-}
-
 struct todo {
     unsigned char *marked;
     int *buffer;
@@ -1540,7 +1517,7 @@ static char *validate_desc(game_params *params, char *desc)
  * Construct an initial game state, given a description and parameters.
  */
 
-static game_state *new_game(midend_data *me, game_params *params, char *desc)
+static game_state *new_game(midend *me, game_params *params, char *desc)
 {
     game_state *state;
     int w, h, x, y;
@@ -1683,6 +1660,8 @@ static char *solve_game(game_state *state, game_state *currstate,
                 tiles[i] = c - 'a' + 10;
             else if (c >= 'A' && c <= 'F')
                 tiles[i] = c - 'A' + 10;
+
+           tiles[i] |= LOCKED;
         }
     }
 
@@ -2132,7 +2111,7 @@ static game_state *execute_move(game_state *from, char *move)
  * Routines for drawing the game position on the screen.
  */
 
-static game_drawstate *game_new_drawstate(game_state *state)
+static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
 {
     game_drawstate *ds = snew(game_drawstate);
 
@@ -2147,7 +2126,7 @@ static game_drawstate *game_new_drawstate(game_state *state)
     return ds;
 }
 
-static void game_free_drawstate(game_drawstate *ds)
+static void game_free_drawstate(drawing *dr, game_drawstate *ds)
 {
     sfree(ds->visible);
     sfree(ds);
@@ -2160,8 +2139,8 @@ static void game_compute_size(game_params *params, int tilesize,
     *y = WINDOW_OFFSET * 2 + tilesize * params->height + TILE_BORDER;
 }
 
-static void game_set_size(game_drawstate *ds, game_params *params,
-                         int tilesize)
+static void game_set_size(drawing *dr, game_drawstate *ds,
+                         game_params *params, int tilesize)
 {
     ds->tilesize = tilesize;
 }
@@ -2224,17 +2203,17 @@ static float *game_colours(frontend *fe, game_state *state, int *ncolours)
     return ret;
 }
 
-static void draw_thick_line(frontend *fe, int x1, int y1, int x2, int y2,
+static void draw_thick_line(drawing *dr, int x1, int y1, int x2, int y2,
                             int colour)
 {
-    draw_line(fe, x1-1, y1, x2-1, y2, COL_WIRE);
-    draw_line(fe, x1+1, y1, x2+1, y2, COL_WIRE);
-    draw_line(fe, x1, y1-1, x2, y2-1, COL_WIRE);
-    draw_line(fe, x1, y1+1, x2, y2+1, COL_WIRE);
-    draw_line(fe, x1, y1, x2, y2, colour);
+    draw_line(dr, x1-1, y1, x2-1, y2, COL_WIRE);
+    draw_line(dr, x1+1, y1, x2+1, y2, COL_WIRE);
+    draw_line(dr, x1, y1-1, x2, y2-1, COL_WIRE);
+    draw_line(dr, x1, y1+1, x2, y2+1, COL_WIRE);
+    draw_line(dr, x1, y1, x2, y2, colour);
 }
 
-static void draw_rect_coords(frontend *fe, int x1, int y1, int x2, int y2,
+static void draw_rect_coords(drawing *dr, int x1, int y1, int x2, int y2,
                              int colour)
 {
     int mx = (x1 < x2 ? x1 : x2);
@@ -2242,13 +2221,13 @@ static void draw_rect_coords(frontend *fe, int x1, int y1, int x2, int y2,
     int dx = (x2 + x1 - 2*mx + 1);
     int dy = (y2 + y1 - 2*my + 1);
 
-    draw_rect(fe, mx, my, dx, dy, colour);
+    draw_rect(dr, mx, my, dx, dy, colour);
 }
 
 /*
  * draw_barrier_corner() and draw_barrier() are passed physical coords
  */
-static void draw_barrier_corner(frontend *fe, game_drawstate *ds,
+static void draw_barrier_corner(drawing *dr, game_drawstate *ds,
                                 int x, int y, int dx, int dy, int phase)
 {
     int bx = WINDOW_OFFSET + TILE_SIZE * x;
@@ -2259,20 +2238,20 @@ static void draw_barrier_corner(frontend *fe, game_drawstate *ds,
     y1 = (dy > 0 ? TILE_SIZE+TILE_BORDER-1 : 0);
 
     if (phase == 0) {
-        draw_rect_coords(fe, bx+x1+dx, by+y1,
+        draw_rect_coords(dr, bx+x1+dx, by+y1,
                          bx+x1-TILE_BORDER*dx, by+y1-(TILE_BORDER-1)*dy,
                          COL_WIRE);
-        draw_rect_coords(fe, bx+x1, by+y1+dy,
+        draw_rect_coords(dr, bx+x1, by+y1+dy,
                          bx+x1-(TILE_BORDER-1)*dx, by+y1-TILE_BORDER*dy,
                          COL_WIRE);
     } else {
-        draw_rect_coords(fe, bx+x1, by+y1,
+        draw_rect_coords(dr, bx+x1, by+y1,
                          bx+x1-(TILE_BORDER-1)*dx, by+y1-(TILE_BORDER-1)*dy,
                          COL_BARRIER);
     }
 }
 
-static void draw_barrier(frontend *fe, game_drawstate *ds,
+static void draw_barrier(drawing *dr, game_drawstate *ds,
                          int x, int y, int dir, int phase)
 {
     int bx = WINDOW_OFFSET + TILE_SIZE * x;
@@ -2285,16 +2264,16 @@ static void draw_barrier(frontend *fe, game_drawstate *ds,
     h = (Y(dir) ? TILE_BORDER : TILE_SIZE - TILE_BORDER);
 
     if (phase == 0) {
-        draw_rect(fe, bx+x1-X(dir), by+y1-Y(dir), w, h, COL_WIRE);
+        draw_rect(dr, bx+x1-X(dir), by+y1-Y(dir), w, h, COL_WIRE);
     } else {
-        draw_rect(fe, bx+x1, by+y1, w, h, COL_BARRIER);
+        draw_rect(dr, bx+x1, by+y1, w, h, COL_BARRIER);
     }
 }
 
 /*
  * draw_tile() is passed physical coordinates
  */
-static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
+static void draw_tile(drawing *dr, game_state *state, game_drawstate *ds,
                       int x, int y, int tile, int src, float angle, int cursor)
 {
     int bx = WINDOW_OFFSET + TILE_SIZE * x;
@@ -2310,16 +2289,16 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
      * we must draw those connections on the borders themselves.
      */
 
-    clip(fe, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER);
+    clip(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER);
 
     /*
      * So. First blank the tile out completely: draw a big
      * rectangle in border colour, and a smaller rectangle in
      * background colour to fill it in.
      */
-    draw_rect(fe, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER,
+    draw_rect(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER,
               COL_BORDER);
-    draw_rect(fe, bx+TILE_BORDER, by+TILE_BORDER,
+    draw_rect(dr, bx+TILE_BORDER, by+TILE_BORDER,
               TILE_SIZE-TILE_BORDER, TILE_SIZE-TILE_BORDER,
               tile & LOCKED ? COL_LOCKED : COL_BACKGROUND);
 
@@ -2329,16 +2308,16 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
      * in.
      */
     if (cursor) {
-       draw_line(fe, bx+TILE_SIZE/8, by+TILE_SIZE/8,
+       draw_line(dr, bx+TILE_SIZE/8, by+TILE_SIZE/8,
                  bx+TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8,
                  tile & LOCKED ? COL_BACKGROUND : COL_LOCKED);
-       draw_line(fe, bx+TILE_SIZE/8, by+TILE_SIZE/8,
+       draw_line(dr, bx+TILE_SIZE/8, by+TILE_SIZE/8,
                  bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE/8,
                  tile & LOCKED ? COL_BACKGROUND : COL_LOCKED);
-       draw_line(fe, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE/8,
+       draw_line(dr, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE/8,
                  bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8,
                  tile & LOCKED ? COL_BACKGROUND : COL_LOCKED);
-       draw_line(fe, bx+TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8,
+       draw_line(dr, bx+TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8,
                  bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8,
                  tile & LOCKED ? COL_BACKGROUND : COL_LOCKED);
     }
@@ -2361,7 +2340,7 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
             ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir);
             ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir);
             MATMUL(tx, ty, matrix, ex, ey);
-            draw_thick_line(fe, bx+(int)cx, by+(int)cy,
+            draw_thick_line(dr, bx+(int)cx, by+(int)cy,
                            bx+(int)(cx+tx), by+(int)(cy+ty),
                             COL_WIRE);
         }
@@ -2371,7 +2350,7 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
             ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir);
             ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir);
             MATMUL(tx, ty, matrix, ex, ey);
-            draw_line(fe, bx+(int)cx, by+(int)cy,
+            draw_line(dr, bx+(int)cx, by+(int)cy,
                      bx+(int)(cx+tx), by+(int)(cy+ty), col);
         }
     }
@@ -2404,7 +2383,7 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
             points[i+1] = by+(int)(cy+ty);
         }
 
-        draw_polygon(fe, points, 4, col, COL_WIRE);
+        draw_polygon(dr, points, 4, col, COL_WIRE);
     }
 
     /*
@@ -2441,8 +2420,8 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
              * in: if we are fully connected to the other tile then
              * the two ACTIVE states will be the same.)
              */
-            draw_rect_coords(fe, px-vx, py-vy, px+lx+vx, py+ly+vy, COL_WIRE);
-            draw_rect_coords(fe, px, py, px+lx, py+ly,
+            draw_rect_coords(dr, px-vx, py-vy, px+lx+vx, py+ly+vy, COL_WIRE);
+            draw_rect_coords(dr, px, py, px+lx, py+ly,
                              (tile & ACTIVE) ? COL_POWERED : COL_WIRE);
         } else {
             /*
@@ -2450,7 +2429,7 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
              * actually connected to us. Just draw a single black
              * dot.
              */
-            draw_rect_coords(fe, px, py, px, py, COL_WIRE);
+            draw_rect_coords(dr, px, py, px, py, COL_WIRE);
         }
     }
 
@@ -2494,7 +2473,7 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
                  * At least one barrier terminates here. Draw a
                  * corner.
                  */
-                draw_barrier_corner(fe, ds, x, y,
+                draw_barrier_corner(dr, ds, x, y,
                                     X(dir)+X(A(dir)), Y(dir)+Y(A(dir)),
                                     phase);
             }
@@ -2502,15 +2481,15 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds,
 
         for (dir = 1; dir < 0x10; dir <<= 1)
             if (barrier(state, GX(x), GY(y)) & dir)
-                draw_barrier(fe, ds, x, y, dir, phase);
+                draw_barrier(dr, ds, x, y, dir, phase);
     }
 
-    unclip(fe);
+    unclip(dr);
 
-    draw_update(fe, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER);
+    draw_update(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER);
 }
 
-static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
+static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
                  game_state *state, int dir, game_ui *ui, float t, float ft)
 {
     int x, y, tx, ty, frame, last_rotate_dir, moved_origin = FALSE;
@@ -2526,7 +2505,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
 
         ds->started = TRUE;
 
-        draw_rect(fe, 0, 0, 
+        draw_rect(dr, 0, 0, 
                   WINDOW_OFFSET * 2 + TILE_SIZE * state->width + TILE_BORDER,
                   WINDOW_OFFSET * 2 + TILE_SIZE * state->height + TILE_BORDER,
                   COL_BACKGROUND);
@@ -2535,7 +2514,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
         ds->org_y = ui->org_y;
         moved_origin = TRUE;
 
-        draw_update(fe, 0, 0, 
+        draw_update(dr, 0, 0, 
                     WINDOW_OFFSET*2 + TILE_SIZE*state->width + TILE_BORDER,
                     WINDOW_OFFSET*2 + TILE_SIZE*state->height + TILE_BORDER);
 
@@ -2544,38 +2523,38 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
             for (x = 0; x < ds->width; x++) {
                 if (x+1 < ds->width) {
                     if (barrier(state, GX(x), GY(0)) & R)
-                        draw_barrier_corner(fe, ds, x, -1, +1, +1, phase);
+                        draw_barrier_corner(dr, ds, x, -1, +1, +1, phase);
                     if (barrier(state, GX(x), GY(ds->height-1)) & R)
-                        draw_barrier_corner(fe, ds, x, ds->height, +1, -1, phase);
+                        draw_barrier_corner(dr, ds, x, ds->height, +1, -1, phase);
                 }
                 if (barrier(state, GX(x), GY(0)) & U) {
-                    draw_barrier_corner(fe, ds, x, -1, -1, +1, phase);
-                    draw_barrier_corner(fe, ds, x, -1, +1, +1, phase);
-                    draw_barrier(fe, ds, x, -1, D, phase);
+                    draw_barrier_corner(dr, ds, x, -1, -1, +1, phase);
+                    draw_barrier_corner(dr, ds, x, -1, +1, +1, phase);
+                    draw_barrier(dr, ds, x, -1, D, phase);
                 }
                 if (barrier(state, GX(x), GY(ds->height-1)) & D) {
-                    draw_barrier_corner(fe, ds, x, ds->height, -1, -1, phase);
-                    draw_barrier_corner(fe, ds, x, ds->height, +1, -1, phase);
-                    draw_barrier(fe, ds, x, ds->height, U, phase);
+                    draw_barrier_corner(dr, ds, x, ds->height, -1, -1, phase);
+                    draw_barrier_corner(dr, ds, x, ds->height, +1, -1, phase);
+                    draw_barrier(dr, ds, x, ds->height, U, phase);
                 }
             }
 
             for (y = 0; y < ds->height; y++) {
                 if (y+1 < ds->height) {
                     if (barrier(state, GX(0), GY(y)) & D)
-                        draw_barrier_corner(fe, ds, -1, y, +1, +1, phase);
+                        draw_barrier_corner(dr, ds, -1, y, +1, +1, phase);
                     if (barrier(state, GX(ds->width-1), GY(y)) & D)
-                        draw_barrier_corner(fe, ds, ds->width, y, -1, +1, phase);
+                        draw_barrier_corner(dr, ds, ds->width, y, -1, +1, phase);
                 }
                 if (barrier(state, GX(0), GY(y)) & L) {
-                    draw_barrier_corner(fe, ds, -1, y, +1, -1, phase);
-                    draw_barrier_corner(fe, ds, -1, y, +1, +1, phase);
-                    draw_barrier(fe, ds, -1, y, R, phase);
+                    draw_barrier_corner(dr, ds, -1, y, +1, -1, phase);
+                    draw_barrier_corner(dr, ds, -1, y, +1, +1, phase);
+                    draw_barrier(dr, ds, -1, y, R, phase);
                 }
                 if (barrier(state, GX(ds->width-1), GY(y)) & R) {
-                    draw_barrier_corner(fe, ds, ds->width, y, -1, -1, phase);
-                    draw_barrier_corner(fe, ds, ds->width, y, -1, +1, phase);
-                    draw_barrier(fe, ds, ds->width, y, L, phase);
+                    draw_barrier_corner(dr, ds, ds->width, y, -1, -1, phase);
+                    draw_barrier_corner(dr, ds, ds->width, y, -1, +1, phase);
+                    draw_barrier(dr, ds, ds->width, y, L, phase);
                 }
             }
         }
@@ -2641,7 +2620,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
                 index(state, ds->visible, x, y) != c ||
                 index(state, ds->visible, x, y) == 0xFF ||
                 is_src || is_anim || is_cursor) {
-                draw_tile(fe, state, ds, x, y, c,
+                draw_tile(dr, state, ds, x, y, c,
                           is_src, (is_anim ? angle : 0.0F), is_cursor);
                 if (is_src || is_anim || is_cursor)
                     index(state, ds->visible, x, y) = 0xFF;
@@ -2669,7 +2648,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
                (state->used_solve ? "Auto-solved. " :
                 state->completed ? "COMPLETED! " : ""), a, n2);
 
-       status_bar(fe, statusbuf);
+       status_bar(dr, statusbuf);
     }
 
     sfree(active);
@@ -2728,6 +2707,143 @@ static int game_timing_state(game_state *state, game_ui *ui)
     return TRUE;
 }
 
+static void game_print_size(game_params *params, float *x, float *y)
+{
+    int pw, ph;
+
+    /*
+     * I'll use 8mm squares by default.
+     */
+    game_compute_size(params, 800, &pw, &ph);
+    *x = pw / 100.0;
+    *y = ph / 100.0;
+}
+
+static void draw_diagram(drawing *dr, game_drawstate *ds, int x, int y,
+                        int topleft, int v, int drawlines, int ink)
+{
+    int tx, ty, cx, cy, r, br, k, thick;
+
+    tx = WINDOW_OFFSET + TILE_SIZE * x;
+    ty = WINDOW_OFFSET + TILE_SIZE * y;
+
+    /*
+     * Find our centre point.
+     */
+    if (topleft) {
+       cx = tx + (v & L ? TILE_SIZE / 4 : TILE_SIZE / 6);
+       cy = ty + (v & U ? TILE_SIZE / 4 : TILE_SIZE / 6);
+       r = TILE_SIZE / 8;
+       br = TILE_SIZE / 32;
+    } else {
+       cx = tx + TILE_SIZE / 2;
+       cy = ty + TILE_SIZE / 2;
+       r = TILE_SIZE / 2;
+       br = TILE_SIZE / 8;
+    }
+    thick = r / 20;
+
+    /*
+     * Draw the square block if we have an endpoint.
+     */
+    if (v == 1 || v == 2 || v == 4 || v == 8)
+       draw_rect(dr, cx - br, cy - br, br*2, br*2, ink);
+
+    /*
+     * Draw each radial line.
+     */
+    if (drawlines) {
+       print_line_width(dr, thick * 2);
+       for (k = 1; k < 16; k *= 2)
+           if (v & k) {
+               int x1 = min(cx, cx + (r-thick) * X(k));
+               int x2 = max(cx, cx + (r-thick) * X(k));
+               int y1 = min(cy, cy + (r-thick) * Y(k));
+               int y2 = max(cy, cy + (r-thick) * Y(k));
+               draw_rect(dr, x1 - thick, y1 - thick,
+                         (x2 - x1) + 2*thick, (y2 - y1) + 2*thick, ink);
+           }
+    }
+}
+
+static void game_print(drawing *dr, game_state *state, int tilesize)
+{
+    int w = state->width, h = state->height;
+    int ink = print_mono_colour(dr, 0);
+    int x, y;
+
+    /* Ick: fake up `ds->tilesize' for macro expansion purposes */
+    game_drawstate ads, *ds = &ads;
+    ads.tilesize = tilesize;
+
+    /*
+     * Border.
+     */
+    print_line_width(dr, TILE_SIZE / (state->wrapping ? 128 : 12));
+    draw_rect_outline(dr, WINDOW_OFFSET, WINDOW_OFFSET,
+                     TILE_SIZE * w, TILE_SIZE * h, ink);
+
+    /*
+     * Grid.
+     */
+    print_line_width(dr, TILE_SIZE / 128);
+    for (x = 1; x < w; x++)
+       draw_line(dr, WINDOW_OFFSET + TILE_SIZE * x, WINDOW_OFFSET,
+                 WINDOW_OFFSET + TILE_SIZE * x, WINDOW_OFFSET + TILE_SIZE * h,
+                 ink);
+    for (y = 1; y < h; y++)
+       draw_line(dr, WINDOW_OFFSET, WINDOW_OFFSET + TILE_SIZE * y,
+                 WINDOW_OFFSET + TILE_SIZE * w, WINDOW_OFFSET + TILE_SIZE * y,
+                 ink);
+
+    /*
+     * Barriers.
+     */
+    for (y = 0; y <= h; y++)
+       for (x = 0; x <= w; x++) {
+           int b = barrier(state, x % w, y % h);
+           fprintf(stderr, "%d,%d: %d\n", x, y, b);
+           if (x < w && (b & U))
+               draw_rect(dr, WINDOW_OFFSET + TILE_SIZE * x - TILE_SIZE/24,
+                         WINDOW_OFFSET + TILE_SIZE * y - TILE_SIZE/24,
+                         TILE_SIZE + TILE_SIZE/24 * 2, TILE_SIZE/24 * 2, ink);
+           if (y < h && (b & L))
+               draw_rect(dr, WINDOW_OFFSET + TILE_SIZE * x - TILE_SIZE/24,
+                         WINDOW_OFFSET + TILE_SIZE * y - TILE_SIZE/24,
+                         TILE_SIZE/24 * 2, TILE_SIZE + TILE_SIZE/24 * 2, ink);
+       }
+
+    /*
+     * Grid contents.
+     */
+    for (y = 0; y < h; y++)
+       for (x = 0; x < w; x++) {
+           int vx, v = tile(state, x, y);
+           int locked = v & LOCKED;
+
+           v &= 0xF;
+
+           /*
+            * Rotate into a standard orientation for the top left
+            * corner diagram.
+            */
+           vx = v;
+           while (vx != 0 && vx != 15 && vx != 1 && vx != 9 && vx != 13 &&
+                  vx != 5)
+               vx = A(vx);
+
+           /*
+            * Draw the top left corner diagram.
+            */
+           draw_diagram(dr, ds, x, y, TRUE, vx, TRUE, ink);
+
+           /*
+            * Draw the real solution diagram, if we're doing so.
+            */
+           draw_diagram(dr, ds, x, y, FALSE, v, locked, ink);
+       }
+}
+
 #ifdef COMBINED
 #define thegame net
 #endif
@@ -2763,6 +2879,7 @@ const struct game thegame = {
     game_redraw,
     game_anim_length,
     game_flash_length,
+    TRUE, FALSE, game_print_size, game_print,
     game_wants_statusbar,
     FALSE, game_timing_state,
     0,                                /* mouse_priorities */