chiark / gitweb /
New infrastructure feature. Games are now permitted to be
[sgt-puzzles.git] / dominosa.c
1 /*
2  * dominosa.c: Domino jigsaw puzzle. Aim to place one of every
3  * possible domino within a rectangle in such a way that the number
4  * on each square matches the provided clue.
5  */
6
7 /*
8  * TODO:
9  * 
10  *  - improve solver so as to use more interesting forms of
11  *    deduction
12  *
13  *     * rule out a domino placement if it would divide an unfilled
14  *       region such that at least one resulting region had an odd
15  *       area
16  *        + use b.f.s. to determine the area of an unfilled region
17  *        + a square is unfilled iff it has at least two possible
18  *          placements, and two adjacent unfilled squares are part
19  *          of the same region iff the domino placement joining
20  *          them is possible
21  *
22  *     * perhaps set analysis
23  *        + look at all unclaimed squares containing a given number
24  *        + for each one, find the set of possible numbers that it
25  *          can connect to (i.e. each neighbouring tile such that
26  *          the placement between it and that neighbour has not yet
27  *          been ruled out)
28  *        + now proceed similarly to Solo set analysis: try to find
29  *          a subset of the squares such that the union of their
30  *          possible numbers is the same size as the subset. If so,
31  *          rule out those possible numbers for all other squares.
32  *           * important wrinkle: the double dominoes complicate
33  *             matters. Connecting a number to itself uses up _two_
34  *             of the unclaimed squares containing a number. Thus,
35  *             when finding the initial subset we must never
36  *             include two adjacent squares; and also, when ruling
37  *             things out after finding the subset, we must be
38  *             careful that we don't rule out precisely the domino
39  *             placement that was _included_ in our set!
40  */
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <assert.h>
46 #include <ctype.h>
47 #include <math.h>
48
49 #include "puzzles.h"
50
51 /* nth triangular number */
52 #define TRI(n) ( (n) * ((n) + 1) / 2 )
53 /* number of dominoes for value n */
54 #define DCOUNT(n) TRI((n)+1)
55 /* map a pair of numbers to a unique domino index from 0 upwards. */
56 #define DINDEX(n1,n2) ( TRI(max(n1,n2)) + min(n1,n2) )
57
58 #define FLASH_TIME 0.13F
59
60 enum {
61     COL_BACKGROUND,
62     COL_TEXT,
63     COL_DOMINO,
64     COL_DOMINOCLASH,
65     COL_DOMINOTEXT,
66     COL_EDGE,
67     NCOLOURS
68 };
69
70 struct game_params {
71     int n;
72     int unique;
73 };
74
75 struct game_numbers {
76     int refcount;
77     int *numbers;                      /* h x w */
78 };
79
80 #define EDGE_L 0x100
81 #define EDGE_R 0x200
82 #define EDGE_T 0x400
83 #define EDGE_B 0x800
84
85 struct game_state {
86     game_params params;
87     int w, h;
88     struct game_numbers *numbers;
89     int *grid;
90     unsigned short *edges;             /* h x w */
91     int completed, cheated;
92 };
93
94 static game_params *default_params(void)
95 {
96     game_params *ret = snew(game_params);
97
98     ret->n = 6;
99     ret->unique = TRUE;
100
101     return ret;
102 }
103
104 static int game_fetch_preset(int i, char **name, game_params **params)
105 {
106     game_params *ret;
107     int n;
108     char buf[80];
109
110     switch (i) {
111       case 0: n = 3; break;
112       case 1: n = 6; break;
113       case 2: n = 9; break;
114       default: return FALSE;
115     }
116
117     sprintf(buf, "Up to double-%d", n);
118     *name = dupstr(buf);
119
120     *params = ret = snew(game_params);
121     ret->n = n;
122     ret->unique = TRUE;
123
124     return TRUE;
125 }
126
127 static void free_params(game_params *params)
128 {
129     sfree(params);
130 }
131
132 static game_params *dup_params(game_params *params)
133 {
134     game_params *ret = snew(game_params);
135     *ret = *params;                    /* structure copy */
136     return ret;
137 }
138
139 static void decode_params(game_params *params, char const *string)
140 {
141     params->n = atoi(string);
142     while (*string && isdigit((unsigned char)*string)) string++;
143     if (*string == 'a')
144         params->unique = FALSE;
145 }
146
147 static char *encode_params(game_params *params, int full)
148 {
149     char buf[80];
150     sprintf(buf, "%d", params->n);
151     if (full && !params->unique)
152         strcat(buf, "a");
153     return dupstr(buf);
154 }
155
156 static config_item *game_configure(game_params *params)
157 {
158     config_item *ret;
159     char buf[80];
160
161     ret = snewn(3, config_item);
162
163     ret[0].name = "Maximum number on dominoes";
164     ret[0].type = C_STRING;
165     sprintf(buf, "%d", params->n);
166     ret[0].sval = dupstr(buf);
167     ret[0].ival = 0;
168
169     ret[1].name = "Ensure unique solution";
170     ret[1].type = C_BOOLEAN;
171     ret[1].sval = NULL;
172     ret[1].ival = params->unique;
173
174     ret[2].name = NULL;
175     ret[2].type = C_END;
176     ret[2].sval = NULL;
177     ret[2].ival = 0;
178
179     return ret;
180 }
181
182 static game_params *custom_params(config_item *cfg)
183 {
184     game_params *ret = snew(game_params);
185
186     ret->n = atoi(cfg[0].sval);
187     ret->unique = cfg[1].ival;
188
189     return ret;
190 }
191
192 static char *validate_params(game_params *params, int full)
193 {
194     if (params->n < 1)
195         return "Maximum face number must be at least one";
196     return NULL;
197 }
198
199 /* ----------------------------------------------------------------------
200  * Solver.
201  */
202
203 static int find_overlaps(int w, int h, int placement, int *set)
204 {
205     int x, y, n;
206
207     n = 0;                             /* number of returned placements */
208
209     x = placement / 2;
210     y = x / w;
211     x %= w;
212
213     if (placement & 1) {
214         /*
215          * Horizontal domino, indexed by its left end.
216          */
217         if (x > 0)
218             set[n++] = placement-2;    /* horizontal domino to the left */
219         if (y > 0)
220             set[n++] = placement-2*w-1;/* vertical domino above left side */
221         if (y+1 < h)
222             set[n++] = placement-1;    /* vertical domino below left side */
223         if (x+2 < w)
224             set[n++] = placement+2;    /* horizontal domino to the right */
225         if (y > 0)
226             set[n++] = placement-2*w+2-1;/* vertical domino above right side */
227         if (y+1 < h)
228             set[n++] = placement+2-1;  /* vertical domino below right side */
229     } else {
230         /*
231          * Vertical domino, indexed by its top end.
232          */
233         if (y > 0)
234             set[n++] = placement-2*w;  /* vertical domino above */
235         if (x > 0)
236             set[n++] = placement-2+1;  /* horizontal domino left of top */
237         if (x+1 < w)
238             set[n++] = placement+1;    /* horizontal domino right of top */
239         if (y+2 < h)
240             set[n++] = placement+2*w;  /* vertical domino below */
241         if (x > 0)
242             set[n++] = placement-2+2*w+1;/* horizontal domino left of bottom */
243         if (x+1 < w)
244             set[n++] = placement+2*w+1;/* horizontal domino right of bottom */
245     }
246
247     return n;
248 }
249
250 /*
251  * Returns 0, 1 or 2 for number of solutions. 2 means `any number
252  * more than one', or more accurately `we were unable to prove
253  * there was only one'.
254  * 
255  * Outputs in a `placements' array, indexed the same way as the one
256  * within this function (see below); entries in there are <0 for a
257  * placement ruled out, 0 for an uncertain placement, and 1 for a
258  * definite one.
259  */
260 static int solver(int w, int h, int n, int *grid, int *output)
261 {
262     int wh = w*h, dc = DCOUNT(n);
263     int *placements, *heads;
264     int i, j, x, y, ret;
265
266     /*
267      * This array has one entry for every possible domino
268      * placement. Vertical placements are indexed by their top
269      * half, at (y*w+x)*2; horizontal placements are indexed by
270      * their left half at (y*w+x)*2+1.
271      * 
272      * This array is used to link domino placements together into
273      * linked lists, so that we can track all the possible
274      * placements of each different domino. It's also used as a
275      * quick means of looking up an individual placement to see
276      * whether we still think it's possible. Actual values stored
277      * in this array are -2 (placement not possible at all), -1
278      * (end of list), or the array index of the next item.
279      * 
280      * Oh, and -3 for `not even valid', used for array indices
281      * which don't even represent a plausible placement.
282      */
283     placements = snewn(2*wh, int);
284     for (i = 0; i < 2*wh; i++)
285         placements[i] = -3;            /* not even valid */
286
287     /*
288      * This array has one entry for every domino, and it is an
289      * index into `placements' denoting the head of the placement
290      * list for that domino.
291      */
292     heads = snewn(dc, int);
293     for (i = 0; i < dc; i++)
294         heads[i] = -1;
295
296     /*
297      * Set up the initial possibility lists by scanning the grid.
298      */
299     for (y = 0; y < h-1; y++)
300         for (x = 0; x < w; x++) {
301             int di = DINDEX(grid[y*w+x], grid[(y+1)*w+x]);
302             placements[(y*w+x)*2] = heads[di];
303             heads[di] = (y*w+x)*2;
304         }
305     for (y = 0; y < h; y++)
306         for (x = 0; x < w-1; x++) {
307             int di = DINDEX(grid[y*w+x], grid[y*w+(x+1)]);
308             placements[(y*w+x)*2+1] = heads[di];
309             heads[di] = (y*w+x)*2+1;
310         }
311
312 #ifdef SOLVER_DIAGNOSTICS
313     printf("before solver:\n");
314     for (i = 0; i <= n; i++)
315         for (j = 0; j <= i; j++) {
316             int k, m;
317             m = 0;
318             printf("%2d [%d %d]:", DINDEX(i, j), i, j);
319             for (k = heads[DINDEX(i,j)]; k >= 0; k = placements[k])
320                 printf(" %3d [%d,%d,%c]", k, k/2%w, k/2/w, k%2?'h':'v');
321             printf("\n");
322         }
323 #endif
324
325     while (1) {
326         int done_something = FALSE;
327
328         /*
329          * For each domino, look at its possible placements, and
330          * for each placement consider the placements (of any
331          * domino) it overlaps. Any placement overlapped by all
332          * placements of this domino can be ruled out.
333          * 
334          * Each domino placement overlaps only six others, so we
335          * need not do serious set theory to work this out.
336          */
337         for (i = 0; i < dc; i++) {
338             int permset[6], permlen = 0, p;
339             
340
341             if (heads[i] == -1) {      /* no placement for this domino */
342                 ret = 0;               /* therefore puzzle is impossible */
343                 goto done;
344             }
345             for (j = heads[i]; j >= 0; j = placements[j]) {
346                 assert(placements[j] != -2);
347
348                 if (j == heads[i]) {
349                     permlen = find_overlaps(w, h, j, permset);
350                 } else {
351                     int tempset[6], templen, m, n, k;
352
353                     templen = find_overlaps(w, h, j, tempset);
354
355                     /*
356                      * Pathetically primitive set intersection
357                      * algorithm, which I'm only getting away with
358                      * because I know my sets are bounded by a very
359                      * small size.
360                      */
361                     for (m = n = 0; m < permlen; m++) {
362                         for (k = 0; k < templen; k++)
363                             if (tempset[k] == permset[m])
364                                 break;
365                         if (k < templen)
366                             permset[n++] = permset[m];
367                     }
368                     permlen = n;
369                 }
370             }
371             for (p = 0; p < permlen; p++) {
372                 j = permset[p];
373                 if (placements[j] != -2) {
374                     int p1, p2, di;
375
376                     done_something = TRUE;
377
378                     /*
379                      * Rule out this placement. First find what
380                      * domino it is...
381                      */
382                     p1 = j / 2;
383                     p2 = (j & 1) ? p1 + 1 : p1 + w;
384                     di = DINDEX(grid[p1], grid[p2]);
385 #ifdef SOLVER_DIAGNOSTICS
386                     printf("considering domino %d: ruling out placement %d"
387                            " for %d\n", i, j, di);
388 #endif
389
390                     /*
391                      * ... then walk that domino's placement list,
392                      * removing this placement when we find it.
393                      */
394                     if (heads[di] == j)
395                         heads[di] = placements[j];
396                     else {
397                         int k = heads[di];
398                         while (placements[k] != -1 && placements[k] != j)
399                             k = placements[k];
400                         assert(placements[k] == j);
401                         placements[k] = placements[j];
402                     }
403                     placements[j] = -2;
404                 }
405             }
406         }
407
408         /*
409          * For each square, look at the available placements
410          * involving that square. If all of them are for the same
411          * domino, then rule out any placements for that domino
412          * _not_ involving this square.
413          */
414         for (i = 0; i < wh; i++) {
415             int list[4], k, n, adi;
416
417             x = i % w;
418             y = i / w;
419
420             j = 0;
421             if (x > 0)
422                 list[j++] = 2*(i-1)+1;
423             if (x+1 < w)
424                 list[j++] = 2*i+1;
425             if (y > 0)
426                 list[j++] = 2*(i-w);
427             if (y+1 < h)
428                 list[j++] = 2*i;
429
430             for (n = k = 0; k < j; k++)
431                 if (placements[list[k]] >= -1)
432                     list[n++] = list[k];
433
434             adi = -1;
435
436             for (j = 0; j < n; j++) {
437                 int p1, p2, di;
438                 k = list[j];
439
440                 p1 = k / 2;
441                 p2 = (k & 1) ? p1 + 1 : p1 + w;
442                 di = DINDEX(grid[p1], grid[p2]);
443
444                 if (adi == -1)
445                     adi = di;
446                 if (adi != di)
447                     break;
448             }
449
450             if (j == n) {
451                 int nn;
452
453                 assert(adi >= 0);
454                 /*
455                  * We've found something. All viable placements
456                  * involving this square are for domino `adi'. If
457                  * the current placement list for that domino is
458                  * longer than n, reduce it to precisely this
459                  * placement list and we've done something.
460                  */
461                 nn = 0;
462                 for (k = heads[adi]; k >= 0; k = placements[k])
463                     nn++;
464                 if (nn > n) {
465                     done_something = TRUE;
466 #ifdef SOLVER_DIAGNOSTICS
467                     printf("considering square %d,%d: reducing placements "
468                            "of domino %d\n", x, y, adi);
469 #endif
470                     /*
471                      * Set all other placements on the list to
472                      * impossible.
473                      */
474                     k = heads[adi];
475                     while (k >= 0) {
476                         int tmp = placements[k];
477                         placements[k] = -2;
478                         k = tmp;
479                     }
480                     /*
481                      * Set up the new list.
482                      */
483                     heads[adi] = list[0];
484                     for (k = 0; k < n; k++)
485                         placements[list[k]] = (k+1 == n ? -1 : list[k+1]);
486                 }
487             }
488         }
489
490         if (!done_something)
491             break;
492     }
493
494 #ifdef SOLVER_DIAGNOSTICS
495     printf("after solver:\n");
496     for (i = 0; i <= n; i++)
497         for (j = 0; j <= i; j++) {
498             int k, m;
499             m = 0;
500             printf("%2d [%d %d]:", DINDEX(i, j), i, j);
501             for (k = heads[DINDEX(i,j)]; k >= 0; k = placements[k])
502                 printf(" %3d [%d,%d,%c]", k, k/2%w, k/2/w, k%2?'h':'v');
503             printf("\n");
504         }
505 #endif
506
507     ret = 1;
508     for (i = 0; i < wh*2; i++) {
509         if (placements[i] == -2) {
510             if (output)
511                 output[i] = -1;        /* ruled out */
512         } else if (placements[i] != -3) {
513             int p1, p2, di;
514
515             p1 = i / 2;
516             p2 = (i & 1) ? p1 + 1 : p1 + w;
517             di = DINDEX(grid[p1], grid[p2]);
518
519             if (i == heads[di] && placements[i] == -1) {
520                 if (output)
521                     output[i] = 1;     /* certain */
522             } else {
523                 if (output)
524                     output[i] = 0;     /* uncertain */
525                 ret = 2;
526             }
527         }
528     }
529
530     done:
531     /*
532      * Free working data.
533      */
534     sfree(placements);
535     sfree(heads);
536
537     return ret;
538 }
539
540 /* ----------------------------------------------------------------------
541  * End of solver code.
542  */
543
544 static char *new_game_desc(game_params *params, random_state *rs,
545                            char **aux, int interactive)
546 {
547     int n = params->n, w = n+2, h = n+1, wh = w*h;
548     int *grid, *grid2, *list;
549     int i, j, k, m, todo, done, len;
550     char *ret;
551
552     /*
553      * Allocate space in which to lay the grid out.
554      */
555     grid = snewn(wh, int);
556     grid2 = snewn(wh, int);
557     list = snewn(2*wh, int);
558
559     /*
560      * I haven't been able to think of any particularly clever
561      * techniques for generating instances of Dominosa with a
562      * unique solution. Many of the deductions used in this puzzle
563      * are based on information involving half the grid at a time
564      * (`of all the 6s, exactly one is next to a 3'), so a strategy
565      * of partially solving the grid and then perturbing the place
566      * where the solver got stuck seems particularly likely to
567      * accidentally destroy the information which the solver had
568      * used in getting that far. (Contrast with, say, Mines, in
569      * which most deductions are local so this is an excellent
570      * strategy.)
571      *
572      * Therefore I resort to the basest of brute force methods:
573      * generate a random grid, see if it's solvable, throw it away
574      * and try again if not. My only concession to sophistication
575      * and cleverness is to at least _try_ not to generate obvious
576      * 2x2 ambiguous sections (see comment below in the domino-
577      * flipping section).
578      *
579      * During tests performed on 2005-07-15, I found that the brute
580      * force approach without that tweak had to throw away about 87
581      * grids on average (at the default n=6) before finding a
582      * unique one, or a staggering 379 at n=9; good job the
583      * generator and solver are fast! When I added the
584      * ambiguous-section avoidance, those numbers came down to 19
585      * and 26 respectively, which is a lot more sensible.
586      */
587
588     do {
589         /*
590          * To begin with, set grid[i] = i for all i to indicate
591          * that all squares are currently singletons. Later we'll
592          * set grid[i] to be the index of the other end of the
593          * domino on i.
594          */
595         for (i = 0; i < wh; i++)
596             grid[i] = i;
597
598         /*
599          * Now prepare a list of the possible domino locations. There
600          * are w*(h-1) possible vertical locations, and (w-1)*h
601          * horizontal ones, for a total of 2*wh - h - w.
602          *
603          * I'm going to denote the vertical domino placement with
604          * its top in square i as 2*i, and the horizontal one with
605          * its left half in square i as 2*i+1.
606          */
607         k = 0;
608         for (j = 0; j < h-1; j++)
609             for (i = 0; i < w; i++)
610                 list[k++] = 2 * (j*w+i);   /* vertical positions */
611         for (j = 0; j < h; j++)
612             for (i = 0; i < w-1; i++)
613                 list[k++] = 2 * (j*w+i) + 1;   /* horizontal positions */
614         assert(k == 2*wh - h - w);
615
616         /*
617          * Shuffle the list.
618          */
619         shuffle(list, k, sizeof(*list), rs);
620
621         /*
622          * Work down the shuffled list, placing a domino everywhere
623          * we can.
624          */
625         for (i = 0; i < k; i++) {
626             int horiz, xy, xy2;
627
628             horiz = list[i] % 2;
629             xy = list[i] / 2;
630             xy2 = xy + (horiz ? 1 : w);
631
632             if (grid[xy] == xy && grid[xy2] == xy2) {
633                 /*
634                  * We can place this domino. Do so.
635                  */
636                 grid[xy] = xy2;
637                 grid[xy2] = xy;
638             }
639         }
640
641 #ifdef GENERATION_DIAGNOSTICS
642         printf("generated initial layout\n");
643 #endif
644
645         /*
646          * Now we've placed as many dominoes as we can immediately
647          * manage. There will be squares remaining, but they'll be
648          * singletons. So loop round and deal with the singletons
649          * two by two.
650          */
651         while (1) {
652 #ifdef GENERATION_DIAGNOSTICS
653             for (j = 0; j < h; j++) {
654                 for (i = 0; i < w; i++) {
655                     int xy = j*w+i;
656                     int v = grid[xy];
657                     int c = (v == xy+1 ? '[' : v == xy-1 ? ']' :
658                              v == xy+w ? 'n' : v == xy-w ? 'U' : '.');
659                     putchar(c);
660                 }
661                 putchar('\n');
662             }
663             putchar('\n');
664 #endif
665
666             /*
667              * Our strategy is:
668              *
669              * First find a singleton square.
670              *
671              * Then breadth-first search out from the starting
672              * square. From that square (and any others we reach on
673              * the way), examine all four neighbours of the square.
674              * If one is an end of a domino, we move to the _other_
675              * end of that domino before looking at neighbours
676              * again. When we encounter another singleton on this
677              * search, stop.
678              *
679              * This will give us a path of adjacent squares such
680              * that all but the two ends are covered in dominoes.
681              * So we can now shuffle every domino on the path up by
682              * one.
683              *
684              * (Chessboard colours are mathematically important
685              * here: we always end up pairing each singleton with a
686              * singleton of the other colour. However, we never
687              * have to track this manually, since it's
688              * automatically taken care of by the fact that we
689              * always make an even number of orthogonal moves.)
690              */
691             for (i = 0; i < wh; i++)
692                 if (grid[i] == i)
693                     break;
694             if (i == wh)
695                 break;                 /* no more singletons; we're done. */
696
697 #ifdef GENERATION_DIAGNOSTICS
698             printf("starting b.f.s. at singleton %d\n", i);
699 #endif
700             /*
701              * Set grid2 to -1 everywhere. It will hold our
702              * distance-from-start values, and also our
703              * backtracking data, during the b.f.s.
704              */
705             for (j = 0; j < wh; j++)
706                 grid2[j] = -1;
707             grid2[i] = 0;              /* starting square has distance zero */
708
709             /*
710              * Start our to-do list of squares. It'll live in
711              * `list'; since the b.f.s can cover every square at
712              * most once there is no need for it to be circular.
713              * We'll just have two counters tracking the end of the
714              * list and the squares we've already dealt with.
715              */
716             done = 0;
717             todo = 1;
718             list[0] = i;
719
720             /*
721              * Now begin the b.f.s. loop.
722              */
723             while (done < todo) {
724                 int d[4], nd, x, y;
725
726                 i = list[done++];
727
728 #ifdef GENERATION_DIAGNOSTICS
729                 printf("b.f.s. iteration from %d\n", i);
730 #endif
731                 x = i % w;
732                 y = i / w;
733                 nd = 0;
734                 if (x > 0)
735                     d[nd++] = i - 1;
736                 if (x+1 < w)
737                     d[nd++] = i + 1;
738                 if (y > 0)
739                     d[nd++] = i - w;
740                 if (y+1 < h)
741                     d[nd++] = i + w;
742                 /*
743                  * To avoid directional bias, process the
744                  * neighbours of this square in a random order.
745                  */
746                 shuffle(d, nd, sizeof(*d), rs);
747
748                 for (j = 0; j < nd; j++) {
749                     k = d[j];
750                     if (grid[k] == k) {
751 #ifdef GENERATION_DIAGNOSTICS
752                         printf("found neighbouring singleton %d\n", k);
753 #endif
754                         grid2[k] = i;
755                         break;         /* found a target singleton! */
756                     }
757
758                     /*
759                      * We're moving through a domino here, so we
760                      * have two entries in grid2 to fill with
761                      * useful data. In grid[k] - the square
762                      * adjacent to where we came from - I'm going
763                      * to put the address _of_ the square we came
764                      * from. In the other end of the domino - the
765                      * square from which we will continue the
766                      * search - I'm going to put the distance.
767                      */
768                     m = grid[k];
769
770                     if (grid2[m] < 0 || grid2[m] > grid2[i]+1) {
771 #ifdef GENERATION_DIAGNOSTICS
772                         printf("found neighbouring domino %d/%d\n", k, m);
773 #endif
774                         grid2[m] = grid2[i]+1;
775                         grid2[k] = i;
776                         /*
777                          * And since we've now visited a new
778                          * domino, add m to the to-do list.
779                          */
780                         assert(todo < wh);
781                         list[todo++] = m;
782                     }
783                 }
784
785                 if (j < nd) {
786                     i = k;
787 #ifdef GENERATION_DIAGNOSTICS
788                     printf("terminating b.f.s. loop, i = %d\n", i);
789 #endif
790                     break;
791                 }
792
793                 i = -1;                /* just in case the loop terminates */
794             }
795
796             /*
797              * We expect this b.f.s. to have found us a target
798              * square.
799              */
800             assert(i >= 0);
801
802             /*
803              * Now we can follow the trail back to our starting
804              * singleton, re-laying dominoes as we go.
805              */
806             while (1) {
807                 j = grid2[i];
808                 assert(j >= 0 && j < wh);
809                 k = grid[j];
810
811                 grid[i] = j;
812                 grid[j] = i;
813 #ifdef GENERATION_DIAGNOSTICS
814                 printf("filling in domino %d/%d (next %d)\n", i, j, k);
815 #endif
816                 if (j == k)
817                     break;             /* we've reached the other singleton */
818                 i = k;
819             }
820 #ifdef GENERATION_DIAGNOSTICS
821             printf("fixup path completed\n");
822 #endif
823         }
824
825         /*
826          * Now we have a complete layout covering the whole
827          * rectangle with dominoes. So shuffle the actual domino
828          * values and fill the rectangle with numbers.
829          */
830         k = 0;
831         for (i = 0; i <= params->n; i++)
832             for (j = 0; j <= i; j++) {
833                 list[k++] = i;
834                 list[k++] = j;
835             }
836         shuffle(list, k/2, 2*sizeof(*list), rs);
837         j = 0;
838         for (i = 0; i < wh; i++)
839             if (grid[i] > i) {
840                 /* Optionally flip the domino round. */
841                 int flip = -1;
842
843                 if (params->unique) {
844                     int t1, t2;
845                     /*
846                      * If we're after a unique solution, we can do
847                      * something here to improve the chances. If
848                      * we're placing a domino so that it forms a
849                      * 2x2 rectangle with one we've already placed,
850                      * and if that domino and this one share a
851                      * number, we can try not to put them so that
852                      * the identical numbers are diagonally
853                      * separated, because that automatically causes
854                      * non-uniqueness:
855                      * 
856                      * +---+      +-+-+
857                      * |2 3|      |2|3|
858                      * +---+  ->  | | |
859                      * |4 2|      |4|2|
860                      * +---+      +-+-+
861                      */
862                     t1 = i;
863                     t2 = grid[i];
864                     if (t2 == t1 + w) {  /* this domino is vertical */
865                         if (t1 % w > 0 &&/* and not on the left hand edge */
866                             grid[t1-1] == t2-1 &&/* alongside one to left */
867                             (grid2[t1-1] == list[j] ||   /* and has a number */
868                              grid2[t1-1] == list[j+1] ||   /* in common */
869                              grid2[t2-1] == list[j] ||
870                              grid2[t2-1] == list[j+1])) {
871                             if (grid2[t1-1] == list[j] ||
872                                 grid2[t2-1] == list[j+1])
873                                 flip = 0;
874                             else
875                                 flip = 1;
876                         }
877                     } else {           /* this domino is horizontal */
878                         if (t1 / w > 0 &&/* and not on the top edge */
879                             grid[t1-w] == t2-w &&/* alongside one above */
880                             (grid2[t1-w] == list[j] ||   /* and has a number */
881                              grid2[t1-w] == list[j+1] ||   /* in common */
882                              grid2[t2-w] == list[j] ||
883                              grid2[t2-w] == list[j+1])) {
884                             if (grid2[t1-w] == list[j] ||
885                                 grid2[t2-w] == list[j+1])
886                                 flip = 0;
887                             else
888                                 flip = 1;
889                         }
890                     }
891                 }
892
893                 if (flip < 0)
894                     flip = random_upto(rs, 2);
895
896                 grid2[i] = list[j + flip];
897                 grid2[grid[i]] = list[j + 1 - flip];
898                 j += 2;
899             }
900         assert(j == k);
901     } while (params->unique && solver(w, h, n, grid2, NULL) > 1);
902
903 #ifdef GENERATION_DIAGNOSTICS
904     for (j = 0; j < h; j++) {
905         for (i = 0; i < w; i++) {
906             putchar('0' + grid2[j*w+i]);
907         }
908         putchar('\n');
909     }
910     putchar('\n');
911 #endif
912
913     /*
914      * Encode the resulting game state.
915      * 
916      * Our encoding is a string of digits. Any number greater than
917      * 9 is represented by a decimal integer within square
918      * brackets. We know there are n+2 of every number (it's paired
919      * with each number from 0 to n inclusive, and one of those is
920      * itself so that adds another occurrence), so we can work out
921      * the string length in advance.
922      */
923
924     /*
925      * To work out the total length of the decimal encodings of all
926      * the numbers from 0 to n inclusive:
927      *  - every number has a units digit; total is n+1.
928      *  - all numbers above 9 have a tens digit; total is max(n+1-10,0).
929      *  - all numbers above 99 have a hundreds digit; total is max(n+1-100,0).
930      *  - and so on.
931      */
932     len = n+1;
933     for (i = 10; i <= n; i *= 10)
934         len += max(n + 1 - i, 0);
935     /* Now add two square brackets for each number above 9. */
936     len += 2 * max(n + 1 - 10, 0);
937     /* And multiply by n+2 for the repeated occurrences of each number. */
938     len *= n+2;
939
940     /*
941      * Now actually encode the string.
942      */
943     ret = snewn(len+1, char);
944     j = 0;
945     for (i = 0; i < wh; i++) {
946         k = grid2[i];
947         if (k < 10)
948             ret[j++] = '0' + k;
949         else
950             j += sprintf(ret+j, "[%d]", k);
951         assert(j <= len);
952     }
953     assert(j == len);
954     ret[j] = '\0';
955
956     /*
957      * Encode the solved state as an aux_info.
958      */
959     {
960         char *auxinfo = snewn(wh+1, char);
961
962         for (i = 0; i < wh; i++) {
963             int v = grid[i];
964             auxinfo[i] = (v == i+1 ? 'L' : v == i-1 ? 'R' :
965                           v == i+w ? 'T' : v == i-w ? 'B' : '.');
966         }
967         auxinfo[wh] = '\0';
968
969         *aux = auxinfo;
970     }
971
972     sfree(list);
973     sfree(grid2);
974     sfree(grid);
975
976     return ret;
977 }
978
979 static char *validate_desc(game_params *params, char *desc)
980 {
981     int n = params->n, w = n+2, h = n+1, wh = w*h;
982     int *occurrences;
983     int i, j;
984     char *ret;
985
986     ret = NULL;
987     occurrences = snewn(n+1, int);
988     for (i = 0; i <= n; i++)
989         occurrences[i] = 0;
990
991     for (i = 0; i < wh; i++) {
992         if (!*desc) {
993             ret = ret ? ret : "Game description is too short";
994         } else {
995             if (*desc >= '0' && *desc <= '9')
996                 j = *desc++ - '0';
997             else if (*desc == '[') {
998                 desc++;
999                 j = atoi(desc);
1000                 while (*desc && isdigit((unsigned char)*desc)) desc++;
1001                 if (*desc != ']')
1002                     ret = ret ? ret : "Missing ']' in game description";
1003                 else
1004                     desc++;
1005             } else {
1006                 j = -1;
1007                 ret = ret ? ret : "Invalid syntax in game description";
1008             }
1009             if (j < 0 || j > n)
1010                 ret = ret ? ret : "Number out of range in game description";
1011             else
1012                 occurrences[j]++;
1013         }
1014     }
1015
1016     if (*desc)
1017         ret = ret ? ret : "Game description is too long";
1018
1019     if (!ret) {
1020         for (i = 0; i <= n; i++)
1021             if (occurrences[i] != n+2)
1022                 ret = "Incorrect number balance in game description";
1023     }
1024
1025     sfree(occurrences);
1026
1027     return ret;
1028 }
1029
1030 static game_state *new_game(midend *me, game_params *params, char *desc)
1031 {
1032     int n = params->n, w = n+2, h = n+1, wh = w*h;
1033     game_state *state = snew(game_state);
1034     int i, j;
1035
1036     state->params = *params;
1037     state->w = w;
1038     state->h = h;
1039
1040     state->grid = snewn(wh, int);
1041     for (i = 0; i < wh; i++)
1042         state->grid[i] = i;
1043
1044     state->edges = snewn(wh, unsigned short);
1045     for (i = 0; i < wh; i++)
1046         state->edges[i] = 0;
1047
1048     state->numbers = snew(struct game_numbers);
1049     state->numbers->refcount = 1;
1050     state->numbers->numbers = snewn(wh, int);
1051
1052     for (i = 0; i < wh; i++) {
1053         assert(*desc);
1054         if (*desc >= '0' && *desc <= '9')
1055             j = *desc++ - '0';
1056         else {
1057             assert(*desc == '[');
1058             desc++;
1059             j = atoi(desc);
1060             while (*desc && isdigit((unsigned char)*desc)) desc++;
1061             assert(*desc == ']');
1062             desc++;
1063         }
1064         assert(j >= 0 && j <= n);
1065         state->numbers->numbers[i] = j;
1066     }
1067
1068     state->completed = state->cheated = FALSE;
1069
1070     return state;
1071 }
1072
1073 static game_state *dup_game(game_state *state)
1074 {
1075     int n = state->params.n, w = n+2, h = n+1, wh = w*h;
1076     game_state *ret = snew(game_state);
1077
1078     ret->params = state->params;
1079     ret->w = state->w;
1080     ret->h = state->h;
1081     ret->grid = snewn(wh, int);
1082     memcpy(ret->grid, state->grid, wh * sizeof(int));
1083     ret->edges = snewn(wh, unsigned short);
1084     memcpy(ret->edges, state->edges, wh * sizeof(unsigned short));
1085     ret->numbers = state->numbers;
1086     ret->numbers->refcount++;
1087     ret->completed = state->completed;
1088     ret->cheated = state->cheated;
1089
1090     return ret;
1091 }
1092
1093 static void free_game(game_state *state)
1094 {
1095     sfree(state->grid);
1096     sfree(state->edges);
1097     if (--state->numbers->refcount <= 0) {
1098         sfree(state->numbers->numbers);
1099         sfree(state->numbers);
1100     }
1101     sfree(state);
1102 }
1103
1104 static char *solve_game(game_state *state, game_state *currstate,
1105                         char *aux, char **error)
1106 {
1107     int n = state->params.n, w = n+2, h = n+1, wh = w*h;
1108     int *placements;
1109     char *ret;
1110     int retlen, retsize;
1111     int i, v;
1112     char buf[80];
1113     int extra;
1114
1115     if (aux) {
1116         retsize = 256;
1117         ret = snewn(retsize, char);
1118         retlen = sprintf(ret, "S");
1119
1120         for (i = 0; i < wh; i++) {
1121             if (aux[i] == 'L')
1122                 extra = sprintf(buf, ";D%d,%d", i, i+1);
1123             else if (aux[i] == 'T')
1124                 extra = sprintf(buf, ";D%d,%d", i, i+w);
1125             else
1126                 continue;
1127
1128             if (retlen + extra + 1 >= retsize) {
1129                 retsize = retlen + extra + 256;
1130                 ret = sresize(ret, retsize, char);
1131             }
1132             strcpy(ret + retlen, buf);
1133             retlen += extra;
1134         }
1135
1136     } else {
1137
1138         placements = snewn(wh*2, int);
1139         for (i = 0; i < wh*2; i++)
1140             placements[i] = -3;
1141         solver(w, h, n, state->numbers->numbers, placements);
1142
1143         /*
1144          * First make a pass putting in edges for -1, then make a pass
1145          * putting in dominoes for +1.
1146          */
1147         retsize = 256;
1148         ret = snewn(retsize, char);
1149         retlen = sprintf(ret, "S");
1150
1151         for (v = -1; v <= +1; v += 2)
1152             for (i = 0; i < wh*2; i++)
1153                 if (placements[i] == v) {
1154                     int p1 = i / 2;
1155                     int p2 = (i & 1) ? p1+1 : p1+w;
1156
1157                     extra = sprintf(buf, ";%c%d,%d",
1158                                     (int)(v==-1 ? 'E' : 'D'), p1, p2);
1159
1160                     if (retlen + extra + 1 >= retsize) {
1161                         retsize = retlen + extra + 256;
1162                         ret = sresize(ret, retsize, char);
1163                     }
1164                     strcpy(ret + retlen, buf);
1165                     retlen += extra;
1166                 }
1167
1168         sfree(placements);
1169     }
1170
1171     return ret;
1172 }
1173
1174 static int game_can_format_as_text_now(game_params *params)
1175 {
1176     return TRUE;
1177 }
1178
1179 static char *game_text_format(game_state *state)
1180 {
1181     return NULL;
1182 }
1183
1184 static game_ui *new_ui(game_state *state)
1185 {
1186     return NULL;
1187 }
1188
1189 static void free_ui(game_ui *ui)
1190 {
1191 }
1192
1193 static char *encode_ui(game_ui *ui)
1194 {
1195     return NULL;
1196 }
1197
1198 static void decode_ui(game_ui *ui, char *encoding)
1199 {
1200 }
1201
1202 static void game_changed_state(game_ui *ui, game_state *oldstate,
1203                                game_state *newstate)
1204 {
1205 }
1206
1207 #define PREFERRED_TILESIZE 32
1208 #define TILESIZE (ds->tilesize)
1209 #define BORDER (TILESIZE * 3 / 4)
1210 #define DOMINO_GUTTER (TILESIZE / 16)
1211 #define DOMINO_RADIUS (TILESIZE / 8)
1212 #define DOMINO_COFFSET (DOMINO_GUTTER + DOMINO_RADIUS)
1213
1214 #define COORD(x) ( (x) * TILESIZE + BORDER )
1215 #define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 )
1216
1217 struct game_drawstate {
1218     int started;
1219     int w, h, tilesize;
1220     unsigned long *visible;
1221 };
1222
1223 static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
1224                             int x, int y, int button)
1225 {
1226     int w = state->w, h = state->h;
1227     char buf[80];
1228
1229     /*
1230      * A left-click between two numbers toggles a domino covering
1231      * them. A right-click toggles an edge.
1232      */
1233     if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
1234         int tx = FROMCOORD(x), ty = FROMCOORD(y), t = ty*w+tx;
1235         int dx, dy;
1236         int d1, d2;
1237
1238         if (tx < 0 || tx >= w || ty < 0 || ty >= h)
1239             return NULL;
1240
1241         /*
1242          * Now we know which square the click was in, decide which
1243          * edge of the square it was closest to.
1244          */
1245         dx = 2 * (x - COORD(tx)) - TILESIZE;
1246         dy = 2 * (y - COORD(ty)) - TILESIZE;
1247
1248         if (abs(dx) > abs(dy) && dx < 0 && tx > 0)
1249             d1 = t - 1, d2 = t;        /* clicked in right side of domino */
1250         else if (abs(dx) > abs(dy) && dx > 0 && tx+1 < w)
1251             d1 = t, d2 = t + 1;        /* clicked in left side of domino */
1252         else if (abs(dy) > abs(dx) && dy < 0 && ty > 0)
1253             d1 = t - w, d2 = t;        /* clicked in bottom half of domino */
1254         else if (abs(dy) > abs(dx) && dy > 0 && ty+1 < h)
1255             d1 = t, d2 = t + w;        /* clicked in top half of domino */
1256         else
1257             return NULL;
1258
1259         /*
1260          * We can't mark an edge next to any domino.
1261          */
1262         if (button == RIGHT_BUTTON &&
1263             (state->grid[d1] != d1 || state->grid[d2] != d2))
1264             return NULL;
1265
1266         sprintf(buf, "%c%d,%d", (int)(button == RIGHT_BUTTON ? 'E' : 'D'), d1, d2);
1267         return dupstr(buf);
1268     }
1269
1270     return NULL;
1271 }
1272
1273 static game_state *execute_move(game_state *state, char *move)
1274 {
1275     int n = state->params.n, w = n+2, h = n+1, wh = w*h;
1276     int d1, d2, d3, p;
1277     game_state *ret = dup_game(state);
1278
1279     while (*move) {
1280         if (move[0] == 'S') {
1281             int i;
1282
1283             ret->cheated = TRUE;
1284
1285             /*
1286              * Clear the existing edges and domino placements. We
1287              * expect the S to be followed by other commands.
1288              */
1289             for (i = 0; i < wh; i++) {
1290                 ret->grid[i] = i;
1291                 ret->edges[i] = 0;
1292             }
1293             move++;
1294         } else if (move[0] == 'D' &&
1295                    sscanf(move+1, "%d,%d%n", &d1, &d2, &p) == 2 &&
1296                    d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2) {
1297
1298             /*
1299              * Toggle domino presence between d1 and d2.
1300              */
1301             if (ret->grid[d1] == d2) {
1302                 assert(ret->grid[d2] == d1);
1303                 ret->grid[d1] = d1;
1304                 ret->grid[d2] = d2;
1305             } else {
1306                 /*
1307                  * Erase any dominoes that might overlap the new one.
1308                  */
1309                 d3 = ret->grid[d1];
1310                 if (d3 != d1)
1311                     ret->grid[d3] = d3;
1312                 d3 = ret->grid[d2];
1313                 if (d3 != d2)
1314                     ret->grid[d3] = d3;
1315                 /*
1316                  * Place the new one.
1317                  */
1318                 ret->grid[d1] = d2;
1319                 ret->grid[d2] = d1;
1320
1321                 /*
1322                  * Destroy any edges lurking around it.
1323                  */
1324                 if (ret->edges[d1] & EDGE_L) {
1325                     assert(d1 - 1 >= 0);
1326                     ret->edges[d1 - 1] &= ~EDGE_R;
1327                 }
1328                 if (ret->edges[d1] & EDGE_R) {
1329                     assert(d1 + 1 < wh);
1330                     ret->edges[d1 + 1] &= ~EDGE_L;
1331                 }
1332                 if (ret->edges[d1] & EDGE_T) {
1333                     assert(d1 - w >= 0);
1334                     ret->edges[d1 - w] &= ~EDGE_B;
1335                 }
1336                 if (ret->edges[d1] & EDGE_B) {
1337                     assert(d1 + 1 < wh);
1338                     ret->edges[d1 + w] &= ~EDGE_T;
1339                 }
1340                 ret->edges[d1] = 0;
1341                 if (ret->edges[d2] & EDGE_L) {
1342                     assert(d2 - 1 >= 0);
1343                     ret->edges[d2 - 1] &= ~EDGE_R;
1344                 }
1345                 if (ret->edges[d2] & EDGE_R) {
1346                     assert(d2 + 1 < wh);
1347                     ret->edges[d2 + 1] &= ~EDGE_L;
1348                 }
1349                 if (ret->edges[d2] & EDGE_T) {
1350                     assert(d2 - w >= 0);
1351                     ret->edges[d2 - w] &= ~EDGE_B;
1352                 }
1353                 if (ret->edges[d2] & EDGE_B) {
1354                     assert(d2 + 1 < wh);
1355                     ret->edges[d2 + w] &= ~EDGE_T;
1356                 }
1357                 ret->edges[d2] = 0;
1358             }
1359
1360             move += p+1;
1361         } else if (move[0] == 'E' &&
1362                    sscanf(move+1, "%d,%d%n", &d1, &d2, &p) == 2 &&
1363                    d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2 &&
1364                    ret->grid[d1] == d1 && ret->grid[d2] == d2) {
1365
1366             /*
1367              * Toggle edge presence between d1 and d2.
1368              */
1369             if (d2 == d1 + 1) {
1370                 ret->edges[d1] ^= EDGE_R;
1371                 ret->edges[d2] ^= EDGE_L;
1372             } else {
1373                 ret->edges[d1] ^= EDGE_B;
1374                 ret->edges[d2] ^= EDGE_T;
1375             }
1376
1377             move += p+1;
1378         } else {
1379             free_game(ret);
1380             return NULL;
1381         }
1382
1383         if (*move) {
1384             if (*move != ';') {
1385                 free_game(ret);
1386                 return NULL;
1387             }
1388             move++;
1389         }
1390     }
1391
1392     /*
1393      * After modifying the grid, check completion.
1394      */
1395     if (!ret->completed) {
1396         int i, ok = 0;
1397         unsigned char *used = snewn(TRI(n+1), unsigned char);
1398
1399         memset(used, 0, TRI(n+1));
1400         for (i = 0; i < wh; i++)
1401             if (ret->grid[i] > i) {
1402                 int n1, n2, di;
1403
1404                 n1 = ret->numbers->numbers[i];
1405                 n2 = ret->numbers->numbers[ret->grid[i]];
1406
1407                 di = DINDEX(n1, n2);
1408                 assert(di >= 0 && di < TRI(n+1));
1409
1410                 if (!used[di]) {
1411                     used[di] = 1;
1412                     ok++;
1413                 }
1414             }
1415
1416         sfree(used);
1417         if (ok == DCOUNT(n))
1418             ret->completed = TRUE;
1419     }
1420
1421     return ret;
1422 }
1423
1424 /* ----------------------------------------------------------------------
1425  * Drawing routines.
1426  */
1427
1428 static void game_compute_size(game_params *params, int tilesize,
1429                               int *x, int *y)
1430 {
1431     int n = params->n, w = n+2, h = n+1;
1432
1433     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1434     struct { int tilesize; } ads, *ds = &ads;
1435     ads.tilesize = tilesize;
1436
1437     *x = w * TILESIZE + 2*BORDER;
1438     *y = h * TILESIZE + 2*BORDER;
1439 }
1440
1441 static void game_set_size(drawing *dr, game_drawstate *ds,
1442                           game_params *params, int tilesize)
1443 {
1444     ds->tilesize = tilesize;
1445 }
1446
1447 static float *game_colours(frontend *fe, int *ncolours)
1448 {
1449     float *ret = snewn(3 * NCOLOURS, float);
1450
1451     frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
1452
1453     ret[COL_TEXT * 3 + 0] = 0.0F;
1454     ret[COL_TEXT * 3 + 1] = 0.0F;
1455     ret[COL_TEXT * 3 + 2] = 0.0F;
1456
1457     ret[COL_DOMINO * 3 + 0] = 0.0F;
1458     ret[COL_DOMINO * 3 + 1] = 0.0F;
1459     ret[COL_DOMINO * 3 + 2] = 0.0F;
1460
1461     ret[COL_DOMINOCLASH * 3 + 0] = 0.5F;
1462     ret[COL_DOMINOCLASH * 3 + 1] = 0.0F;
1463     ret[COL_DOMINOCLASH * 3 + 2] = 0.0F;
1464
1465     ret[COL_DOMINOTEXT * 3 + 0] = 1.0F;
1466     ret[COL_DOMINOTEXT * 3 + 1] = 1.0F;
1467     ret[COL_DOMINOTEXT * 3 + 2] = 1.0F;
1468
1469     ret[COL_EDGE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2 / 3; 
1470     ret[COL_EDGE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2 / 3;
1471     ret[COL_EDGE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2 / 3;
1472
1473     *ncolours = NCOLOURS;
1474     return ret;
1475 }
1476
1477 static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
1478 {
1479     struct game_drawstate *ds = snew(struct game_drawstate);
1480     int i;
1481
1482     ds->started = FALSE;
1483     ds->w = state->w;
1484     ds->h = state->h;
1485     ds->visible = snewn(ds->w * ds->h, unsigned long);
1486     ds->tilesize = 0;                  /* not decided yet */
1487     for (i = 0; i < ds->w * ds->h; i++)
1488         ds->visible[i] = 0xFFFF;
1489
1490     return ds;
1491 }
1492
1493 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1494 {
1495     sfree(ds->visible);
1496     sfree(ds);
1497 }
1498
1499 enum {
1500     TYPE_L,
1501     TYPE_R,
1502     TYPE_T,
1503     TYPE_B,
1504     TYPE_BLANK,
1505     TYPE_MASK = 0x0F
1506 };
1507
1508 static void draw_tile(drawing *dr, game_drawstate *ds, game_state *state,
1509                       int x, int y, int type)
1510 {
1511     int w = state->w /*, h = state->h */;
1512     int cx = COORD(x), cy = COORD(y);
1513     int nc;
1514     char str[80];
1515     int flags;
1516
1517     draw_rect(dr, cx, cy, TILESIZE, TILESIZE, COL_BACKGROUND);
1518
1519     flags = type &~ TYPE_MASK;
1520     type &= TYPE_MASK;
1521
1522     if (type != TYPE_BLANK) {
1523         int i, bg;
1524
1525         /*
1526          * Draw one end of a domino. This is composed of:
1527          * 
1528          *  - two filled circles (rounded corners)
1529          *  - two rectangles
1530          *  - a slight shift in the number
1531          */
1532
1533         if (flags & 0x80)
1534             bg = COL_DOMINOCLASH;
1535         else
1536             bg = COL_DOMINO;
1537         nc = COL_DOMINOTEXT;
1538
1539         if (flags & 0x40) {
1540             int tmp = nc;
1541             nc = bg;
1542             bg = tmp;
1543         }
1544
1545         if (type == TYPE_L || type == TYPE_T)
1546             draw_circle(dr, cx+DOMINO_COFFSET, cy+DOMINO_COFFSET,
1547                         DOMINO_RADIUS, bg, bg);
1548         if (type == TYPE_R || type == TYPE_T)
1549             draw_circle(dr, cx+TILESIZE-1-DOMINO_COFFSET, cy+DOMINO_COFFSET,
1550                         DOMINO_RADIUS, bg, bg);
1551         if (type == TYPE_L || type == TYPE_B)
1552             draw_circle(dr, cx+DOMINO_COFFSET, cy+TILESIZE-1-DOMINO_COFFSET,
1553                         DOMINO_RADIUS, bg, bg);
1554         if (type == TYPE_R || type == TYPE_B)
1555             draw_circle(dr, cx+TILESIZE-1-DOMINO_COFFSET,
1556                         cy+TILESIZE-1-DOMINO_COFFSET,
1557                         DOMINO_RADIUS, bg, bg);
1558
1559         for (i = 0; i < 2; i++) {
1560             int x1, y1, x2, y2;
1561
1562             x1 = cx + (i ? DOMINO_GUTTER : DOMINO_COFFSET);
1563             y1 = cy + (i ? DOMINO_COFFSET : DOMINO_GUTTER);
1564             x2 = cx + TILESIZE-1 - (i ? DOMINO_GUTTER : DOMINO_COFFSET);
1565             y2 = cy + TILESIZE-1 - (i ? DOMINO_COFFSET : DOMINO_GUTTER);
1566             if (type == TYPE_L)
1567                 x2 = cx + TILESIZE + TILESIZE/16;
1568             else if (type == TYPE_R)
1569                 x1 = cx - TILESIZE/16;
1570             else if (type == TYPE_T)
1571                 y2 = cy + TILESIZE + TILESIZE/16;
1572             else if (type == TYPE_B)
1573                 y1 = cy - TILESIZE/16;
1574
1575             draw_rect(dr, x1, y1, x2-x1+1, y2-y1+1, bg);
1576         }
1577     } else {
1578         if (flags & EDGE_T)
1579             draw_rect(dr, cx+DOMINO_GUTTER, cy,
1580                       TILESIZE-2*DOMINO_GUTTER, 1, COL_EDGE);
1581         if (flags & EDGE_B)
1582             draw_rect(dr, cx+DOMINO_GUTTER, cy+TILESIZE-1,
1583                       TILESIZE-2*DOMINO_GUTTER, 1, COL_EDGE);
1584         if (flags & EDGE_L)
1585             draw_rect(dr, cx, cy+DOMINO_GUTTER,
1586                       1, TILESIZE-2*DOMINO_GUTTER, COL_EDGE);
1587         if (flags & EDGE_R)
1588             draw_rect(dr, cx+TILESIZE-1, cy+DOMINO_GUTTER,
1589                       1, TILESIZE-2*DOMINO_GUTTER, COL_EDGE);
1590         nc = COL_TEXT;
1591     }
1592
1593     sprintf(str, "%d", state->numbers->numbers[y*w+x]);
1594     draw_text(dr, cx+TILESIZE/2, cy+TILESIZE/2, FONT_VARIABLE, TILESIZE/2,
1595               ALIGN_HCENTRE | ALIGN_VCENTRE, nc, str);
1596
1597     draw_update(dr, cx, cy, TILESIZE, TILESIZE);
1598 }
1599
1600 static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
1601                  game_state *state, int dir, game_ui *ui,
1602                  float animtime, float flashtime)
1603 {
1604     int n = state->params.n, w = state->w, h = state->h, wh = w*h;
1605     int x, y, i;
1606     unsigned char *used;
1607
1608     if (!ds->started) {
1609         int pw, ph;
1610         game_compute_size(&state->params, TILESIZE, &pw, &ph);
1611         draw_rect(dr, 0, 0, pw, ph, COL_BACKGROUND);
1612         draw_update(dr, 0, 0, pw, ph);
1613         ds->started = TRUE;
1614     }
1615
1616     /*
1617      * See how many dominoes of each type there are, so we can
1618      * highlight clashes in red.
1619      */
1620     used = snewn(TRI(n+1), unsigned char);
1621     memset(used, 0, TRI(n+1));
1622     for (i = 0; i < wh; i++)
1623         if (state->grid[i] > i) {
1624             int n1, n2, di;
1625
1626             n1 = state->numbers->numbers[i];
1627             n2 = state->numbers->numbers[state->grid[i]];
1628
1629             di = DINDEX(n1, n2);
1630             assert(di >= 0 && di < TRI(n+1));
1631
1632             if (used[di] < 2)
1633                 used[di]++;
1634         }
1635
1636     for (y = 0; y < h; y++)
1637         for (x = 0; x < w; x++) {
1638             int n = y*w+x;
1639             int n1, n2, di;
1640             unsigned long c;
1641
1642             if (state->grid[n] == n-1)
1643                 c = TYPE_R;
1644             else if (state->grid[n] == n+1)
1645                 c = TYPE_L;
1646             else if (state->grid[n] == n-w)
1647                 c = TYPE_B;
1648             else if (state->grid[n] == n+w)
1649                 c = TYPE_T;
1650             else
1651                 c = TYPE_BLANK;
1652
1653             if (c != TYPE_BLANK) {
1654                 n1 = state->numbers->numbers[n];
1655                 n2 = state->numbers->numbers[state->grid[n]];
1656                 di = DINDEX(n1, n2);
1657                 if (used[di] > 1)
1658                     c |= 0x80;         /* highlight a clash */
1659             } else {
1660                 c |= state->edges[n];
1661             }
1662
1663             if (flashtime != 0)
1664                 c |= 0x40;             /* we're flashing */
1665
1666             if (ds->visible[n] != c) {
1667                 draw_tile(dr, ds, state, x, y, c);
1668                 ds->visible[n] = c;
1669             }
1670         }
1671
1672     sfree(used);
1673 }
1674
1675 static float game_anim_length(game_state *oldstate, game_state *newstate,
1676                               int dir, game_ui *ui)
1677 {
1678     return 0.0F;
1679 }
1680
1681 static float game_flash_length(game_state *oldstate, game_state *newstate,
1682                                int dir, game_ui *ui)
1683 {
1684     if (!oldstate->completed && newstate->completed &&
1685         !oldstate->cheated && !newstate->cheated)
1686         return FLASH_TIME;
1687     return 0.0F;
1688 }
1689
1690 static int game_timing_state(game_state *state, game_ui *ui)
1691 {
1692     return TRUE;
1693 }
1694
1695 static void game_print_size(game_params *params, float *x, float *y)
1696 {
1697     int pw, ph;
1698
1699     /*
1700      * I'll use 6mm squares by default.
1701      */
1702     game_compute_size(params, 600, &pw, &ph);
1703     *x = pw / 100.0;
1704     *y = ph / 100.0;
1705 }
1706
1707 static void game_print(drawing *dr, game_state *state, int tilesize)
1708 {
1709     int w = state->w, h = state->h;
1710     int c, x, y;
1711
1712     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1713     game_drawstate ads, *ds = &ads;
1714     game_set_size(dr, ds, NULL, tilesize);
1715
1716     c = print_mono_colour(dr, 1); assert(c == COL_BACKGROUND);
1717     c = print_mono_colour(dr, 0); assert(c == COL_TEXT);
1718     c = print_mono_colour(dr, 0); assert(c == COL_DOMINO);
1719     c = print_mono_colour(dr, 0); assert(c == COL_DOMINOCLASH);
1720     c = print_mono_colour(dr, 1); assert(c == COL_DOMINOTEXT);
1721     c = print_mono_colour(dr, 0); assert(c == COL_EDGE);
1722
1723     for (y = 0; y < h; y++)
1724         for (x = 0; x < w; x++) {
1725             int n = y*w+x;
1726             unsigned long c;
1727
1728             if (state->grid[n] == n-1)
1729                 c = TYPE_R;
1730             else if (state->grid[n] == n+1)
1731                 c = TYPE_L;
1732             else if (state->grid[n] == n-w)
1733                 c = TYPE_B;
1734             else if (state->grid[n] == n+w)
1735                 c = TYPE_T;
1736             else
1737                 c = TYPE_BLANK;
1738
1739             draw_tile(dr, ds, state, x, y, c);
1740         }
1741 }
1742
1743 #ifdef COMBINED
1744 #define thegame dominosa
1745 #endif
1746
1747 const struct game thegame = {
1748     "Dominosa", "games.dominosa", "dominosa",
1749     default_params,
1750     game_fetch_preset,
1751     decode_params,
1752     encode_params,
1753     free_params,
1754     dup_params,
1755     TRUE, game_configure, custom_params,
1756     validate_params,
1757     new_game_desc,
1758     validate_desc,
1759     new_game,
1760     dup_game,
1761     free_game,
1762     TRUE, solve_game,
1763     FALSE, game_can_format_as_text_now, game_text_format,
1764     new_ui,
1765     free_ui,
1766     encode_ui,
1767     decode_ui,
1768     game_changed_state,
1769     interpret_move,
1770     execute_move,
1771     PREFERRED_TILESIZE, game_compute_size, game_set_size,
1772     game_colours,
1773     game_new_drawstate,
1774     game_free_drawstate,
1775     game_redraw,
1776     game_anim_length,
1777     game_flash_length,
1778     TRUE, FALSE, game_print_size, game_print,
1779     FALSE,                             /* wants_statusbar */
1780     FALSE, game_timing_state,
1781     0,                                 /* flags */
1782 };