+ int pw, ph;
+
+ /*
+ * I'll use 9mm squares by default. They should be quite big
+ * 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);
+ *x = pw / 100.0;
+ *y = ph / 100.0;
+}
+
+static void game_print(drawing *dr, game_state *state, int tilesize)
+{
+ int cr = state->cr;
+ int ink = print_mono_colour(dr, 0);
+ int x, y;
+
+ /* Ick: fake up `ds->tilesize' for macro expansion purposes */
+ game_drawstate ads, *ds = &ads;
+ game_set_size(dr, ds, NULL, tilesize);
+
+ /*
+ * Border.
+ */
+ print_line_width(dr, 3 * TILE_SIZE / 40);
+ draw_rect_outline(dr, BORDER, BORDER, cr*TILE_SIZE, cr*TILE_SIZE, ink);
+
+ /*
+ * Highlight X-diagonal squares.
+ */
+ if (state->xtype) {
+ int i;
+ int xhighlight = print_grey_colour(dr, HATCH_SLASH, 0.90F);
+
+ for (i = 0; i < cr; i++)
+ draw_rect(dr, BORDER + i*TILE_SIZE, BORDER + i*TILE_SIZE,
+ TILE_SIZE, TILE_SIZE, xhighlight);
+ for (i = 0; i < cr; i++)
+ if (i*2 != cr-1) /* avoid redoing centre square, just for fun */
+ draw_rect(dr, BORDER + i*TILE_SIZE,
+ BORDER + (cr-1-i)*TILE_SIZE,
+ TILE_SIZE, TILE_SIZE, xhighlight);
+ }
+
+ /*
+ * Main grid.
+ */
+ for (x = 1; x < cr; x++) {
+ print_line_width(dr, TILE_SIZE / 40);
+ draw_line(dr, BORDER+x*TILE_SIZE, BORDER,
+ BORDER+x*TILE_SIZE, BORDER+cr*TILE_SIZE, ink);
+ }
+ for (y = 1; y < cr; y++) {
+ print_line_width(dr, TILE_SIZE / 40);
+ draw_line(dr, BORDER, BORDER+y*TILE_SIZE,
+ BORDER+cr*TILE_SIZE, BORDER+y*TILE_SIZE, ink);
+ }
+
+ /*
+ * Thick lines between cells. In order to do this using the
+ * line-drawing rather than rectangle-drawing API (so as to
+ * get line thicknesses to scale correctly) and yet have
+ * correctly mitred joins between lines, we must do this by
+ * tracing the boundary of each sub-block and drawing it in
+ * one go as a single polygon.
+ */
+ {
+ int *coords;
+ int bi, i, n;
+ int x, y, dx, dy, sx, sy, sdx, sdy;
+
+ print_line_width(dr, 3 * TILE_SIZE / 40);
+
+ /*
+ * Maximum perimeter of a k-omino is 2k+2. (Proof: start
+ * with k unconnected squares, with total perimeter 4k.
+ * Now repeatedly join two disconnected components
+ * together into a larger one; every time you do so you
+ * remove at least two unit edges, and you require k-1 of
+ * these operations to create a single connected piece, so
+ * you must have at most 4k-2(k-1) = 2k+2 unit edges left
+ * afterwards.)
+ */
+ coords = snewn(4*cr+4, int); /* 2k+2 points, 2 coords per point */
+
+ /*
+ * Iterate over all the blocks.
+ */
+ for (bi = 0; bi < cr; bi++) {
+
+ /*
+ * For each block, find a starting square within it
+ * which has a boundary at the left.
+ */
+ for (i = 0; i < cr; i++) {
+ int j = state->blocks->blocks[bi][i];
+ if (j % cr == 0 || state->blocks->whichblock[j-1] != bi)
+ break;
+ }
+ assert(i < cr); /* every block must have _some_ leftmost square */
+ x = state->blocks->blocks[bi][i] % cr;
+ y = state->blocks->blocks[bi][i] / cr;
+ dx = -1;
+ dy = 0;
+
+ /*
+ * Now begin tracing round the perimeter. At all
+ * times, (x,y) describes some square within the
+ * block, and (x+dx,y+dy) is some adjacent square
+ * outside it; so the edge between those two squares
+ * is always an edge of the block.
+ */
+ sx = x, sy = y, sdx = dx, sdy = dy; /* save starting position */
+ n = 0;
+ do {
+ int cx, cy, tx, ty, nin;
+
+ /*
+ * To begin with, record the point at one end of
+ * the edge. To do this, we translate (x,y) down
+ * and right by half a unit (so they're describing
+ * a point in the _centre_ of the square) and then
+ * translate back again in a manner rotated by dy
+ * and dx.
+ */
+ assert(n < 2*cr+2);
+ cx = ((2*x+1) + dy + dx) / 2;
+ cy = ((2*y+1) - dx + dy) / 2;
+ coords[2*n+0] = BORDER + cx * TILE_SIZE;
+ coords[2*n+1] = BORDER + cy * TILE_SIZE;
+ n++;
+
+ /*
+ * Now advance to the next edge, by looking at the
+ * two squares beyond it. If they're both outside
+ * the block, we turn right (by leaving x,y the
+ * same and rotating dx,dy clockwise); if they're
+ * both inside, we turn left (by rotating dx,dy
+ * anticlockwise and contriving to leave x+dx,y+dy
+ * unchanged); if one of each, we go straight on
+ * (and may enforce by assertion that they're one
+ * of each the _right_ way round).
+ */
+ nin = 0;
+ tx = x - dy + dx;
+ ty = y + dx + dy;
+ nin += (tx >= 0 && tx < cr && ty >= 0 && ty < cr &&
+ state->blocks->whichblock[ty*cr+tx] == bi);
+ tx = x - dy;
+ ty = y + dx;
+ nin += (tx >= 0 && tx < cr && ty >= 0 && ty < cr &&
+ state->blocks->whichblock[ty*cr+tx] == bi);
+ if (nin == 0) {
+ /*
+ * Turn right.
+ */
+ int tmp;
+ tmp = dx;
+ dx = -dy;
+ dy = tmp;
+ } else if (nin == 2) {
+ /*
+ * Turn left.
+ */
+ int tmp;
+
+ x += dx;
+ y += dy;
+
+ tmp = dx;
+ dx = dy;
+ dy = -tmp;
+
+ x -= dx;
+ y -= dy;
+ } else {
+ /*
+ * Go straight on.
+ */
+ x -= dy;
+ y += dx;
+ }
+
+ /*
+ * Now enforce by assertion that we ended up
+ * somewhere sensible.
+ */
+ assert(x >= 0 && x < cr && y >= 0 && y < cr &&
+ state->blocks->whichblock[y*cr+x] == bi);
+ assert(x+dx < 0 || x+dx >= cr || y+dy < 0 || y+dy >= cr ||
+ state->blocks->whichblock[(y+dy)*cr+(x+dx)] != bi);
+
+ } while (x != sx || y != sy || dx != sdx || dy != sdy);
+
+ /*
+ * That's our polygon; now draw it.
+ */
+ draw_polygon(dr, coords, n, -1, ink);
+ }
+
+ sfree(coords);
+ }
+
+ /*
+ * Numbers.
+ */
+ for (y = 0; y < cr; y++)
+ for (x = 0; x < cr; x++)
+ if (state->grid[y*cr+x]) {
+ char str[2];
+ str[1] = '\0';
+ str[0] = state->grid[y*cr+x] + '0';
+ if (str[0] > '9')
+ str[0] += 'a' - ('9'+1);
+ draw_text(dr, BORDER + x*TILE_SIZE + TILE_SIZE/2,
+ BORDER + y*TILE_SIZE + TILE_SIZE/2,
+ FONT_VARIABLE, TILE_SIZE/2,
+ ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str);
+ }