chiark / gitweb /
Remove dependencies on Subversion.
[sgt-puzzles.git] / galaxies.c
1 /*
2  * galaxies.c: implementation of 'Tentai Show' from Nikoli,
3  *             also sometimes called 'Spiral Galaxies'.
4  *
5  * Notes:
6  *
7  * Grid is stored as size (2n-1), holding edges as well as spaces
8  * (and thus vertices too, at edge intersections).
9  *
10  * Any dot will thus be positioned at one of our grid points,
11  * which saves any faffing with half-of-a-square stuff.
12  *
13  * Edges have on/off state; obviously the actual edges of the
14  * board are fixed to on, and everything else starts as off.
15  *
16  * TTD:
17    * Cleverer solver
18    * Think about how to display remote groups of tiles?
19  *
20  * Bugs:
21  *
22  * Notable puzzle IDs:
23  *
24  * Nikoli's example [web site has wrong highlighting]
25  * (at http://www.nikoli.co.jp/en/puzzles/astronomical_show/):
26  *  5x5:eBbbMlaBbOEnf
27  *
28  * The 'spiral galaxies puzzles are NP-complete' paper
29  * (at http://www.stetson.edu/~efriedma/papers/spiral.pdf):
30  *  7x7:chpgdqqqoezdddki
31  *
32  * Puzzle competition pdf examples
33  * (at http://www.puzzleratings.org/Yurekli2006puz.pdf):
34  *  6x6:EDbaMucCohbrecEi
35  *  10x10:beFbufEEzowDlxldibMHezBQzCdcFzjlci
36  *  13x13:dCemIHFFkJajjgDfdbdBzdzEgjccoPOcztHjBczLDjczqktJjmpreivvNcggFi
37  *
38  */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <assert.h>
44 #include <ctype.h>
45 #include <math.h>
46
47 #include "puzzles.h"
48
49 #ifdef DEBUGGING
50 #define solvep debug
51 #else
52 int solver_show_working;
53 #define solvep(x) do { if (solver_show_working) { printf x; } } while(0)
54 #endif
55
56 #ifdef STANDALONE_PICTURE_GENERATOR
57 /*
58  * Dirty hack to enable the generator to construct a game ID which
59  * solves to a specified black-and-white bitmap. We define a global
60  * variable here which gives the desired colour of each square, and
61  * we arrange that the grid generator never merges squares of
62  * different colours.
63  *
64  * The bitmap as stored here is a simple int array (at these sizes
65  * it isn't worth doing fiddly bit-packing). picture[y*w+x] is 1
66  * iff the pixel at (x,y) is intended to be black.
67  *
68  * (It might be nice to be able to specify some pixels as
69  * don't-care, to give the generator more leeway. But that might be
70  * fiddly.)
71  */
72 static int *picture;
73 #endif
74
75 enum {
76     COL_BACKGROUND,
77     COL_WHITEBG,
78     COL_BLACKBG,
79     COL_WHITEDOT,
80     COL_BLACKDOT,
81     COL_GRID,
82     COL_EDGE,
83     COL_ARROW,
84     COL_CURSOR,
85     NCOLOURS
86 };
87
88 #define DIFFLIST(A)             \
89     A(NORMAL,Normal,n)          \
90     A(UNREASONABLE,Unreasonable,u)
91
92 #define ENUM(upper,title,lower) DIFF_ ## upper,
93 #define TITLE(upper,title,lower) #title,
94 #define ENCODE(upper,title,lower) #lower
95 #define CONFIG(upper,title,lower) ":" #title
96 enum { DIFFLIST(ENUM)
97     DIFF_IMPOSSIBLE, DIFF_AMBIGUOUS, DIFF_UNFINISHED, DIFF_MAX };
98 static char const *const galaxies_diffnames[] = {
99     DIFFLIST(TITLE) "Impossible", "Ambiguous", "Unfinished" };
100 static char const galaxies_diffchars[] = DIFFLIST(ENCODE);
101 #define DIFFCONFIG DIFFLIST(CONFIG)
102
103 struct game_params {
104     /* X and Y is the area of the board as seen by
105      * the user, not the (2n+1) area the game uses. */
106     int w, h, diff;
107 };
108
109 enum { s_tile, s_edge, s_vertex };
110
111 #define F_DOT           1       /* there's a dot here */
112 #define F_EDGE_SET      2       /* the edge is set */
113 #define F_TILE_ASSOC    4       /* this tile is associated with a dot. */
114 #define F_DOT_BLACK     8       /* (ui only) dot is black. */
115 #define F_MARK          16      /* scratch flag */
116 #define F_REACHABLE     32
117 #define F_SCRATCH       64
118 #define F_MULTIPLE      128
119 #define F_DOT_HOLD      256
120 #define F_GOOD          512
121
122 typedef struct space {
123     int x, y;           /* its position */
124     int type;
125     unsigned int flags;
126     int dotx, doty;     /* if flags & F_TILE_ASSOC */
127     int nassoc;         /* if flags & F_DOT */
128 } space;
129
130 #define INGRID(s,x,y) ((x) >= 0 && (y) >= 0 &&                  \
131                        (x) < (state)->sx && (y) < (state)->sy)
132 #define INUI(s,x,y)   ((x) > 0 && (y) > 0 &&                  \
133                        (x) < ((state)->sx-1) && (y) < ((state)->sy-1))
134
135 #define GRID(s,g,x,y) ((s)->g[((y)*(s)->sx)+(x)])
136 #define SPACE(s,x,y) GRID(s,grid,x,y)
137
138 struct game_state {
139     int w, h;           /* size from params */
140     int sx, sy;         /* allocated size, (2x-1)*(2y-1) */
141     space *grid;
142     int completed, used_solve;
143     int ndots;
144     space **dots;
145
146     midend *me;         /* to call supersede_game_desc */
147     int cdiff;          /* difficulty of current puzzle (for status bar),
148                            or -1 if stale. */
149 };
150
151 /* ----------------------------------------------------------
152  * Game parameters and presets
153  */
154
155 /* make up some sensible default sizes */
156
157 #define DEFAULT_PRESET 0
158
159 static const game_params galaxies_presets[] = {
160     {  7,  7, DIFF_NORMAL },
161     {  7,  7, DIFF_UNREASONABLE },
162     { 10, 10, DIFF_NORMAL },
163     { 15, 15, DIFF_NORMAL },
164 };
165
166 static int game_fetch_preset(int i, char **name, game_params **params)
167 {
168     game_params *ret;
169     char buf[80];
170
171     if (i < 0 || i >= lenof(galaxies_presets))
172         return FALSE;
173
174     ret = snew(game_params);
175     *ret = galaxies_presets[i]; /* structure copy */
176
177     sprintf(buf, "%dx%d %s", ret->w, ret->h,
178             galaxies_diffnames[ret->diff]);
179
180     if (name) *name = dupstr(buf);
181     *params = ret;
182     return TRUE;
183 }
184
185 static game_params *default_params(void)
186 {
187     game_params *ret;
188     game_fetch_preset(DEFAULT_PRESET, NULL, &ret);
189     return ret;
190 }
191
192 static void free_params(game_params *params)
193 {
194     sfree(params);
195 }
196
197 static game_params *dup_params(const game_params *params)
198 {
199     game_params *ret = snew(game_params);
200     *ret = *params;                    /* structure copy */
201     return ret;
202 }
203
204 static void decode_params(game_params *params, char const *string)
205 {
206     params->h = params->w = atoi(string);
207     params->diff = DIFF_NORMAL;
208     while (*string && isdigit((unsigned char)*string)) string++;
209     if (*string == 'x') {
210         string++;
211         params->h = atoi(string);
212         while (*string && isdigit((unsigned char)*string)) string++;
213     }
214     if (*string == 'd') {
215         int i;
216         string++;
217         for (i = 0; i <= DIFF_UNREASONABLE; i++)
218             if (*string == galaxies_diffchars[i])
219                 params->diff = i;
220         if (*string) string++;
221     }
222 }
223
224 static char *encode_params(const game_params *params, int full)
225 {
226     char str[80];
227     sprintf(str, "%dx%d", params->w, params->h);
228     if (full)
229         sprintf(str + strlen(str), "d%c", galaxies_diffchars[params->diff]);
230     return dupstr(str);
231 }
232
233 static config_item *game_configure(const game_params *params)
234 {
235     config_item *ret;
236     char buf[80];
237
238     ret = snewn(4, config_item);
239
240     ret[0].name = "Width";
241     ret[0].type = C_STRING;
242     sprintf(buf, "%d", params->w);
243     ret[0].sval = dupstr(buf);
244     ret[0].ival = 0;
245
246     ret[1].name = "Height";
247     ret[1].type = C_STRING;
248     sprintf(buf, "%d", params->h);
249     ret[1].sval = dupstr(buf);
250     ret[1].ival = 0;
251
252     ret[2].name = "Difficulty";
253     ret[2].type = C_CHOICES;
254     ret[2].sval = DIFFCONFIG;
255     ret[2].ival = params->diff;
256
257     ret[3].name = NULL;
258     ret[3].type = C_END;
259     ret[3].sval = NULL;
260     ret[3].ival = 0;
261
262     return ret;
263 }
264
265 static game_params *custom_params(const config_item *cfg)
266 {
267     game_params *ret = snew(game_params);
268
269     ret->w = atoi(cfg[0].sval);
270     ret->h = atoi(cfg[1].sval);
271     ret->diff = cfg[2].ival;
272
273     return ret;
274 }
275
276 static char *validate_params(const game_params *params, int full)
277 {
278     if (params->w < 3 || params->h < 3)
279         return "Width and height must both be at least 3";
280     /*
281      * This shouldn't be able to happen at all, since decode_params
282      * and custom_params will never generate anything that isn't
283      * within range.
284      */
285     assert(params->diff <= DIFF_UNREASONABLE);
286
287     return NULL;
288 }
289
290 /* ----------------------------------------------------------
291  * Game utility functions.
292  */
293
294 static void add_dot(space *space) {
295     assert(!(space->flags & F_DOT));
296     space->flags |= F_DOT;
297     space->nassoc = 0;
298 }
299
300 static void remove_dot(space *space) {
301     assert(space->flags & F_DOT);
302     space->flags &= ~F_DOT;
303 }
304
305 static void remove_assoc(const game_state *state, space *tile) {
306     if (tile->flags & F_TILE_ASSOC) {
307         SPACE(state, tile->dotx, tile->doty).nassoc--;
308         tile->flags &= ~F_TILE_ASSOC;
309         tile->dotx = -1;
310         tile->doty = -1;
311     }
312 }
313
314 static void add_assoc(const game_state *state, space *tile, space *dot) {
315     remove_assoc(state, tile);
316
317 #ifdef STANDALONE_PICTURE_GENERATOR
318     if (picture)
319         assert(!picture[(tile->y/2) * state->w + (tile->x/2)] ==
320                !(dot->flags & F_DOT_BLACK));
321 #endif
322     tile->flags |= F_TILE_ASSOC;
323     tile->dotx = dot->x;
324     tile->doty = dot->y;
325     dot->nassoc++;
326     /*debug(("add_assoc sp %d %d --> dot %d,%d, new nassoc %d.\n",
327            tile->x, tile->y, dot->x, dot->y, dot->nassoc));*/
328 }
329
330 static struct space *sp2dot(const game_state *state, int x, int y)
331 {
332     struct space *sp = &SPACE(state, x, y);
333     if (!(sp->flags & F_TILE_ASSOC)) return NULL;
334     return &SPACE(state, sp->dotx, sp->doty);
335 }
336
337 #define IS_VERTICAL_EDGE(x) ((x % 2) == 0)
338
339 static int game_can_format_as_text_now(const game_params *params)
340 {
341     return TRUE;
342 }
343
344 static char *game_text_format(const game_state *state)
345 {
346     int maxlen = (state->sx+1)*state->sy, x, y;
347     char *ret, *p;
348     space *sp;
349
350     ret = snewn(maxlen+1, char);
351     p = ret;
352
353     for (y = 0; y < state->sy; y++) {
354         for (x = 0; x < state->sx; x++) {
355             sp = &SPACE(state, x, y);
356             if (sp->flags & F_DOT)
357                 *p++ = 'o';
358 #if 0
359             else if (sp->flags & (F_REACHABLE|F_MULTIPLE|F_MARK))
360                 *p++ = (sp->flags & F_MULTIPLE) ? 'M' :
361                     (sp->flags & F_REACHABLE) ? 'R' : 'X';
362 #endif
363             else {
364                 switch (sp->type) {
365                 case s_tile:
366                     if (sp->flags & F_TILE_ASSOC) {
367                         space *dot = sp2dot(state, sp->x, sp->y);
368                         if (dot && dot->flags & F_DOT)
369                             *p++ = (dot->flags & F_DOT_BLACK) ? 'B' : 'W';
370                         else
371                             *p++ = '?'; /* association with not-a-dot. */
372                     } else
373                         *p++ = ' ';
374                     break;
375
376                 case s_vertex:
377                     *p++ = '+';
378                     break;
379
380                 case s_edge:
381                     if (sp->flags & F_EDGE_SET)
382                         *p++ = (IS_VERTICAL_EDGE(x)) ? '|' : '-';
383                     else
384                         *p++ = ' ';
385                     break;
386
387                 default:
388                     assert(!"shouldn't get here!");
389                 }
390             }
391         }
392         *p++ = '\n';
393     }
394
395     assert(p - ret == maxlen);
396     *p = '\0';
397
398     return ret;
399 }
400
401 static void dbg_state(const game_state *state)
402 {
403 #ifdef DEBUGGING
404     char *temp = game_text_format(state);
405     debug(("%s\n", temp));
406     sfree(temp);
407 #endif
408 }
409
410 /* Space-enumeration callbacks should all return 1 for 'progress made',
411  * -1 for 'impossible', and 0 otherwise. */
412 typedef int (*space_cb)(game_state *state, space *sp, void *ctx);
413
414 #define IMPOSSIBLE_QUITS        1
415
416 static int foreach_sub(game_state *state, space_cb cb, unsigned int f,
417                        void *ctx, int startx, int starty)
418 {
419     int x, y, progress = 0, impossible = 0, ret;
420     space *sp;
421
422     for (y = starty; y < state->sy; y += 2) {
423         sp = &SPACE(state, startx, y);
424         for (x = startx; x < state->sx; x += 2) {
425             ret = cb(state, sp, ctx);
426             if (ret == -1) {
427                 if (f & IMPOSSIBLE_QUITS) return -1;
428                 impossible = -1;
429             } else if (ret == 1) {
430                 progress = 1;
431             }
432             sp += 2;
433         }
434     }
435     return impossible ? -1 : progress;
436 }
437
438 static int foreach_tile(game_state *state, space_cb cb, unsigned int f,
439                         void *ctx)
440 {
441     return foreach_sub(state, cb, f, ctx, 1, 1);
442 }
443
444 static int foreach_edge(game_state *state, space_cb cb, unsigned int f,
445                         void *ctx)
446 {
447     int ret1, ret2;
448
449     ret1 = foreach_sub(state, cb, f, ctx, 0, 1);
450     ret2 = foreach_sub(state, cb, f, ctx, 1, 0);
451
452     if (ret1 == -1 || ret2 == -1) return -1;
453     return (ret1 || ret2) ? 1 : 0;
454 }
455
456 #if 0
457 static int foreach_vertex(game_state *state, space_cb cb, unsigned int f,
458                           void *ctx)
459 {
460     return foreach_sub(state, cb, f, ctx, 0, 0);
461 }
462 #endif
463
464 #if 0
465 static int is_same_assoc(game_state *state,
466                          int x1, int y1, int x2, int y2)
467 {
468     struct space *s1, *s2;
469
470     if (!INGRID(state, x1, y1) || !INGRID(state, x2, y2))
471         return 0;
472
473     s1 = &SPACE(state, x1, y1);
474     s2 = &SPACE(state, x2, y2);
475     assert(s1->type == s_tile && s2->type == s_tile);
476     if ((s1->flags & F_TILE_ASSOC) && (s2->flags & F_TILE_ASSOC) &&
477         s1->dotx == s2->dotx && s1->doty == s2->doty)
478         return 1;
479     return 0; /* 0 if not same or not both associated. */
480 }
481 #endif
482
483 #if 0
484 static int edges_into_vertex(game_state *state,
485                              int x, int y)
486 {
487     int dx, dy, nx, ny, count = 0;
488
489     assert(SPACE(state, x, y).type == s_vertex);
490     for (dx = -1; dx <= 1; dx++) {
491         for (dy = -1; dy <= 1; dy++) {
492             if (dx != 0 && dy != 0) continue;
493             if (dx == 0 && dy == 0) continue;
494
495             nx = x+dx; ny = y+dy;
496             if (!INGRID(state, nx, ny)) continue;
497             assert(SPACE(state, nx, ny).type == s_edge);
498             if (SPACE(state, nx, ny).flags & F_EDGE_SET)
499                 count++;
500         }
501     }
502     return count;
503 }
504 #endif
505
506 static struct space *space_opposite_dot(struct game_state *state,
507                                         struct space *sp, struct space *dot)
508 {
509     int dx, dy, tx, ty;
510     space *sp2;
511
512     dx = sp->x - dot->x;
513     dy = sp->y - dot->y;
514     tx = dot->x - dx;
515     ty = dot->y - dy;
516     if (!INGRID(state, tx, ty)) return NULL;
517
518     sp2 = &SPACE(state, tx, ty);
519     assert(sp2->type == sp->type);
520     return sp2;
521 }
522
523 static struct space *tile_opposite(struct game_state *state, struct space *sp)
524 {
525     struct space *dot;
526
527     assert(sp->flags & F_TILE_ASSOC);
528     dot = &SPACE(state, sp->dotx, sp->doty);
529     return space_opposite_dot(state, sp, dot);
530 }
531
532 static int dotfortile(game_state *state, space *tile, space *dot)
533 {
534     space *tile_opp = space_opposite_dot(state, tile, dot);
535
536     if (!tile_opp) return 0; /* opposite would be off grid */
537     if (tile_opp->flags & F_TILE_ASSOC &&
538             (tile_opp->dotx != dot->x || tile_opp->doty != dot->y))
539             return 0; /* opposite already associated with diff. dot */
540     return 1;
541 }
542
543 static void adjacencies(struct game_state *state, struct space *sp,
544                         struct space **a1s, struct space **a2s)
545 {
546     int dxs[4] = {-1, 1, 0, 0}, dys[4] = {0, 0, -1, 1};
547     int n, x, y;
548
549     /* this function needs optimising. */
550
551     for (n = 0; n < 4; n++) {
552         x = sp->x+dxs[n];
553         y = sp->y+dys[n];
554
555         if (INGRID(state, x, y)) {
556             a1s[n] = &SPACE(state, x, y);
557
558             x += dxs[n]; y += dys[n];
559
560             if (INGRID(state, x, y))
561                 a2s[n] = &SPACE(state, x, y);
562             else
563                 a2s[n] = NULL;
564         } else {
565             a1s[n] = a2s[n] = NULL;
566         }
567     }
568 }
569
570 static int outline_tile_fordot(game_state *state, space *tile, int mark)
571 {
572     struct space *tadj[4], *eadj[4];
573     int i, didsth = 0, edge, same;
574
575     assert(tile->type == s_tile);
576     adjacencies(state, tile, eadj, tadj);
577     for (i = 0; i < 4; i++) {
578         if (!eadj[i]) continue;
579
580         edge = (eadj[i]->flags & F_EDGE_SET) ? 1 : 0;
581         if (tadj[i]) {
582             if (!(tile->flags & F_TILE_ASSOC))
583                 same = (tadj[i]->flags & F_TILE_ASSOC) ? 0 : 1;
584             else
585                 same = ((tadj[i]->flags & F_TILE_ASSOC) &&
586                     tile->dotx == tadj[i]->dotx &&
587                     tile->doty == tadj[i]->doty) ? 1 : 0;
588         } else
589             same = 0;
590
591         if (!edge && !same) {
592             if (mark) eadj[i]->flags |= F_EDGE_SET;
593             didsth = 1;
594         } else if (edge && same) {
595             if (mark) eadj[i]->flags &= ~F_EDGE_SET;
596             didsth = 1;
597         }
598     }
599     return didsth;
600 }
601
602 static void tiles_from_edge(struct game_state *state,
603                             struct space *sp, struct space **ts)
604 {
605     int xs[2], ys[2];
606
607     if (IS_VERTICAL_EDGE(sp->x)) {
608         xs[0] = sp->x-1; ys[0] = sp->y;
609         xs[1] = sp->x+1; ys[1] = sp->y;
610     } else {
611         xs[0] = sp->x; ys[0] = sp->y-1;
612         xs[1] = sp->x; ys[1] = sp->y+1;
613     }
614     ts[0] = INGRID(state, xs[0], ys[0]) ? &SPACE(state, xs[0], ys[0]) : NULL;
615     ts[1] = INGRID(state, xs[1], ys[1]) ? &SPACE(state, xs[1], ys[1]) : NULL;
616 }
617
618 /* Returns a move string for use by 'solve', including the initial
619  * 'S' if issolve is true. */
620 static char *diff_game(const game_state *src, const game_state *dest,
621                        int issolve)
622 {
623     int movelen = 0, movesize = 256, x, y, len;
624     char *move = snewn(movesize, char), buf[80], *sep = "";
625     char achar = issolve ? 'a' : 'A';
626     space *sps, *spd;
627
628     assert(src->sx == dest->sx && src->sy == dest->sy);
629
630     if (issolve) {
631         move[movelen++] = 'S';
632         sep = ";";
633     }
634     move[movelen] = '\0';
635     for (x = 0; x < src->sx; x++) {
636         for (y = 0; y < src->sy; y++) {
637             sps = &SPACE(src, x, y);
638             spd = &SPACE(dest, x, y);
639
640             assert(sps->type == spd->type);
641
642             len = 0;
643             if (sps->type == s_tile) {
644                 if ((sps->flags & F_TILE_ASSOC) &&
645                     (spd->flags & F_TILE_ASSOC)) {
646                     if (sps->dotx != spd->dotx ||
647                         sps->doty != spd->doty)
648                     /* Both associated; change association, if different */
649                         len = sprintf(buf, "%s%c%d,%d,%d,%d", sep,
650                                       (int)achar, x, y, spd->dotx, spd->doty);
651                 } else if (sps->flags & F_TILE_ASSOC)
652                     /* Only src associated; remove. */
653                     len = sprintf(buf, "%sU%d,%d", sep, x, y);
654                 else if (spd->flags & F_TILE_ASSOC)
655                     /* Only dest associated; add. */
656                     len = sprintf(buf, "%s%c%d,%d,%d,%d", sep,
657                                   (int)achar, x, y, spd->dotx, spd->doty);
658             } else if (sps->type == s_edge) {
659                 if ((sps->flags & F_EDGE_SET) != (spd->flags & F_EDGE_SET))
660                     /* edge flags are different; flip them. */
661                     len = sprintf(buf, "%sE%d,%d", sep, x, y);
662             }
663             if (len) {
664                 if (movelen + len >= movesize) {
665                     movesize = movelen + len + 256;
666                     move = sresize(move, movesize, char);
667                 }
668                 strcpy(move + movelen, buf);
669                 movelen += len;
670                 sep = ";";
671             }
672         }
673     }
674     debug(("diff_game src then dest:\n"));
675     dbg_state(src);
676     dbg_state(dest);
677     debug(("diff string %s\n", move));
678     return move;
679 }
680
681 /* Returns 1 if a dot here would not be too close to any other dots
682  * (and would avoid other game furniture). */
683 static int dot_is_possible(game_state *state, space *sp, int allow_assoc)
684 {
685     int bx = 0, by = 0, dx, dy;
686     space *adj;
687 #ifdef STANDALONE_PICTURE_GENERATOR
688     int col = -1;
689 #endif
690
691     switch (sp->type) {
692     case s_tile:
693         bx = by = 1; break;
694     case s_edge:
695         if (IS_VERTICAL_EDGE(sp->x)) {
696             bx = 2; by = 1;
697         } else {
698             bx = 1; by = 2;
699         }
700         break;
701     case s_vertex:
702         bx = by = 2; break;
703     }
704
705     for (dx = -bx; dx <= bx; dx++) {
706         for (dy = -by; dy <= by; dy++) {
707             if (!INGRID(state, sp->x+dx, sp->y+dy)) continue;
708
709             adj = &SPACE(state, sp->x+dx, sp->y+dy);
710
711 #ifdef STANDALONE_PICTURE_GENERATOR
712             /*
713              * Check that all the squares we're looking at have the
714              * same colour.
715              */
716             if (picture) {
717                 if (adj->type == s_tile) {
718                     int c = picture[(adj->y / 2) * state->w + (adj->x / 2)];
719                     if (col < 0)
720                         col = c;
721                     if (c != col)
722                         return 0;          /* colour mismatch */
723                 }
724             }
725 #endif
726
727             if (!allow_assoc && (adj->flags & F_TILE_ASSOC))
728                 return 0;
729
730             if (dx != 0 || dy != 0) {
731                 /* Other than our own square, no dots nearby. */
732                 if (adj->flags & (F_DOT))
733                     return 0;
734             }
735
736             /* We don't want edges within our rectangle
737              * (but don't care about edges on the edge) */
738             if (abs(dx) < bx && abs(dy) < by &&
739                 adj->flags & F_EDGE_SET)
740                 return 0;
741         }
742     }
743     return 1;
744 }
745
746 /* ----------------------------------------------------------
747  * Game generation, structure creation, and descriptions.
748  */
749
750 static game_state *blank_game(int w, int h)
751 {
752     game_state *state = snew(game_state);
753     int x, y;
754
755     state->w = w;
756     state->h = h;
757
758     state->sx = (w*2)+1;
759     state->sy = (h*2)+1;
760     state->grid = snewn(state->sx * state->sy, struct space);
761     state->completed = state->used_solve = 0;
762
763     for (x = 0; x < state->sx; x++) {
764         for (y = 0; y < state->sy; y++) {
765             struct space *sp = &SPACE(state, x, y);
766             memset(sp, 0, sizeof(struct space));
767             sp->x = x;
768             sp->y = y;
769             if ((x % 2) == 0 && (y % 2) == 0)
770                 sp->type = s_vertex;
771             else if ((x % 2) == 0 || (y % 2) == 0) {
772                 sp->type = s_edge;
773                 if (x == 0 || y == 0 || x == state->sx-1 || y == state->sy-1)
774                     sp->flags |= F_EDGE_SET;
775             } else
776                 sp->type = s_tile;
777         }
778     }
779
780     state->ndots = 0;
781     state->dots = NULL;
782
783     state->me = NULL; /* filled in by new_game. */
784     state->cdiff = -1;
785
786     return state;
787 }
788
789 static void game_update_dots(game_state *state)
790 {
791     int i, n, sz = state->sx * state->sy;
792
793     if (state->dots) sfree(state->dots);
794     state->ndots = 0;
795
796     for (i = 0; i < sz; i++) {
797         if (state->grid[i].flags & F_DOT) state->ndots++;
798     }
799     state->dots = snewn(state->ndots, space *);
800     n = 0;
801     for (i = 0; i < sz; i++) {
802         if (state->grid[i].flags & F_DOT)
803             state->dots[n++] = &state->grid[i];
804     }
805 }
806
807 static void clear_game(game_state *state, int cleardots)
808 {
809     int x, y;
810
811     /* don't erase edge flags around outline! */
812     for (x = 1; x < state->sx-1; x++) {
813         for (y = 1; y < state->sy-1; y++) {
814             if (cleardots)
815                 SPACE(state, x, y).flags = 0;
816             else
817                 SPACE(state, x, y).flags &= (F_DOT|F_DOT_BLACK);
818         }
819     }
820     if (cleardots) game_update_dots(state);
821 }
822
823 static game_state *dup_game(const game_state *state)
824 {
825     game_state *ret = blank_game(state->w, state->h);
826
827     ret->completed = state->completed;
828     ret->used_solve = state->used_solve;
829
830     memcpy(ret->grid, state->grid,
831            ret->sx*ret->sy*sizeof(struct space));
832
833     game_update_dots(ret);
834
835     ret->me = state->me;
836     ret->cdiff = state->cdiff;
837
838     return ret;
839 }
840
841 static void free_game(game_state *state)
842 {
843     if (state->dots) sfree(state->dots);
844     sfree(state->grid);
845     sfree(state);
846 }
847
848 /* Game description is a sequence of letters representing the number
849  * of spaces (a = 0, y = 24) before the next dot; a-y for a white dot,
850  * and A-Y for a black dot. 'z' is 25 spaces (and no dot).
851  *
852  * I know it's a bitch to generate by hand, so we provide
853  * an edit mode.
854  */
855
856 static char *encode_game(game_state *state)
857 {
858     char *desc, *p;
859     int run, x, y, area;
860     unsigned int f;
861
862     area = (state->sx-2) * (state->sy-2);
863
864     desc = snewn(area, char);
865     p = desc;
866     run = 0;
867     for (y = 1; y < state->sy-1; y++) {
868         for (x = 1; x < state->sx-1; x++) {
869             f = SPACE(state, x, y).flags;
870
871             /* a/A is 0 spaces between, b/B is 1 space, ...
872              * y/Y is 24 spaces, za/zA is 25 spaces, ...
873              * It's easier to count from 0 because we then
874              * don't have to special-case the top left-hand corner
875              * (which could be a dot with 0 spaces before it). */
876             if (!(f & F_DOT))
877                 run++;
878             else {
879                 while (run > 24) {
880                     *p++ = 'z';
881                     run -= 25;
882                 }
883                 *p++ = ((f & F_DOT_BLACK) ? 'A' : 'a') + run;
884                 run = 0;
885             }
886         }
887     }
888     assert(p - desc < area);
889     *p++ = '\0';
890     desc = sresize(desc, p - desc, char);
891
892     return desc;
893 }
894
895 struct movedot {
896     int op;
897     space *olddot, *newdot;
898 };
899
900 enum { MD_CHECK, MD_MOVE };
901
902 static int movedot_cb(game_state *state, space *tile, void *vctx)
903 {
904    struct movedot *md = (struct movedot *)vctx;
905    space *newopp = NULL;
906
907    assert(tile->type == s_tile);
908    assert(md->olddot && md->newdot);
909
910    if (!(tile->flags & F_TILE_ASSOC)) return 0;
911    if (tile->dotx != md->olddot->x || tile->doty != md->olddot->y)
912        return 0;
913
914    newopp = space_opposite_dot(state, tile, md->newdot);
915
916    switch (md->op) {
917    case MD_CHECK:
918        /* If the tile is associated with the old dot, check its
919         * opposite wrt the _new_ dot is empty or same assoc. */
920        if (!newopp) return -1; /* no new opposite */
921        if (newopp->flags & F_TILE_ASSOC) {
922            if (newopp->dotx != md->olddot->x ||
923                newopp->doty != md->olddot->y)
924                return -1; /* associated, but wrong dot. */
925        }
926 #ifdef STANDALONE_PICTURE_GENERATOR
927        if (picture) {
928            /*
929             * Reject if either tile and the dot don't match in colour.
930             */
931            if (!(picture[(tile->y/2) * state->w + (tile->x/2)]) ^
932                !(md->newdot->flags & F_DOT_BLACK))
933                return -1;
934            if (!(picture[(newopp->y/2) * state->w + (newopp->x/2)]) ^
935                !(md->newdot->flags & F_DOT_BLACK))
936                return -1;
937        }
938 #endif
939        break;
940
941    case MD_MOVE:
942        /* Move dot associations: anything that was associated
943         * with the old dot, and its opposite wrt the new dot,
944         * become associated with the new dot. */
945        assert(newopp);
946        debug(("Associating %d,%d and %d,%d with new dot %d,%d.\n",
947               tile->x, tile->y, newopp->x, newopp->y,
948               md->newdot->x, md->newdot->y));
949        add_assoc(state, tile, md->newdot);
950        add_assoc(state, newopp, md->newdot);
951        return 1; /* we did something! */
952    }
953    return 0;
954 }
955
956 /* For the given dot, first see if we could expand it into all the given
957  * extra spaces (by checking for empty spaces on the far side), and then
958  * see if we can move the dot to shift the CoG to include the new spaces.
959  */
960 static int dot_expand_or_move(game_state *state, space *dot,
961                               space **toadd, int nadd)
962 {
963     space *tileopp;
964     int i, ret, nnew, cx, cy;
965     struct movedot md;
966
967     debug(("dot_expand_or_move: %d tiles for dot %d,%d\n",
968            nadd, dot->x, dot->y));
969     for (i = 0; i < nadd; i++)
970         debug(("dot_expand_or_move:   dot %d,%d\n",
971                toadd[i]->x, toadd[i]->y));
972     assert(dot->flags & F_DOT);
973
974 #ifdef STANDALONE_PICTURE_GENERATOR
975     if (picture) {
976         /*
977          * Reject the expansion totally if any of the new tiles are
978          * the wrong colour.
979          */
980         for (i = 0; i < nadd; i++) {
981             if (!(picture[(toadd[i]->y/2) * state->w + (toadd[i]->x/2)]) ^
982                 !(dot->flags & F_DOT_BLACK))
983                 return 0;
984         }
985     }
986 #endif
987
988     /* First off, could we just expand the current dot's tile to cover
989      * the space(s) passed in and their opposites? */
990     for (i = 0; i < nadd; i++) {
991         tileopp = space_opposite_dot(state, toadd[i], dot);
992         if (!tileopp) goto noexpand;
993         if (tileopp->flags & F_TILE_ASSOC) goto noexpand;
994 #ifdef STANDALONE_PICTURE_GENERATOR
995         if (picture) {
996             /*
997              * The opposite tiles have to be the right colour as well.
998              */
999             if (!(picture[(tileopp->y/2) * state->w + (tileopp->x/2)]) ^
1000                 !(dot->flags & F_DOT_BLACK))
1001                 goto noexpand;
1002         }
1003 #endif
1004     }
1005     /* OK, all spaces have valid empty opposites: associate spaces and
1006      * opposites with our dot. */
1007     for (i = 0; i < nadd; i++) {
1008         tileopp = space_opposite_dot(state, toadd[i], dot);
1009         add_assoc(state, toadd[i], dot);
1010         add_assoc(state, tileopp, dot);
1011         debug(("Added associations %d,%d and %d,%d --> %d,%d\n",
1012                toadd[i]->x, toadd[i]->y,
1013                tileopp->x, tileopp->y,
1014                dot->x, dot->y));
1015         dbg_state(state);
1016     }
1017     return 1;
1018
1019 noexpand:
1020     /* Otherwise, try to move dot so as to encompass given spaces: */
1021     /* first, calculate the 'centre of gravity' of the new dot. */
1022     nnew = dot->nassoc + nadd; /* number of tiles assoc. with new dot. */
1023     cx = dot->x * dot->nassoc;
1024     cy = dot->y * dot->nassoc;
1025     for (i = 0; i < nadd; i++) {
1026         cx += toadd[i]->x;
1027         cy += toadd[i]->y;
1028     }
1029     /* If the CoG isn't a whole number, it's not possible. */
1030     if ((cx % nnew) != 0 || (cy % nnew) != 0) {
1031         debug(("Unable to move dot %d,%d, CoG not whole number.\n",
1032                dot->x, dot->y));
1033         return 0;
1034     }
1035     cx /= nnew; cy /= nnew;
1036
1037     /* Check whether all spaces in the old tile would have a good
1038      * opposite wrt the new dot. */
1039     md.olddot = dot;
1040     md.newdot = &SPACE(state, cx, cy);
1041     md.op = MD_CHECK;
1042     ret = foreach_tile(state, movedot_cb, IMPOSSIBLE_QUITS, &md);
1043     if (ret == -1) {
1044         debug(("Unable to move dot %d,%d, new dot not symmetrical.\n",
1045                dot->x, dot->y));
1046         return 0;
1047     }
1048     /* Also check whether all spaces we're adding would have a good
1049      * opposite wrt the new dot. */
1050     for (i = 0; i < nadd; i++) {
1051         tileopp = space_opposite_dot(state, toadd[i], md.newdot);
1052         if (tileopp && (tileopp->flags & F_TILE_ASSOC) &&
1053             (tileopp->dotx != dot->x || tileopp->doty != dot->y)) {
1054             tileopp = NULL;
1055         }
1056         if (!tileopp) {
1057             debug(("Unable to move dot %d,%d, new dot not symmetrical.\n",
1058                dot->x, dot->y));
1059             return 0;
1060         }
1061 #ifdef STANDALONE_PICTURE_GENERATOR
1062         if (picture) {
1063             if (!(picture[(tileopp->y/2) * state->w + (tileopp->x/2)]) ^
1064                 !(dot->flags & F_DOT_BLACK))
1065                 return 0;
1066         }
1067 #endif
1068     }
1069
1070     /* If we've got here, we're ok. First, associate all of 'toadd'
1071      * with the _old_ dot (so they'll get fixed up, with their opposites,
1072      * in the next step). */
1073     for (i = 0; i < nadd; i++) {
1074         debug(("Associating to-add %d,%d with old dot %d,%d.\n",
1075                toadd[i]->x, toadd[i]->y, dot->x, dot->y));
1076         add_assoc(state, toadd[i], dot);
1077     }
1078
1079     /* Finally, move the dot and fix up all the old associations. */
1080     debug(("Moving dot at %d,%d to %d,%d\n",
1081            dot->x, dot->y, md.newdot->x, md.newdot->y));
1082     {
1083 #ifdef STANDALONE_PICTURE_GENERATOR
1084         int f = dot->flags & F_DOT_BLACK;
1085 #endif
1086         remove_dot(dot);
1087         add_dot(md.newdot);
1088 #ifdef STANDALONE_PICTURE_GENERATOR
1089         md.newdot->flags |= f;
1090 #endif
1091     }
1092
1093     md.op = MD_MOVE;
1094     ret = foreach_tile(state, movedot_cb, 0, &md);
1095     assert(ret == 1);
1096     dbg_state(state);
1097
1098     return 1;
1099 }
1100
1101 /* Hard-code to a max. of 2x2 squares, for speed (less malloc) */
1102 #define MAX_TOADD 4
1103 #define MAX_OUTSIDE 8
1104
1105 #define MAX_TILE_PERC 20
1106
1107 static int generate_try_block(game_state *state, random_state *rs,
1108                               int x1, int y1, int x2, int y2)
1109 {
1110     int x, y, nadd = 0, nout = 0, i, maxsz;
1111     space *sp, *toadd[MAX_TOADD], *outside[MAX_OUTSIDE], *dot;
1112
1113     if (!INGRID(state, x1, y1) || !INGRID(state, x2, y2)) return 0;
1114
1115     /* We limit the maximum size of tiles to be ~2*sqrt(area); so,
1116      * a 5x5 grid shouldn't have anything >10 tiles, a 20x20 grid
1117      * nothing >40 tiles. */
1118     maxsz = (int)sqrt((double)(state->w * state->h)) * 2;
1119     debug(("generate_try_block, maxsz %d\n", maxsz));
1120
1121     /* Make a static list of the spaces; if any space is already
1122      * associated then quit immediately. */
1123     for (x = x1; x <= x2; x += 2) {
1124         for (y = y1; y <= y2; y += 2) {
1125             assert(nadd < MAX_TOADD);
1126             sp = &SPACE(state, x, y);
1127             assert(sp->type == s_tile);
1128             if (sp->flags & F_TILE_ASSOC) return 0;
1129             toadd[nadd++] = sp;
1130         }
1131     }
1132
1133     /* Make a list of the spaces outside of our block, and shuffle it. */
1134 #define OUTSIDE(x, y) do {                              \
1135     if (INGRID(state, (x), (y))) {                      \
1136         assert(nout < MAX_OUTSIDE);                     \
1137         outside[nout++] = &SPACE(state, (x), (y));      \
1138     }                                                   \
1139 } while(0)
1140     for (x = x1; x <= x2; x += 2) {
1141         OUTSIDE(x, y1-2);
1142         OUTSIDE(x, y2+2);
1143     }
1144     for (y = y1; y <= y2; y += 2) {
1145         OUTSIDE(x1-2, y);
1146         OUTSIDE(x2+2, y);
1147     }
1148     shuffle(outside, nout, sizeof(space *), rs);
1149
1150     for (i = 0; i < nout; i++) {
1151         if (!(outside[i]->flags & F_TILE_ASSOC)) continue;
1152         dot = &SPACE(state, outside[i]->dotx, outside[i]->doty);
1153         if (dot->nassoc >= maxsz) {
1154             debug(("Not adding to dot %d,%d, large enough (%d) already.\n",
1155                    dot->x, dot->y, dot->nassoc));
1156             continue;
1157         }
1158         if (dot_expand_or_move(state, dot, toadd, nadd)) return 1;
1159     }
1160     return 0;
1161 }
1162
1163 #ifdef STANDALONE_SOLVER
1164 int maxtries;
1165 #define MAXTRIES maxtries
1166 #else
1167 #define MAXTRIES 50
1168 #endif
1169
1170 static int solver_obvious_dot(game_state *state,space *dot);
1171
1172 #define GP_DOTS   1
1173
1174 static void generate_pass(game_state *state, random_state *rs, int *scratch,
1175                          int perc, unsigned int flags)
1176 {
1177     int sz = state->sx*state->sy, nspc, i, ret;
1178
1179     shuffle(scratch, sz, sizeof(int), rs);
1180
1181     /* This bug took me a, er, little while to track down. On PalmOS,
1182      * which has 16-bit signed ints, puzzles over about 9x9 started
1183      * failing to generate because the nspc calculation would start
1184      * to overflow, causing the dots not to be filled in properly. */
1185     nspc = (int)(((long)perc * (long)sz) / 100L);
1186     debug(("generate_pass: %d%% (%d of %dx%d) squares, flags 0x%x\n",
1187            perc, nspc, state->sx, state->sy, flags));
1188
1189     for (i = 0; i < nspc; i++) {
1190         space *sp = &state->grid[scratch[i]];
1191         int x1 = sp->x, y1 = sp->y, x2 = sp->x, y2 = sp->y;
1192
1193         if (sp->type == s_edge) {
1194             if (IS_VERTICAL_EDGE(sp->x)) {
1195                 x1--; x2++;
1196             } else {
1197                 y1--; y2++;
1198             }
1199         }
1200         if (sp->type != s_vertex) {
1201             /* heuristic; expanding from vertices tends to generate lots of
1202              * too-big regions of tiles. */
1203             if (generate_try_block(state, rs, x1, y1, x2, y2))
1204                 continue; /* we expanded successfully. */
1205         }
1206
1207         if (!(flags & GP_DOTS)) continue;
1208
1209         if ((sp->type == s_edge) && (i % 2)) {
1210             debug(("Omitting edge %d,%d as half-of.\n", sp->x, sp->y));
1211             continue;
1212         }
1213
1214         /* If we've got here we might want to put a dot down. Check
1215          * if we can, and add one if so. */
1216         if (dot_is_possible(state, sp, 0)) {
1217             add_dot(sp);
1218 #ifdef STANDALONE_PICTURE_GENERATOR
1219             if (picture) {
1220                 if (picture[(sp->y/2) * state->w + (sp->x/2)])
1221                     sp->flags |= F_DOT_BLACK;
1222             }
1223 #endif
1224             ret = solver_obvious_dot(state, sp);
1225             assert(ret != -1);
1226             debug(("Added dot (and obvious associations) at %d,%d\n",
1227                    sp->x, sp->y));
1228             dbg_state(state);
1229         }
1230     }
1231     dbg_state(state);
1232 }
1233
1234 static int check_complete(const game_state *state, int *dsf, int *colours);
1235 static int solver_state(game_state *state, int maxdiff);
1236
1237 static char *new_game_desc(const game_params *params, random_state *rs,
1238                            char **aux, int interactive)
1239 {
1240     game_state *state = blank_game(params->w, params->h), *copy;
1241     char *desc;
1242     int *scratch, sz = state->sx*state->sy, i;
1243     int diff, ntries = 0, cc;
1244
1245     /* Random list of squares to try and process, one-by-one. */
1246     scratch = snewn(sz, int);
1247     for (i = 0; i < sz; i++) scratch[i] = i;
1248
1249 generate:
1250     clear_game(state, 1);
1251     ntries++;
1252
1253     /* generate_pass(state, rs, scratch, 10, GP_DOTS); */
1254     /* generate_pass(state, rs, scratch, 100, 0); */
1255     generate_pass(state, rs, scratch, 100, GP_DOTS);
1256
1257     game_update_dots(state);
1258
1259 #ifdef DEBUGGING
1260     {
1261         char *tmp = encode_game(state);
1262         debug(("new_game_desc state %dx%d:%s\n", params->w, params->h, tmp));
1263         sfree(tmp);
1264     }
1265 #endif
1266
1267     for (i = 0; i < state->sx*state->sy; i++)
1268         if (state->grid[i].type == s_tile)
1269             outline_tile_fordot(state, &state->grid[i], TRUE);
1270     cc = check_complete(state, NULL, NULL);
1271     assert(cc);
1272
1273     copy = dup_game(state);
1274     clear_game(copy, 0);
1275     dbg_state(copy);
1276     diff = solver_state(copy, params->diff);
1277     free_game(copy);
1278
1279     assert(diff != DIFF_IMPOSSIBLE);
1280     if (diff != params->diff) {
1281         /*
1282          * We'll grudgingly accept a too-easy puzzle, but we must
1283          * _not_ permit a too-hard one (one which the solver
1284          * couldn't handle at all).
1285          */
1286         if (diff > params->diff ||
1287             ntries < MAXTRIES) goto generate;
1288     }
1289
1290 #ifdef STANDALONE_PICTURE_GENERATOR
1291     /*
1292      * Postprocessing pass to prevent excessive numbers of adjacent
1293      * singletons. Iterate over all edges in random shuffled order;
1294      * for each edge that separates two regions, investigate
1295      * whether removing that edge and merging the regions would
1296      * still yield a valid and soluble puzzle. (The two regions
1297      * must also be the same colour, of course.) If so, do it.
1298      * 
1299      * This postprocessing pass is slow (due to repeated solver
1300      * invocations), and seems to be unnecessary during normal
1301      * unconstrained game generation. However, when generating a
1302      * game under colour constraints, excessive singletons seem to
1303      * turn up more often, so it's worth doing this.
1304      */
1305     {
1306         int *posns, nposns;
1307         int i, j, newdiff;
1308         game_state *copy2;
1309
1310         nposns = params->w * (params->h+1) + params->h * (params->w+1);
1311         posns = snewn(nposns, int);
1312         for (i = j = 0; i < state->sx*state->sy; i++)
1313             if (state->grid[i].type == s_edge)
1314                 posns[j++] = i;
1315         assert(j == nposns);
1316
1317         shuffle(posns, nposns, sizeof(*posns), rs);
1318
1319         for (i = 0; i < nposns; i++) {
1320             int x, y, x0, y0, x1, y1, cx, cy, cn, cx0, cy0, cx1, cy1, tx, ty;
1321             space *s0, *s1, *ts, *d0, *d1, *dn;
1322             int ok;
1323
1324             /* Coordinates of edge space */
1325             x = posns[i] % state->sx;
1326             y = posns[i] / state->sx;
1327
1328             /* Coordinates of square spaces on either side of edge */
1329             x0 = ((x+1) & ~1) - 1;     /* round down to next odd number */
1330             y0 = ((y+1) & ~1) - 1;
1331             x1 = 2*x-x0;               /* and reflect about x to get x1 */
1332             y1 = 2*y-y0;
1333
1334             if (!INGRID(state, x0, y0) || !INGRID(state, x1, y1))
1335                 continue;              /* outermost edge of grid */
1336             s0 = &SPACE(state, x0, y0);
1337             s1 = &SPACE(state, x1, y1);
1338             assert(s0->type == s_tile && s1->type == s_tile);
1339
1340             if (s0->dotx == s1->dotx && s0->doty == s1->doty)
1341                 continue;              /* tiles _already_ owned by same dot */
1342
1343             d0 = &SPACE(state, s0->dotx, s0->doty);
1344             d1 = &SPACE(state, s1->dotx, s1->doty);
1345
1346             if ((d0->flags ^ d1->flags) & F_DOT_BLACK)
1347                 continue;              /* different colours: cannot merge */
1348
1349             /*
1350              * Work out where the centre of gravity of the new
1351              * region would be.
1352              */
1353             cx = d0->nassoc * d0->x + d1->nassoc * d1->x;
1354             cy = d0->nassoc * d0->y + d1->nassoc * d1->y;
1355             cn = d0->nassoc + d1->nassoc;
1356             if (cx % cn || cy % cn)
1357                 continue;              /* CoG not at integer coordinates */
1358             cx /= cn;
1359             cy /= cn;
1360             assert(INUI(state, cx, cy));
1361
1362             /*
1363              * Ensure that the CoG would actually be _in_ the new
1364              * region, by verifying that all its surrounding tiles
1365              * belong to one or other of our two dots.
1366              */
1367             cx0 = ((cx+1) & ~1) - 1;   /* round down to next odd number */
1368             cy0 = ((cy+1) & ~1) - 1;
1369             cx1 = 2*cx-cx0;            /* and reflect about cx to get cx1 */
1370             cy1 = 2*cy-cy0;
1371             ok = TRUE;
1372             for (ty = cy0; ty <= cy1; ty += 2)
1373                 for (tx = cx0; tx <= cx1; tx += 2) {
1374                     ts = &SPACE(state, tx, ty);
1375                     assert(ts->type == s_tile);
1376                     if ((ts->dotx != d0->x || ts->doty != d0->y) &&
1377                         (ts->dotx != d1->x || ts->doty != d1->y))
1378                         ok = FALSE;
1379                 }
1380             if (!ok)
1381                 continue;
1382
1383             /*
1384              * Verify that for every tile in either source region,
1385              * that tile's image in the new CoG is also in one of
1386              * the two source regions.
1387              */
1388             for (ty = 1; ty < state->sy; ty += 2) {
1389                 for (tx = 1; tx < state->sx; tx += 2) {
1390                     int tx1, ty1;
1391
1392                     ts = &SPACE(state, tx, ty);
1393                     assert(ts->type == s_tile);
1394                     if ((ts->dotx != d0->x || ts->doty != d0->y) &&
1395                         (ts->dotx != d1->x || ts->doty != d1->y))
1396                         continue;      /* not part of these tiles anyway */
1397                     tx1 = 2*cx-tx;
1398                     ty1 = 2*cy-ty;
1399                     if (!INGRID(state, tx1, ty1)) {
1400                         ok = FALSE;
1401                         break;
1402                     }
1403                     ts = &SPACE(state, cx+cx-tx, cy+cy-ty);
1404                     if ((ts->dotx != d0->x || ts->doty != d0->y) &&
1405                         (ts->dotx != d1->x || ts->doty != d1->y)) {
1406                         ok = FALSE;
1407                         break;
1408                     }
1409                 }
1410                 if (!ok)
1411                     break;
1412             }
1413             if (!ok)
1414                 continue;
1415
1416             /*
1417              * Now we're clear to attempt the merge. We take a copy
1418              * of the game state first, so we can revert it easily
1419              * if the resulting puzzle turns out to have become
1420              * insoluble.
1421              */
1422             copy2 = dup_game(state);
1423
1424             remove_dot(d0);
1425             remove_dot(d1);
1426             dn = &SPACE(state, cx, cy);
1427             add_dot(dn);
1428             dn->flags |= (d0->flags & F_DOT_BLACK);
1429             for (ty = 1; ty < state->sy; ty += 2) {
1430                 for (tx = 1; tx < state->sx; tx += 2) {
1431                     ts = &SPACE(state, tx, ty);
1432                     assert(ts->type == s_tile);
1433                     if ((ts->dotx != d0->x || ts->doty != d0->y) &&
1434                         (ts->dotx != d1->x || ts->doty != d1->y))
1435                         continue;      /* not part of these tiles anyway */
1436                     add_assoc(state, ts, dn);
1437                 }
1438             }
1439
1440             copy = dup_game(state);
1441             clear_game(copy, 0);
1442             dbg_state(copy);
1443             newdiff = solver_state(copy, params->diff);
1444             free_game(copy);
1445             if (diff == newdiff) {
1446                 /* Still just as soluble. Let the merge stand. */
1447                 free_game(copy2);
1448             } else {
1449                 /* Became insoluble. Revert. */
1450                 free_game(state);
1451                 state = copy2;
1452             }
1453         }
1454         sfree(posns);
1455     }
1456 #endif
1457
1458     desc = encode_game(state);
1459 #ifndef STANDALONE_SOLVER
1460     debug(("new_game_desc generated: \n"));
1461     dbg_state(state);
1462 #endif
1463
1464     free_game(state);
1465     sfree(scratch);
1466
1467     return desc;
1468 }
1469
1470 static int solver_obvious(game_state *state);
1471
1472 static int dots_too_close(game_state *state)
1473 {
1474     /* Quick-and-dirty check, using half the solver:
1475      * solver_obvious will only fail if the dots are
1476      * too close together, so dot-proximity associations
1477      * overlap. */
1478     game_state *tmp = dup_game(state);
1479     int ret = solver_obvious(tmp);
1480     free_game(tmp);
1481     return (ret == -1) ? 1 : 0;
1482 }
1483
1484 static game_state *load_game(const game_params *params, const char *desc,
1485                              char **why_r)
1486 {
1487     game_state *state = blank_game(params->w, params->h);
1488     char *why = NULL;
1489     int i, x, y, n;
1490     unsigned int df;
1491
1492     i = 0;
1493     while (*desc) {
1494         n = *desc++;
1495         if (n == 'z') {
1496             i += 25;
1497             continue;
1498         }
1499         if (n >= 'a' && n <= 'y') {
1500             i += n - 'a';
1501             df = 0;
1502         } else if (n >= 'A' && n <= 'Y') {
1503             i += n - 'A';
1504             df = F_DOT_BLACK;
1505         } else {
1506             why = "Invalid characters in game description"; goto fail;
1507         }
1508         /* if we got here we incremented i and have a dot to add. */
1509         y = (i / (state->sx-2)) + 1;
1510         x = (i % (state->sx-2)) + 1;
1511         if (!INUI(state, x, y)) {
1512             why = "Too much data to fit in grid"; goto fail;
1513         }
1514         add_dot(&SPACE(state, x, y));
1515         SPACE(state, x, y).flags |= df;
1516         i++;
1517     }
1518     game_update_dots(state);
1519
1520     if (dots_too_close(state)) {
1521         why = "Dots too close together"; goto fail;
1522     }
1523
1524     return state;
1525
1526 fail:
1527     free_game(state);
1528     if (why_r) *why_r = why;
1529     return NULL;
1530 }
1531
1532 static char *validate_desc(const game_params *params, const char *desc)
1533 {
1534     char *why = NULL;
1535     game_state *dummy = load_game(params, desc, &why);
1536     if (dummy) {
1537         free_game(dummy);
1538         assert(!why);
1539     } else
1540         assert(why);
1541     return why;
1542 }
1543
1544 static game_state *new_game(midend *me, const game_params *params,
1545                             const char *desc)
1546 {
1547     game_state *state = load_game(params, desc, NULL);
1548     if (!state) {
1549         assert("Unable to load ?validated game.");
1550         return NULL;
1551     }
1552 #ifdef EDITOR
1553     state->me = me;
1554 #endif
1555     return state;
1556 }
1557
1558 /* ----------------------------------------------------------
1559  * Solver and all its little wizards.
1560  */
1561
1562 int solver_recurse_depth;
1563
1564 typedef struct solver_ctx {
1565     game_state *state;
1566     int sz;             /* state->sx * state->sy */
1567     space **scratch;    /* size sz */
1568
1569 } solver_ctx;
1570
1571 static solver_ctx *new_solver(game_state *state)
1572 {
1573     solver_ctx *sctx = snew(solver_ctx);
1574     sctx->state = state;
1575     sctx->sz = state->sx*state->sy;
1576     sctx->scratch = snewn(sctx->sz, space *);
1577     return sctx;
1578 }
1579
1580 static void free_solver(solver_ctx *sctx)
1581 {
1582     sfree(sctx->scratch);
1583     sfree(sctx);
1584 }
1585
1586     /* Solver ideas so far:
1587      *
1588      * For any empty space, work out how many dots it could associate
1589      * with:
1590        * it needs line-of-sight
1591        * it needs an empty space on the far side
1592        * any adjacent lines need corresponding line possibilities.
1593      */
1594
1595 /* The solver_ctx should keep a list of dot positions, for quicker looping.
1596  *
1597  * Solver techniques, in order of difficulty:
1598    * obvious adjacency to dots
1599    * transferring tiles to opposite side
1600    * transferring lines to opposite side
1601    * one possible dot for a given tile based on opposite availability
1602    * tile with 3 definite edges next to an associated tile must associate
1603       with same dot.
1604    *
1605    * one possible dot for a given tile based on line-of-sight
1606  */
1607
1608 static int solver_add_assoc(game_state *state, space *tile, int dx, int dy,
1609                             const char *why)
1610 {
1611     space *dot, *tile_opp;
1612
1613     dot = &SPACE(state, dx, dy);
1614     tile_opp = space_opposite_dot(state, tile, dot);
1615
1616     assert(tile->type == s_tile);
1617     if (tile->flags & F_TILE_ASSOC) {
1618         if ((tile->dotx != dx) || (tile->doty != dy)) {
1619             solvep(("%*sSet %d,%d --> %d,%d (%s) impossible; "
1620                     "already --> %d,%d.\n",
1621                     solver_recurse_depth*4, "",
1622                     tile->x, tile->y, dx, dy, why,
1623                     tile->dotx, tile->doty));
1624             return -1;
1625         }
1626         return 0; /* no-op */
1627     }
1628     if (!tile_opp) {
1629         solvep(("%*s%d,%d --> %d,%d impossible, no opposite tile.\n",
1630                 solver_recurse_depth*4, "", tile->x, tile->y, dx, dy));
1631         return -1;
1632     }
1633     if (tile_opp->flags & F_TILE_ASSOC &&
1634         (tile_opp->dotx != dx || tile_opp->doty != dy)) {
1635         solvep(("%*sSet %d,%d --> %d,%d (%s) impossible; "
1636                 "opposite already --> %d,%d.\n",
1637                 solver_recurse_depth*4, "",
1638                 tile->x, tile->y, dx, dy, why,
1639                 tile_opp->dotx, tile_opp->doty));
1640         return -1;
1641     }
1642
1643     add_assoc(state, tile, dot);
1644     add_assoc(state, tile_opp, dot);
1645     solvep(("%*sSetting %d,%d --> %d,%d (%s).\n",
1646             solver_recurse_depth*4, "",
1647             tile->x, tile->y,dx, dy, why));
1648     solvep(("%*sSetting %d,%d --> %d,%d (%s, opposite).\n",
1649             solver_recurse_depth*4, "",
1650             tile_opp->x, tile_opp->y, dx, dy, why));
1651     return 1;
1652 }
1653
1654 static int solver_obvious_dot(game_state *state, space *dot)
1655 {
1656     int dx, dy, ret, didsth = 0;
1657     space *tile;
1658
1659     debug(("%*ssolver_obvious_dot for %d,%d.\n",
1660            solver_recurse_depth*4, "", dot->x, dot->y));
1661
1662     assert(dot->flags & F_DOT);
1663     for (dx = -1; dx <= 1; dx++) {
1664         for (dy = -1; dy <= 1; dy++) {
1665             if (!INGRID(state, dot->x+dx, dot->y+dy)) continue;
1666
1667             tile = &SPACE(state, dot->x+dx, dot->y+dy);
1668             if (tile->type == s_tile) {
1669                 ret = solver_add_assoc(state, tile, dot->x, dot->y,
1670                                        "next to dot");
1671                 if (ret < 0) return -1;
1672                 if (ret > 0) didsth = 1;
1673             }
1674         }
1675     }
1676     return didsth;
1677 }
1678
1679 static int solver_obvious(game_state *state)
1680 {
1681     int i, didsth = 0, ret;
1682
1683     debug(("%*ssolver_obvious.\n", solver_recurse_depth*4, ""));
1684
1685     for (i = 0; i < state->ndots; i++) {
1686         ret = solver_obvious_dot(state, state->dots[i]);
1687         if (ret < 0) return -1;
1688         if (ret > 0) didsth = 1;
1689     }
1690     return didsth;
1691 }
1692
1693 static int solver_lines_opposite_cb(game_state *state, space *edge, void *ctx)
1694 {
1695     int didsth = 0, n, dx, dy;
1696     space *tiles[2], *tile_opp, *edge_opp;
1697
1698     assert(edge->type == s_edge);
1699
1700     tiles_from_edge(state, edge, tiles);
1701
1702     /* if tiles[0] && tiles[1] && they're both associated
1703      * and they're both associated with different dots,
1704      * ensure the line is set. */
1705     if (!(edge->flags & F_EDGE_SET) &&
1706         tiles[0] && tiles[1] &&
1707         (tiles[0]->flags & F_TILE_ASSOC) &&
1708         (tiles[1]->flags & F_TILE_ASSOC) &&
1709         (tiles[0]->dotx != tiles[1]->dotx ||
1710          tiles[0]->doty != tiles[1]->doty)) {
1711         /* No edge, but the two adjacent tiles are both
1712          * associated with different dots; add the edge. */
1713         solvep(("%*sSetting edge %d,%d - tiles different dots.\n",
1714                solver_recurse_depth*4, "", edge->x, edge->y));
1715         edge->flags |= F_EDGE_SET;
1716         didsth = 1;
1717     }
1718
1719     if (!(edge->flags & F_EDGE_SET)) return didsth;
1720     for (n = 0; n < 2; n++) {
1721         if (!tiles[n]) continue;
1722         assert(tiles[n]->type == s_tile);
1723         if (!(tiles[n]->flags & F_TILE_ASSOC)) continue;
1724
1725         tile_opp = tile_opposite(state, tiles[n]);
1726         if (!tile_opp) {
1727             solvep(("%*simpossible: edge %d,%d has assoc. tile %d,%d"
1728                    " with no opposite.\n",
1729                    solver_recurse_depth*4, "",
1730                    edge->x, edge->y, tiles[n]->x, tiles[n]->y));
1731             /* edge of tile has no opposite edge (off grid?);
1732              * this is impossible. */
1733             return -1;
1734         }
1735
1736         dx = tiles[n]->x - edge->x;
1737         dy = tiles[n]->y - edge->y;
1738         assert(INGRID(state, tile_opp->x+dx, tile_opp->y+dy));
1739         edge_opp = &SPACE(state, tile_opp->x+dx, tile_opp->y+dy);
1740         if (!(edge_opp->flags & F_EDGE_SET)) {
1741             solvep(("%*sSetting edge %d,%d as opposite %d,%d\n",
1742                    solver_recurse_depth*4, "",
1743                    tile_opp->x-dx, tile_opp->y-dy, edge->x, edge->y));
1744             edge_opp->flags |= F_EDGE_SET;
1745             didsth = 1;
1746         }
1747     }
1748     return didsth;
1749 }
1750
1751 static int solver_spaces_oneposs_cb(game_state *state, space *tile, void *ctx)
1752 {
1753     int n, eset, ret;
1754     struct space *edgeadj[4], *tileadj[4];
1755     int dotx, doty;
1756
1757     assert(tile->type == s_tile);
1758     if (tile->flags & F_TILE_ASSOC) return 0;
1759
1760     adjacencies(state, tile, edgeadj, tileadj);
1761
1762     /* Empty tile. If each edge is either set, or associated with
1763      * the same dot, we must also associate with dot. */
1764     eset = 0; dotx = -1; doty = -1;
1765     for (n = 0; n < 4; n++) {
1766         assert(edgeadj[n]);
1767         assert(edgeadj[n]->type == s_edge);
1768         if (edgeadj[n]->flags & F_EDGE_SET) {
1769             eset++;
1770         } else {
1771             assert(tileadj[n]);
1772             assert(tileadj[n]->type == s_tile);
1773
1774             /* If an adjacent tile is empty we can't make any deductions.*/
1775             if (!(tileadj[n]->flags & F_TILE_ASSOC))
1776                 return 0;
1777
1778             /* If an adjacent tile is assoc. with a different dot
1779              * we can't make any deductions. */
1780             if (dotx != -1 && doty != -1 &&
1781                 (tileadj[n]->dotx != dotx ||
1782                  tileadj[n]->doty != doty))
1783                 return 0;
1784
1785             dotx = tileadj[n]->dotx;
1786             doty = tileadj[n]->doty;
1787         }
1788     }
1789     if (eset == 4) {
1790         solvep(("%*simpossible: empty tile %d,%d has 4 edges\n",
1791                solver_recurse_depth*4, "",
1792                tile->x, tile->y));
1793         return -1;
1794     }
1795     assert(dotx != -1 && doty != -1);
1796
1797     ret = solver_add_assoc(state, tile, dotx, doty, "rest are edges");
1798     if (ret == -1) return -1;
1799     assert(ret != 0); /* really should have done something. */
1800
1801     return 1;
1802 }
1803
1804 /* Improved algorithm for tracking line-of-sight from dots, and not spaces.
1805  *
1806  * The solver_ctx already stores a list of dots: the algorithm proceeds by
1807  * expanding outwards from each dot in turn, expanding first to the boundary
1808  * of its currently-connected tile and then to all empty tiles that could see
1809  * it. Empty tiles will be flagged with a 'can see dot <x,y>' sticker.
1810  *
1811  * Expansion will happen by (symmetrically opposite) pairs of squares; if
1812  * a square hasn't an opposite number there's no point trying to expand through
1813  * it. Empty tiles will therefore also be tagged in pairs.
1814  *
1815  * If an empty tile already has a 'can see dot <x,y>' tag from a previous dot,
1816  * it (and its partner) gets untagged (or, rather, a 'can see two dots' tag)
1817  * because we're looking for single-dot possibilities.
1818  *
1819  * Once we've gone through all the dots, any which still have a 'can see dot'
1820  * tag get associated with that dot (because it must have been the only one);
1821  * any without any tag (i.e. that could see _no_ dots) cause an impossibility
1822  * marked.
1823  *
1824  * The expansion will happen each time with a stored list of (space *) pairs,
1825  * rather than a mark-and-sweep idea; that's horrifically inefficient.
1826  *
1827  * expansion algorithm:
1828  *
1829  * * allocate list of (space *) the size of s->sx*s->sy.
1830  * * allocate second grid for (flags, dotx, doty) size of sx*sy.
1831  *
1832  * clear second grid (flags = 0, all dotx and doty = 0)
1833  * flags: F_REACHABLE, F_MULTIPLE
1834  *
1835  *
1836  * * for each dot, start with one pair of tiles that are associated with it --
1837  *   * vertex --> (dx+1, dy+1), (dx-1, dy-1)
1838  *   * edge --> (adj1, adj2)
1839  *   * tile --> (tile, tile) ???
1840  * * mark that pair of tiles with F_MARK, clear all other F_MARKs.
1841  * * add two tiles to start of list.
1842  *
1843  * set start = 0, end = next = 2
1844  *
1845  * from (start to end-1, step 2) {
1846  * * we have two tiles (t1, t2), opposites wrt our dot.
1847  * * for each (at1) sensible adjacent tile to t1 (i.e. not past an edge):
1848  *   * work out at2 as the opposite to at1
1849  *   * assert at1 and at2 have the same F_MARK values.
1850  *   * if at1 & F_MARK ignore it (we've been there on a previous sweep)
1851  *   * if either are associated with a different dot
1852  *     * mark both with F_MARK (so we ignore them later)
1853  *   * otherwise (assoc. with our dot, or empty):
1854  *     * mark both with F_MARK
1855  *     * add their space * values to the end of the list, set next += 2.
1856  * }
1857  *
1858  * if (end == next)
1859  * * we didn't add any new squares; exit the loop.
1860  * else
1861  * * set start = next+1, end = next. go round again
1862  *
1863  * We've finished expanding from the dot. Now, for each square we have
1864  * in our list (--> each square with F_MARK):
1865  * * if the tile is empty:
1866  *   * if F_REACHABLE was already set
1867  *     * set F_MULTIPLE
1868  *   * otherwise
1869  *     * set F_REACHABLE, set dotx and doty to our dot.
1870  *
1871  * Then, continue the whole thing for each dot in turn.
1872  *
1873  * Once we've done for each dot, go through the entire grid looking for
1874  * empty tiles: for each empty tile:
1875    * if F_REACHABLE and not F_MULTIPLE, set that dot (and its double)
1876    * if !F_REACHABLE, return as impossible.
1877  *
1878  */
1879
1880 /* Returns 1 if this tile is either already associated with this dot,
1881  * or blank. */
1882 static int solver_expand_checkdot(space *tile, space *dot)
1883 {
1884     if (!(tile->flags & F_TILE_ASSOC)) return 1;
1885     if (tile->dotx == dot->x && tile->doty == dot->y) return 1;
1886     return 0;
1887 }
1888
1889 static void solver_expand_fromdot(game_state *state, space *dot, solver_ctx *sctx)
1890 {
1891     int i, j, x, y, start, end, next;
1892     space *sp;
1893
1894     /* Clear the grid of the (space) flags we'll use. */
1895
1896     /* This is well optimised; analysis showed that:
1897         for (i = 0; i < sctx->sz; i++) state->grid[i].flags &= ~F_MARK;
1898        took up ~85% of the total function time! */
1899     for (y = 1; y < state->sy; y += 2) {
1900         sp = &SPACE(state, 1, y);
1901         for (x = 1; x < state->sx; x += 2, sp += 2)
1902             sp->flags &= ~F_MARK;
1903     }
1904
1905     /* Seed the list of marked squares with two that must be associated
1906      * with our dot (possibly the same space) */
1907     if (dot->type == s_tile) {
1908         sctx->scratch[0] = sctx->scratch[1] = dot;
1909     } else if (dot->type == s_edge) {
1910         tiles_from_edge(state, dot, sctx->scratch);
1911     } else if (dot->type == s_vertex) {
1912         /* pick two of the opposite ones arbitrarily. */
1913         sctx->scratch[0] = &SPACE(state, dot->x-1, dot->y-1);
1914         sctx->scratch[1] = &SPACE(state, dot->x+1, dot->y+1);
1915     }
1916     assert(sctx->scratch[0]->flags & F_TILE_ASSOC);
1917     assert(sctx->scratch[1]->flags & F_TILE_ASSOC);
1918
1919     sctx->scratch[0]->flags |= F_MARK;
1920     sctx->scratch[1]->flags |= F_MARK;
1921
1922     debug(("%*sexpand from dot %d,%d seeded with %d,%d and %d,%d.\n",
1923            solver_recurse_depth*4, "", dot->x, dot->y,
1924            sctx->scratch[0]->x, sctx->scratch[0]->y,
1925            sctx->scratch[1]->x, sctx->scratch[1]->y));
1926
1927     start = 0; end = 2; next = 2;
1928
1929 expand:
1930     debug(("%*sexpand: start %d, end %d, next %d\n",
1931            solver_recurse_depth*4, "", start, end, next));
1932     for (i = start; i < end; i += 2) {
1933         space *t1 = sctx->scratch[i]/*, *t2 = sctx->scratch[i+1]*/;
1934         space *edges[4], *tileadj[4], *tileadj2;
1935
1936         adjacencies(state, t1, edges, tileadj);
1937
1938         for (j = 0; j < 4; j++) {
1939             assert(edges[j]);
1940             if (edges[j]->flags & F_EDGE_SET) continue;
1941             assert(tileadj[j]);
1942
1943             if (tileadj[j]->flags & F_MARK) continue; /* seen before. */
1944
1945             /* We have a tile adjacent to t1; find its opposite. */
1946             tileadj2 = space_opposite_dot(state, tileadj[j], dot);
1947             if (!tileadj2) {
1948                 debug(("%*sMarking %d,%d, no opposite.\n",
1949                        solver_recurse_depth*4, "",
1950                        tileadj[j]->x, tileadj[j]->y));
1951                 tileadj[j]->flags |= F_MARK;
1952                 continue; /* no opposite, so mark for next time. */
1953             }
1954             /* If the tile had an opposite we should have either seen both of
1955              * these, or neither of these, before. */
1956             assert(!(tileadj2->flags & F_MARK));
1957
1958             if (solver_expand_checkdot(tileadj[j], dot) &&
1959                 solver_expand_checkdot(tileadj2, dot)) {
1960                 /* Both tiles could associate with this dot; add them to
1961                  * our list. */
1962                 debug(("%*sAdding %d,%d and %d,%d to possibles list.\n",
1963                        solver_recurse_depth*4, "",
1964                        tileadj[j]->x, tileadj[j]->y, tileadj2->x, tileadj2->y));
1965                 sctx->scratch[next++] = tileadj[j];
1966                 sctx->scratch[next++] = tileadj2;
1967             }
1968             /* Either way, we've seen these tiles already so mark them. */
1969             debug(("%*sMarking %d,%d and %d,%d.\n",
1970                    solver_recurse_depth*4, "",
1971                        tileadj[j]->x, tileadj[j]->y, tileadj2->x, tileadj2->y));
1972             tileadj[j]->flags |= F_MARK;
1973             tileadj2->flags |= F_MARK;
1974         }
1975     }
1976     if (next > end) {
1977         /* We added more squares; go back and try again. */
1978         start = end; end = next; goto expand;
1979     }
1980
1981     /* We've expanded as far as we can go. Now we update the main flags
1982      * on all tiles we've expanded into -- if they were empty, we have
1983      * found possible associations for this dot. */
1984     for (i = 0; i < end; i++) {
1985         if (sctx->scratch[i]->flags & F_TILE_ASSOC) continue;
1986         if (sctx->scratch[i]->flags & F_REACHABLE) {
1987             /* This is (at least) the second dot this tile could
1988              * associate with. */
1989             debug(("%*sempty tile %d,%d could assoc. other dot %d,%d\n",
1990                    solver_recurse_depth*4, "",
1991                    sctx->scratch[i]->x, sctx->scratch[i]->y, dot->x, dot->y));
1992             sctx->scratch[i]->flags |= F_MULTIPLE;
1993         } else {
1994             /* This is the first (possibly only) dot. */
1995             debug(("%*sempty tile %d,%d could assoc. 1st dot %d,%d\n",
1996                    solver_recurse_depth*4, "",
1997                    sctx->scratch[i]->x, sctx->scratch[i]->y, dot->x, dot->y));
1998             sctx->scratch[i]->flags |= F_REACHABLE;
1999             sctx->scratch[i]->dotx = dot->x;
2000             sctx->scratch[i]->doty = dot->y;
2001         }
2002     }
2003     dbg_state(state);
2004 }
2005
2006 static int solver_expand_postcb(game_state *state, space *tile, void *ctx)
2007 {
2008     assert(tile->type == s_tile);
2009
2010     if (tile->flags & F_TILE_ASSOC) return 0;
2011
2012     if (!(tile->flags & F_REACHABLE)) {
2013         solvep(("%*simpossible: space (%d,%d) can reach no dots.\n",
2014                 solver_recurse_depth*4, "", tile->x, tile->y));
2015         return -1;
2016     }
2017     if (tile->flags & F_MULTIPLE) return 0;
2018
2019     return solver_add_assoc(state, tile, tile->dotx, tile->doty,
2020                             "single possible dot after expansion");
2021 }
2022
2023 static int solver_expand_dots(game_state *state, solver_ctx *sctx)
2024 {
2025     int i;
2026
2027     for (i = 0; i < sctx->sz; i++)
2028         state->grid[i].flags &= ~(F_REACHABLE|F_MULTIPLE);
2029
2030     for (i = 0; i < state->ndots; i++)
2031         solver_expand_fromdot(state, state->dots[i], sctx);
2032
2033     return foreach_tile(state, solver_expand_postcb, IMPOSSIBLE_QUITS, sctx);
2034 }
2035
2036 struct recurse_ctx {
2037     space *best;
2038     int bestn;
2039 };
2040
2041 static int solver_recurse_cb(game_state *state, space *tile, void *ctx)
2042 {
2043     struct recurse_ctx *rctx = (struct recurse_ctx *)ctx;
2044     int i, n = 0;
2045
2046     assert(tile->type == s_tile);
2047     if (tile->flags & F_TILE_ASSOC) return 0;
2048
2049     /* We're unassociated: count up all the dots we could associate with. */
2050     for (i = 0; i < state->ndots; i++) {
2051         if (dotfortile(state, tile, state->dots[i]))
2052             n++;
2053     }
2054     if (n > rctx->bestn) {
2055         rctx->bestn = n;
2056         rctx->best = tile;
2057     }
2058     return 0;
2059 }
2060
2061 static int solver_state(game_state *state, int maxdiff);
2062
2063 #define MAXRECURSE 5
2064
2065 static int solver_recurse(game_state *state, int maxdiff)
2066 {
2067     int diff = DIFF_IMPOSSIBLE, ret, n, gsz = state->sx * state->sy;
2068     space *ingrid, *outgrid = NULL, *bestopp;
2069     struct recurse_ctx rctx;
2070
2071     if (solver_recurse_depth >= MAXRECURSE) {
2072         solvep(("Limiting recursion to %d, returning.", MAXRECURSE));
2073         return DIFF_UNFINISHED;
2074     }
2075
2076     /* Work out the cell to recurse on; go through all unassociated tiles
2077      * and find which one has the most possible dots it could associate
2078      * with. */
2079     rctx.best = NULL;
2080     rctx.bestn = 0;
2081
2082     foreach_tile(state, solver_recurse_cb, 0, &rctx);
2083     if (rctx.bestn == 0) return DIFF_IMPOSSIBLE; /* or assert? */
2084     assert(rctx.best);
2085
2086     solvep(("%*sRecursing around %d,%d, with %d possible dots.\n",
2087            solver_recurse_depth*4, "",
2088            rctx.best->x, rctx.best->y, rctx.bestn));
2089
2090 #ifdef STANDALONE_SOLVER
2091     solver_recurse_depth++;
2092 #endif
2093
2094     ingrid = snewn(gsz, struct space);
2095     memcpy(ingrid, state->grid, gsz * sizeof(struct space));
2096
2097     for (n = 0; n < state->ndots; n++) {
2098         memcpy(state->grid, ingrid, gsz * sizeof(struct space));
2099
2100         if (!dotfortile(state, rctx.best, state->dots[n])) continue;
2101
2102         /* set cell (temporarily) pointing to that dot. */
2103         solver_add_assoc(state, rctx.best,
2104                          state->dots[n]->x, state->dots[n]->y,
2105                          "Attempting for recursion");
2106
2107         ret = solver_state(state, maxdiff);
2108
2109         if (diff == DIFF_IMPOSSIBLE && ret != DIFF_IMPOSSIBLE) {
2110             /* we found our first solved grid; copy it away. */
2111             assert(!outgrid);
2112             outgrid = snewn(gsz, struct space);
2113             memcpy(outgrid, state->grid, gsz * sizeof(struct space));
2114         }
2115         /* reset cell back to unassociated. */
2116         bestopp = tile_opposite(state, rctx.best);
2117         assert(bestopp && bestopp->flags & F_TILE_ASSOC);
2118
2119         remove_assoc(state, rctx.best);
2120         remove_assoc(state, bestopp);
2121
2122         if (ret == DIFF_AMBIGUOUS || ret == DIFF_UNFINISHED)
2123             diff = ret;
2124         else if (ret == DIFF_IMPOSSIBLE)
2125             /* no change */;
2126         else {
2127             /* precisely one solution */
2128             if (diff == DIFF_IMPOSSIBLE)
2129                 diff = DIFF_UNREASONABLE;
2130             else
2131                 diff = DIFF_AMBIGUOUS;
2132         }
2133         /* if we've found >1 solution, or ran out of recursion,
2134          * give up immediately. */
2135         if (diff == DIFF_AMBIGUOUS || diff == DIFF_UNFINISHED)
2136             break;
2137     }
2138
2139 #ifdef STANDALONE_SOLVER
2140     solver_recurse_depth--;
2141 #endif
2142
2143     if (outgrid) {
2144         /* we found (at least one) soln; copy it back to state */
2145         memcpy(state->grid, outgrid, gsz * sizeof(struct space));
2146         sfree(outgrid);
2147     }
2148     sfree(ingrid);
2149     return diff;
2150 }
2151
2152 static int solver_state(game_state *state, int maxdiff)
2153 {
2154     solver_ctx *sctx = new_solver(state);
2155     int ret, diff = DIFF_NORMAL;
2156
2157 #ifdef STANDALONE_PICTURE_GENERATOR
2158     /* hack, hack: set picture to NULL during solving so that add_assoc
2159      * won't complain when we attempt recursive guessing and guess wrong */
2160     int *savepic = picture;
2161     picture = NULL;
2162 #endif
2163
2164     ret = solver_obvious(state);
2165     if (ret < 0) {
2166         diff = DIFF_IMPOSSIBLE;
2167         goto got_result;
2168     }
2169
2170 #define CHECKRET(d) do {                                        \
2171     if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; }   \
2172     if (ret > 0) { diff = max(diff, (d)); goto cont; }          \
2173 } while(0)
2174
2175     while (1) {
2176 cont:
2177         ret = foreach_edge(state, solver_lines_opposite_cb,
2178                            IMPOSSIBLE_QUITS, sctx);
2179         CHECKRET(DIFF_NORMAL);
2180
2181         ret = foreach_tile(state, solver_spaces_oneposs_cb,
2182                            IMPOSSIBLE_QUITS, sctx);
2183         CHECKRET(DIFF_NORMAL);
2184
2185         ret = solver_expand_dots(state, sctx);
2186         CHECKRET(DIFF_NORMAL);
2187
2188         if (maxdiff <= DIFF_NORMAL)
2189             break;
2190
2191         /* harder still? */
2192
2193         /* if we reach here, we've made no deductions, so we terminate. */
2194         break;
2195     }
2196
2197     if (check_complete(state, NULL, NULL)) goto got_result;
2198
2199     diff = (maxdiff >= DIFF_UNREASONABLE) ?
2200         solver_recurse(state, maxdiff) : DIFF_UNFINISHED;
2201
2202 got_result:
2203     free_solver(sctx);
2204 #ifndef STANDALONE_SOLVER
2205     debug(("solver_state ends, diff %s:\n", galaxies_diffnames[diff]));
2206     dbg_state(state);
2207 #endif
2208
2209 #ifdef STANDALONE_PICTURE_GENERATOR
2210     picture = savepic;
2211 #endif
2212
2213     return diff;
2214 }
2215
2216 #ifndef EDITOR
2217 static char *solve_game(const game_state *state, const game_state *currstate,
2218                         const char *aux, char **error)
2219 {
2220     game_state *tosolve;
2221     char *ret;
2222     int i;
2223     int diff;
2224
2225     tosolve = dup_game(currstate);
2226     diff = solver_state(tosolve, DIFF_UNREASONABLE);
2227     if (diff != DIFF_UNFINISHED && diff != DIFF_IMPOSSIBLE) {
2228         debug(("solve_game solved with current state.\n"));
2229         goto solved;
2230     }
2231     free_game(tosolve);
2232
2233     tosolve = dup_game(state);
2234     diff = solver_state(tosolve, DIFF_UNREASONABLE);
2235     if (diff != DIFF_UNFINISHED && diff != DIFF_IMPOSSIBLE) {
2236         debug(("solve_game solved with original state.\n"));
2237         goto solved;
2238     }
2239     free_game(tosolve);
2240
2241     return NULL;
2242
2243 solved:
2244     /*
2245      * Clear tile associations: the solution will only include the
2246      * edges.
2247      */
2248     for (i = 0; i < tosolve->sx*tosolve->sy; i++)
2249         tosolve->grid[i].flags &= ~F_TILE_ASSOC;
2250     ret = diff_game(currstate, tosolve, 1);
2251     free_game(tosolve);
2252     return ret;
2253 }
2254 #endif
2255
2256 /* ----------------------------------------------------------
2257  * User interface.
2258  */
2259
2260 struct game_ui {
2261     int dragging;
2262     int dx, dy;         /* pixel coords of drag pos. */
2263     int dotx, doty;     /* grid coords of dot we're dragging from. */
2264     int srcx, srcy;     /* grid coords of drag start */
2265     int cur_x, cur_y, cur_visible;
2266 };
2267
2268 static game_ui *new_ui(const game_state *state)
2269 {
2270     game_ui *ui = snew(game_ui);
2271     ui->dragging = FALSE;
2272     ui->cur_x = ui->cur_y = 1;
2273     ui->cur_visible = 0;
2274     return ui;
2275 }
2276
2277 static void free_ui(game_ui *ui)
2278 {
2279     sfree(ui);
2280 }
2281
2282 static char *encode_ui(const game_ui *ui)
2283 {
2284     return NULL;
2285 }
2286
2287 static void decode_ui(game_ui *ui, const char *encoding)
2288 {
2289 }
2290
2291 static void game_changed_state(game_ui *ui, const game_state *oldstate,
2292                                const game_state *newstate)
2293 {
2294 }
2295
2296 #define FLASH_TIME 0.15F
2297
2298 #define PREFERRED_TILE_SIZE 32
2299 #define TILE_SIZE (ds->tilesize)
2300 #define DOT_SIZE        (TILE_SIZE / 4)
2301 #define EDGE_THICKNESS (max(TILE_SIZE / 16, 2))
2302 #define BORDER TILE_SIZE
2303
2304 #define COORD(x) ( (x) * TILE_SIZE + BORDER )
2305 #define SCOORD(x) ( ((x) * TILE_SIZE)/2 + BORDER )
2306 #define FROMCOORD(x) ( ((x) - BORDER) / TILE_SIZE )
2307
2308 #define DRAW_WIDTH      (BORDER * 2 + ds->w * TILE_SIZE)
2309 #define DRAW_HEIGHT     (BORDER * 2 + ds->h * TILE_SIZE)
2310
2311 #define CURSOR_SIZE DOT_SIZE
2312
2313 struct game_drawstate {
2314     int started;
2315     int w, h;
2316     int tilesize;
2317     unsigned long *grid;
2318     int *dx, *dy;
2319     blitter *bl;
2320
2321     int dragging, dragx, dragy;
2322
2323     int *colour_scratch;
2324
2325     int cx, cy, cur_visible;
2326     blitter *cur_bl;
2327 };
2328
2329 #define CORNER_TOLERANCE 0.15F
2330 #define CENTRE_TOLERANCE 0.15F
2331
2332 /*
2333  * Round FP coordinates to the centre of the nearest edge.
2334  */
2335 #ifndef EDITOR
2336 static void coord_round_to_edge(float x, float y, int *xr, int *yr)
2337 {
2338     float xs, ys, xv, yv, dx, dy;
2339
2340     /*
2341      * Find the nearest square-centre.
2342      */
2343     xs = (float)floor(x) + 0.5F;
2344     ys = (float)floor(y) + 0.5F;
2345
2346     /*
2347      * Find the nearest grid vertex.
2348      */
2349     xv = (float)floor(x + 0.5F);
2350     yv = (float)floor(y + 0.5F);
2351
2352     /*
2353      * Determine whether the horizontal or vertical edge from that
2354      * vertex alongside that square is closer to us, by comparing
2355      * distances from the square cente.
2356      */
2357     dx = (float)fabs(x - xs);
2358     dy = (float)fabs(y - ys);
2359     if (dx > dy) {
2360         /* Vertical edge: x-coord of corner,
2361          * y-coord of square centre. */
2362         *xr = 2 * (int)xv;
2363         *yr = 1 + 2 * (int)floor(ys);
2364     } else {
2365         /* Horizontal edge: x-coord of square centre,
2366          * y-coord of corner. */
2367         *xr = 1 + 2 * (int)floor(xs);
2368         *yr = 2 * (int)yv;
2369     }
2370 }
2371 #endif
2372
2373 #ifdef EDITOR
2374 static char *interpret_move(const game_state *state, game_ui *ui,
2375                             const game_drawstate *ds,
2376                             int x, int y, int button)
2377 {
2378     char buf[80];
2379     int px, py;
2380     struct space *sp;
2381
2382     px = 2*FROMCOORD((float)x) + 0.5;
2383     py = 2*FROMCOORD((float)y) + 0.5;
2384
2385     state->cdiff = -1;
2386
2387     if (button == 'C' || button == 'c') return dupstr("C");
2388
2389     if (button == 'S' || button == 's') {
2390         char *ret;
2391         game_state *tmp = dup_game(state);
2392         state->cdiff = solver_state(tmp, DIFF_UNREASONABLE-1);
2393         ret = diff_game(state, tmp, 0);
2394         free_game(tmp);
2395         return ret;
2396     }
2397
2398     if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
2399         if (!INUI(state, px, py)) return NULL;
2400         sp = &SPACE(state, px, py);
2401         if (!dot_is_possible(state, sp, 1)) return NULL;
2402         sprintf(buf, "%c%d,%d",
2403                 (char)((button == LEFT_BUTTON) ? 'D' : 'd'), px, py);
2404         return dupstr(buf);
2405     }
2406
2407     return NULL;
2408 }
2409 #else
2410 static char *interpret_move(const game_state *state, game_ui *ui,
2411                             const game_drawstate *ds,
2412                             int x, int y, int button)
2413 {
2414     /* UI operations (play mode):
2415      *
2416      * Toggle edge (set/unset) (left-click on edge)
2417      * Associate space with dot (left-drag from dot)
2418      * Unassociate space (left-drag from space off grid)
2419      * Autofill lines around shape? (right-click?)
2420      *
2421      * (edit mode; will clear all lines/associations)
2422      *
2423      * Add or remove dot (left-click)
2424      */
2425     char buf[80];
2426     const char *sep = "";
2427     int px, py;
2428     struct space *sp, *dot;
2429
2430     buf[0] = '\0';
2431
2432     if (button == 'H' || button == 'h') {
2433         char *ret;
2434         game_state *tmp = dup_game(state);
2435         solver_obvious(tmp);
2436         ret = diff_game(state, tmp, 0);
2437         free_game(tmp);
2438         return ret;
2439     }
2440
2441     if (button == LEFT_BUTTON) {
2442         ui->cur_visible = 0;
2443         coord_round_to_edge(FROMCOORD((float)x), FROMCOORD((float)y),
2444                             &px, &py);
2445
2446         if (!INUI(state, px, py)) return NULL;
2447
2448         sp = &SPACE(state, px, py);
2449         assert(sp->type == s_edge);
2450         {
2451             sprintf(buf, "E%d,%d", px, py);
2452             return dupstr(buf);
2453         }
2454     } else if (button == RIGHT_BUTTON) {
2455         int px1, py1;
2456
2457         ui->cur_visible = 0;
2458
2459         px = (int)(2*FROMCOORD((float)x) + 0.5);
2460         py = (int)(2*FROMCOORD((float)y) + 0.5);
2461
2462         dot = NULL;
2463
2464         /*
2465          * If there's a dot anywhere nearby, we pick up an arrow
2466          * pointing at that dot.
2467          */
2468         for (py1 = py-1; py1 <= py+1; py1++)
2469             for (px1 = px-1; px1 <= px+1; px1++) {
2470                 if (px1 >= 0 && px1 < state->sx &&
2471                     py1 >= 0 && py1 < state->sy &&
2472                     x >= SCOORD(px1-1) && x < SCOORD(px1+1) &&
2473                     y >= SCOORD(py1-1) && y < SCOORD(py1+1) &&
2474                     SPACE(state, px1, py1).flags & F_DOT) {
2475                     /*
2476                      * Found a dot. Begin a drag from it.
2477                      */
2478                     dot = &SPACE(state, px1, py1);
2479                     ui->srcx = px1;
2480                     ui->srcy = py1;
2481                     goto done;         /* multi-level break */
2482                 }
2483             }
2484
2485         /*
2486          * Otherwise, find the nearest _square_, and pick up the
2487          * same arrow as it's got on it, if any.
2488          */
2489         if (!dot) {
2490             px = 2*FROMCOORD(x+TILE_SIZE) - 1;
2491             py = 2*FROMCOORD(y+TILE_SIZE) - 1;
2492             if (px >= 0 && px < state->sx && py >= 0 && py < state->sy) {
2493                 sp = &SPACE(state, px, py);
2494                 if (sp->flags & F_TILE_ASSOC) {
2495                     dot = &SPACE(state, sp->dotx, sp->doty);
2496                     ui->srcx = px;
2497                     ui->srcy = py;
2498                 }
2499             }
2500         }
2501
2502         done:
2503         /*
2504          * Now, if we've managed to find a dot, begin a drag.
2505          */
2506         if (dot) {
2507             ui->dragging = TRUE;
2508             ui->dx = x;
2509             ui->dy = y;
2510             ui->dotx = dot->x;
2511             ui->doty = dot->y;
2512             return "";
2513         }
2514     } else if (button == RIGHT_DRAG && ui->dragging) {
2515         /* just move the drag coords. */
2516         ui->dx = x;
2517         ui->dy = y;
2518         return "";
2519     } else if (button == RIGHT_RELEASE && ui->dragging) {
2520         ui->dragging = FALSE;
2521
2522         /*
2523          * Drags are always targeted at a single square.
2524          */
2525         px = 2*FROMCOORD(x+TILE_SIZE) - 1;
2526         py = 2*FROMCOORD(y+TILE_SIZE) - 1;
2527
2528         /*
2529          * Dragging an arrow on to the same square it started from
2530          * is a null move; just update the ui and finish.
2531          */
2532         if (px == ui->srcx && py == ui->srcy)
2533             return "";
2534
2535         /*
2536          * Otherwise, we remove the arrow from its starting
2537          * square if we didn't start from a dot...
2538          */
2539         if ((ui->srcx != ui->dotx || ui->srcy != ui->doty) &&
2540             SPACE(state, ui->srcx, ui->srcy).flags & F_TILE_ASSOC) {
2541             sprintf(buf + strlen(buf), "%sU%d,%d", sep, ui->srcx, ui->srcy);
2542             sep = ";";
2543         }
2544
2545         /*
2546          * ... and if the square we're moving it _to_ is valid, we
2547          * add one there instead.
2548          */
2549         if (INUI(state, px, py)) {
2550             sp = &SPACE(state, px, py);
2551
2552             if (!(sp->flags & F_DOT) && !(sp->flags & F_TILE_ASSOC))
2553                 sprintf(buf + strlen(buf), "%sA%d,%d,%d,%d",
2554                         sep, px, py, ui->dotx, ui->doty);
2555         }
2556
2557         if (buf[0])
2558             return dupstr(buf);
2559         else
2560             return "";
2561     } else if (IS_CURSOR_MOVE(button)) {
2562         move_cursor(button, &ui->cur_x, &ui->cur_y, state->sx-1, state->sy-1, 0);
2563         if (ui->cur_x < 1) ui->cur_x = 1;
2564         if (ui->cur_y < 1) ui->cur_y = 1;
2565         ui->cur_visible = 1;
2566         if (ui->dragging) {
2567             ui->dx = SCOORD(ui->cur_x);
2568             ui->dy = SCOORD(ui->cur_y);
2569         }
2570         return "";
2571     } else if (IS_CURSOR_SELECT(button)) {
2572         if (!ui->cur_visible) {
2573             ui->cur_visible = 1;
2574             return "";
2575         }
2576         sp = &SPACE(state, ui->cur_x, ui->cur_y);
2577         if (ui->dragging) {
2578             ui->dragging = FALSE;
2579
2580             if ((ui->srcx != ui->dotx || ui->srcy != ui->doty) &&
2581                 SPACE(state, ui->srcx, ui->srcy).flags & F_TILE_ASSOC) {
2582                 sprintf(buf, "%sU%d,%d", sep, ui->srcx, ui->srcy);
2583                 sep = ";";
2584             }
2585             if (sp->type == s_tile && !(sp->flags & F_DOT) && !(sp->flags & F_TILE_ASSOC)) {
2586                 sprintf(buf + strlen(buf), "%sA%d,%d,%d,%d",
2587                         sep, ui->cur_x, ui->cur_y, ui->dotx, ui->doty);
2588             }
2589             return dupstr(buf);
2590         } else if (sp->flags & F_DOT) {
2591             ui->dragging = TRUE;
2592             ui->dx = SCOORD(ui->cur_x);
2593             ui->dy = SCOORD(ui->cur_y);
2594             ui->dotx = ui->srcx = ui->cur_x;
2595             ui->doty = ui->srcy = ui->cur_y;
2596             return "";
2597         } else if (sp->flags & F_TILE_ASSOC) {
2598             assert(sp->type == s_tile);
2599             ui->dragging = TRUE;
2600             ui->dx = SCOORD(ui->cur_x);
2601             ui->dy = SCOORD(ui->cur_y);
2602             ui->dotx = sp->dotx;
2603             ui->doty = sp->doty;
2604             ui->srcx = ui->cur_x;
2605             ui->srcy = ui->cur_y;
2606             return "";
2607         } else if (sp->type == s_edge) {
2608             sprintf(buf, "E%d,%d", ui->cur_x, ui->cur_y);
2609             return dupstr(buf);
2610         }
2611     }
2612
2613     return NULL;
2614 }
2615 #endif
2616
2617 static int check_complete(const game_state *state, int *dsf, int *colours)
2618 {
2619     int w = state->w, h = state->h;
2620     int x, y, i, ret;
2621
2622     int free_dsf;
2623     struct sqdata {
2624         int minx, miny, maxx, maxy;
2625         int cx, cy;
2626         int valid, colour;
2627     } *sqdata;
2628
2629     if (!dsf) {
2630         dsf = snew_dsf(w*h);
2631         free_dsf = TRUE;
2632     } else {
2633         dsf_init(dsf, w*h);
2634         free_dsf = FALSE;
2635     }
2636
2637     /*
2638      * During actual game play, completion checking is done on the
2639      * basis of the edges rather than the square associations. So
2640      * first we must go through the grid figuring out the connected
2641      * components into which the edges divide it.
2642      */
2643     for (y = 0; y < h; y++)
2644         for (x = 0; x < w; x++) {
2645             if (y+1 < h && !(SPACE(state, 2*x+1, 2*y+2).flags & F_EDGE_SET))
2646                 dsf_merge(dsf, y*w+x, (y+1)*w+x);
2647             if (x+1 < w && !(SPACE(state, 2*x+2, 2*y+1).flags & F_EDGE_SET))
2648                 dsf_merge(dsf, y*w+x, y*w+(x+1));
2649         }
2650
2651     /*
2652      * That gives us our connected components. Now, for each
2653      * component, decide whether it's _valid_. A valid component is
2654      * one which:
2655      *
2656      *  - is 180-degree rotationally symmetric
2657      *  - has a dot at its centre of symmetry
2658      *  - has no other dots anywhere within it (including on its
2659      *    boundary)
2660      *  - contains no internal edges (i.e. edges separating two
2661      *    squares which are both part of the component).
2662      */
2663
2664     /*
2665      * First, go through the grid finding the bounding box of each
2666      * component.
2667      */
2668     sqdata = snewn(w*h, struct sqdata);
2669     for (i = 0; i < w*h; i++) {
2670         sqdata[i].minx = w+1;
2671         sqdata[i].miny = h+1;
2672         sqdata[i].maxx = sqdata[i].maxy = -1;
2673         sqdata[i].valid = FALSE;
2674     }
2675     for (y = 0; y < h; y++)
2676         for (x = 0; x < w; x++) {
2677             i = dsf_canonify(dsf, y*w+x);
2678             if (sqdata[i].minx > x)
2679                 sqdata[i].minx = x;
2680             if (sqdata[i].maxx < x)
2681                 sqdata[i].maxx = x;
2682             if (sqdata[i].miny > y)
2683                 sqdata[i].miny = y;
2684             if (sqdata[i].maxy < y)
2685                 sqdata[i].maxy = y;
2686             sqdata[i].valid = TRUE;
2687         }
2688
2689     /*
2690      * Now we're in a position to loop over each actual component
2691      * and figure out where its centre of symmetry has to be if
2692      * it's anywhere.
2693      */
2694     for (i = 0; i < w*h; i++)
2695         if (sqdata[i].valid) {
2696             int cx, cy;
2697             cx = sqdata[i].cx = sqdata[i].minx + sqdata[i].maxx + 1;
2698             cy = sqdata[i].cy = sqdata[i].miny + sqdata[i].maxy + 1;
2699             if (!(SPACE(state, sqdata[i].cx, sqdata[i].cy).flags & F_DOT))
2700                 sqdata[i].valid = FALSE;   /* no dot at centre of symmetry */
2701             if (dsf_canonify(dsf, (cy-1)/2*w+(cx-1)/2) != i ||
2702                 dsf_canonify(dsf, (cy)/2*w+(cx-1)/2) != i ||
2703                 dsf_canonify(dsf, (cy-1)/2*w+(cx)/2) != i ||
2704                 dsf_canonify(dsf, (cy)/2*w+(cx)/2) != i)
2705                 sqdata[i].valid = FALSE;   /* dot at cx,cy isn't ours */
2706             if (SPACE(state, sqdata[i].cx, sqdata[i].cy).flags & F_DOT_BLACK)
2707                 sqdata[i].colour = 2;
2708             else
2709                 sqdata[i].colour = 1;
2710         }
2711
2712     /*
2713      * Now we loop over the whole grid again, this time finding
2714      * extraneous dots (any dot which wholly or partially overlaps
2715      * a square and is not at the centre of symmetry of that
2716      * square's component disqualifies the component from validity)
2717      * and extraneous edges (any edge separating two squares
2718      * belonging to the same component also disqualifies that
2719      * component).
2720      */
2721     for (y = 1; y < state->sy-1; y++)
2722         for (x = 1; x < state->sx-1; x++) {
2723             space *sp = &SPACE(state, x, y);
2724
2725             if (sp->flags & F_DOT) {
2726                 /*
2727                  * There's a dot here. Use it to disqualify any
2728                  * component which deserves it.
2729                  */
2730                 int cx, cy;
2731                 for (cy = (y-1) >> 1; cy <= y >> 1; cy++)
2732                     for (cx = (x-1) >> 1; cx <= x >> 1; cx++) {
2733                         i = dsf_canonify(dsf, cy*w+cx);
2734                         if (x != sqdata[i].cx || y != sqdata[i].cy)
2735                             sqdata[i].valid = FALSE;
2736                     }
2737             }
2738
2739             if (sp->flags & F_EDGE_SET) {
2740                 /*
2741                  * There's an edge here. Use it to disqualify a
2742                  * component if necessary.
2743                  */
2744                 int cx1 = (x-1) >> 1, cx2 = x >> 1;
2745                 int cy1 = (y-1) >> 1, cy2 = y >> 1;
2746                 assert((cx1==cx2) ^ (cy1==cy2));
2747                 i = dsf_canonify(dsf, cy1*w+cx1);
2748                 if (i == dsf_canonify(dsf, cy2*w+cx2))
2749                     sqdata[i].valid = FALSE;
2750             }
2751         }
2752
2753     /*
2754      * And finally we test rotational symmetry: for each square in
2755      * the grid, find which component it's in, test that that
2756      * component also has a square in the symmetric position, and
2757      * disqualify it if it doesn't.
2758      */
2759     for (y = 0; y < h; y++)
2760         for (x = 0; x < w; x++) {
2761             int x2, y2;
2762
2763             i = dsf_canonify(dsf, y*w+x);
2764
2765             x2 = sqdata[i].cx - 1 - x;
2766             y2 = sqdata[i].cy - 1 - y;
2767             if (i != dsf_canonify(dsf, y2*w+x2))
2768                 sqdata[i].valid = FALSE;
2769         }
2770
2771     /*
2772      * That's it. We now have all the connected components marked
2773      * as valid or not valid. So now we return a `colours' array if
2774      * we were asked for one, and also we return an overall
2775      * true/false value depending on whether _every_ square in the
2776      * grid is part of a valid component.
2777      */
2778     ret = TRUE;
2779     for (i = 0; i < w*h; i++) {
2780         int ci = dsf_canonify(dsf, i);
2781         int thisok = sqdata[ci].valid;
2782         if (colours)
2783             colours[i] = thisok ? sqdata[ci].colour : 0;
2784         ret = ret && thisok;
2785     }
2786
2787     sfree(sqdata);
2788     if (free_dsf)
2789         sfree(dsf);
2790
2791     return ret;
2792 }
2793
2794 static game_state *execute_move(const game_state *state, const char *move)
2795 {
2796     int x, y, ax, ay, n, dx, dy;
2797     game_state *ret = dup_game(state);
2798     struct space *sp, *dot;
2799
2800     debug(("%s\n", move));
2801
2802     while (*move) {
2803         char c = *move;
2804         if (c == 'E' || c == 'U' || c == 'M'
2805 #ifdef EDITOR
2806             || c == 'D' || c == 'd'
2807 #endif
2808             ) {
2809             move++;
2810             if (sscanf(move, "%d,%d%n", &x, &y, &n) != 2 ||
2811                 !INUI(state, x, y))
2812                 goto badmove;
2813
2814             sp = &SPACE(ret, x, y);
2815 #ifdef EDITOR
2816             if (c == 'D' || c == 'd') {
2817                 unsigned int currf, newf, maskf;
2818
2819                 if (!dot_is_possible(state, sp, 1)) goto badmove;
2820
2821                 newf = F_DOT | (c == 'd' ? F_DOT_BLACK : 0);
2822                 currf = GRID(ret, grid, x, y).flags;
2823                 maskf = F_DOT | F_DOT_BLACK;
2824                 /* if we clicked 'white dot':
2825                  *   white --> empty, empty --> white, black --> white.
2826                  * if we clicker 'black dot':
2827                  *   black --> empty, empty --> black, white --> black.
2828                  */
2829                 if (currf & maskf) {
2830                     sp->flags &= ~maskf;
2831                     if ((currf & maskf) != newf)
2832                         sp->flags |= newf;
2833                 } else
2834                     sp->flags |= newf;
2835                 sp->nassoc = 0; /* edit-mode disallows associations. */
2836                 game_update_dots(ret);
2837             } else
2838 #endif
2839                    if (c == 'E') {
2840                 if (sp->type != s_edge) goto badmove;
2841                 sp->flags ^= F_EDGE_SET;
2842             } else if (c == 'U') {
2843                 if (sp->type != s_tile || !(sp->flags & F_TILE_ASSOC))
2844                     goto badmove;
2845                 remove_assoc(ret, sp);
2846             } else if (c == 'M') {
2847                 if (!(sp->flags & F_DOT)) goto badmove;
2848                 sp->flags ^= F_DOT_HOLD;
2849             }
2850             move += n;
2851         } else if (c == 'A' || c == 'a') {
2852             move++;
2853             if (sscanf(move, "%d,%d,%d,%d%n", &x, &y, &ax, &ay, &n) != 4 ||
2854                 x < 1 || y < 1 || x >= (state->sx-1) || y >= (state->sy-1) ||
2855                 ax < 1 || ay < 1 || ax >= (state->sx-1) || ay >= (state->sy-1))
2856                 goto badmove;
2857
2858             dot = &GRID(ret, grid, ax, ay);
2859             if (!(dot->flags & F_DOT))goto badmove;
2860             if (dot->flags & F_DOT_HOLD) goto badmove;
2861
2862             for (dx = -1; dx <= 1; dx++) {
2863                 for (dy = -1; dy <= 1; dy++) {
2864                     sp = &GRID(ret, grid, x+dx, y+dy);
2865                     if (sp->type != s_tile) continue;
2866                     if (sp->flags & F_TILE_ASSOC) {
2867                         space *dot = &SPACE(state, sp->dotx, sp->doty);
2868                         if (dot->flags & F_DOT_HOLD) continue;
2869                     }
2870                     add_assoc(state, sp, dot);
2871                 }
2872             }
2873             move += n;
2874 #ifdef EDITOR
2875         } else if (c == 'C') {
2876             move++;
2877             clear_game(ret, 1);
2878 #endif
2879         } else if (c == 'S') {
2880             move++;
2881             ret->used_solve = 1;
2882         } else
2883             goto badmove;
2884
2885         if (*move == ';')
2886             move++;
2887         else if (*move)
2888             goto badmove;
2889     }
2890     if (check_complete(ret, NULL, NULL))
2891         ret->completed = 1;
2892     return ret;
2893
2894 badmove:
2895     free_game(ret);
2896     return NULL;
2897 }
2898
2899 /* ----------------------------------------------------------------------
2900  * Drawing routines.
2901  */
2902
2903 /* Lines will be much smaller size than squares; say, 1/8 the size?
2904  *
2905  * Need a 'top-left corner of location XxY' to take this into account;
2906  * alternaticaly, that could give the middle of that location, and the
2907  * drawing code would just know the expected dimensions.
2908  *
2909  * We also need something to take a click and work out what it was
2910  * we were interested in. Clicking on vertices is required because
2911  * we may want to drag from them, for example.
2912  */
2913
2914 static void game_compute_size(const game_params *params, int sz,
2915                               int *x, int *y)
2916 {
2917     struct { int tilesize, w, h; } ads, *ds = &ads;
2918
2919     ds->tilesize = sz;
2920     ds->w = params->w;
2921     ds->h = params->h;
2922
2923     *x = DRAW_WIDTH;
2924     *y = DRAW_HEIGHT;
2925 }
2926
2927 static void game_set_size(drawing *dr, game_drawstate *ds,
2928                           const game_params *params, int sz)
2929 {
2930     ds->tilesize = sz;
2931
2932     assert(TILE_SIZE > 0);
2933
2934     assert(!ds->bl);
2935     ds->bl = blitter_new(dr, TILE_SIZE, TILE_SIZE);
2936
2937     assert(!ds->cur_bl);
2938     ds->cur_bl = blitter_new(dr, TILE_SIZE, TILE_SIZE);
2939 }
2940
2941 static float *game_colours(frontend *fe, int *ncolours)
2942 {
2943     float *ret = snewn(3 * NCOLOURS, float);
2944     int i;
2945
2946     /*
2947      * We call game_mkhighlight to ensure the background colour
2948      * isn't completely white. We don't actually use the high- and
2949      * lowlight colours it generates.
2950      */
2951     game_mkhighlight(fe, ret, COL_BACKGROUND, COL_WHITEBG, COL_BLACKBG);
2952
2953     for (i = 0; i < 3; i++) {
2954         /*
2955          * Currently, white dots and white-background squares are
2956          * both pure white.
2957          */
2958         ret[COL_WHITEDOT * 3 + i] = 1.0F;
2959         ret[COL_WHITEBG * 3 + i] = 1.0F;
2960
2961         /*
2962          * But black-background squares are a dark grey, whereas
2963          * black dots are really black.
2964          */
2965         ret[COL_BLACKDOT * 3 + i] = 0.0F;
2966         ret[COL_BLACKBG * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 0.3F;
2967
2968         /*
2969          * In unfilled squares, we draw a faint gridwork.
2970          */
2971         ret[COL_GRID * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 0.8F;
2972
2973         /*
2974          * Edges and arrows are filled in in pure black.
2975          */
2976         ret[COL_EDGE * 3 + i] = 0.0F;
2977         ret[COL_ARROW * 3 + i] = 0.0F;
2978     }
2979
2980 #ifdef EDITOR
2981     /* tinge the edit background to bluey */
2982     ret[COL_BACKGROUND * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.8F;
2983     ret[COL_BACKGROUND * 3 + 1] = ret[COL_BACKGROUND * 3 + 0] * 0.8F;
2984     ret[COL_BACKGROUND * 3 + 2] = min(ret[COL_BACKGROUND * 3 + 0] * 1.4F, 1.0F);
2985 #endif
2986
2987     ret[COL_CURSOR * 3 + 0] = min(ret[COL_BACKGROUND * 3 + 0] * 1.4F, 1.0F);
2988     ret[COL_CURSOR * 3 + 1] = ret[COL_BACKGROUND * 3 + 0] * 0.8F;
2989     ret[COL_CURSOR * 3 + 2] = ret[COL_BACKGROUND * 3 + 0] * 0.8F;
2990
2991     *ncolours = NCOLOURS;
2992     return ret;
2993 }
2994
2995 static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
2996 {
2997     struct game_drawstate *ds = snew(struct game_drawstate);
2998     int i;
2999
3000     ds->started = 0;
3001     ds->w = state->w;
3002     ds->h = state->h;
3003
3004     ds->grid = snewn(ds->w*ds->h, unsigned long);
3005     for (i = 0; i < ds->w*ds->h; i++)
3006         ds->grid[i] = 0xFFFFFFFFUL;
3007     ds->dx = snewn(ds->w*ds->h, int);
3008     ds->dy = snewn(ds->w*ds->h, int);
3009
3010     ds->bl = NULL;
3011     ds->dragging = FALSE;
3012     ds->dragx = ds->dragy = 0;
3013
3014     ds->colour_scratch = snewn(ds->w * ds->h, int);
3015
3016     ds->cur_bl = NULL;
3017     ds->cx = ds->cy = 0;
3018     ds->cur_visible = 0;
3019
3020     return ds;
3021 }
3022
3023 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
3024 {
3025     if (ds->cur_bl) blitter_free(dr, ds->cur_bl);
3026     sfree(ds->colour_scratch);
3027     if (ds->bl) blitter_free(dr, ds->bl);
3028     sfree(ds->dx);
3029     sfree(ds->dy);
3030     sfree(ds->grid);
3031     sfree(ds);
3032 }
3033
3034 #define DRAW_EDGE_L    0x0001
3035 #define DRAW_EDGE_R    0x0002
3036 #define DRAW_EDGE_U    0x0004
3037 #define DRAW_EDGE_D    0x0008
3038 #define DRAW_CORNER_UL 0x0010
3039 #define DRAW_CORNER_UR 0x0020
3040 #define DRAW_CORNER_DL 0x0040
3041 #define DRAW_CORNER_DR 0x0080
3042 #define DRAW_WHITE     0x0100
3043 #define DRAW_BLACK     0x0200
3044 #define DRAW_ARROW     0x0400
3045 #define DRAW_CURSOR    0x0800
3046 #define DOT_SHIFT_C    12
3047 #define DOT_SHIFT_M    2
3048 #define DOT_WHITE      1UL
3049 #define DOT_BLACK      2UL
3050
3051 /*
3052  * Draw an arrow centred on (cx,cy), pointing in the direction
3053  * (ddx,ddy). (I.e. pointing at the point (cx+ddx, cy+ddy).
3054  */
3055 static void draw_arrow(drawing *dr, game_drawstate *ds,
3056                        int cx, int cy, int ddx, int ddy, int col)
3057 {
3058     float vlen = (float)sqrt(ddx*ddx+ddy*ddy);
3059     float xdx = ddx/vlen, xdy = ddy/vlen;
3060     float ydx = -xdy, ydy = xdx;
3061     int e1x = cx + (int)(xdx*TILE_SIZE/3), e1y = cy + (int)(xdy*TILE_SIZE/3);
3062     int e2x = cx - (int)(xdx*TILE_SIZE/3), e2y = cy - (int)(xdy*TILE_SIZE/3);
3063     int adx = (int)((ydx-xdx)*TILE_SIZE/8), ady = (int)((ydy-xdy)*TILE_SIZE/8);
3064     int adx2 = (int)((-ydx-xdx)*TILE_SIZE/8), ady2 = (int)((-ydy-xdy)*TILE_SIZE/8);
3065
3066     draw_line(dr, e1x, e1y, e2x, e2y, col);
3067     draw_line(dr, e1x, e1y, e1x+adx, e1y+ady, col);
3068     draw_line(dr, e1x, e1y, e1x+adx2, e1y+ady2, col);
3069 }
3070
3071 static void draw_square(drawing *dr, game_drawstate *ds, int x, int y,
3072                         unsigned long flags, int ddx, int ddy)
3073 {
3074     int lx = COORD(x), ly = COORD(y);
3075     int dx, dy;
3076     int gridcol;
3077
3078     clip(dr, lx, ly, TILE_SIZE, TILE_SIZE);
3079
3080     /*
3081      * Draw the tile background.
3082      */
3083     draw_rect(dr, lx, ly, TILE_SIZE, TILE_SIZE,
3084               (flags & DRAW_WHITE ? COL_WHITEBG :
3085                flags & DRAW_BLACK ? COL_BLACKBG : COL_BACKGROUND));
3086
3087     /*
3088      * Draw the grid.
3089      */
3090     gridcol = (flags & DRAW_BLACK ? COL_BLACKDOT : COL_GRID);
3091     draw_rect(dr, lx, ly, 1, TILE_SIZE, gridcol);
3092     draw_rect(dr, lx, ly, TILE_SIZE, 1, gridcol);
3093
3094     /*
3095      * Draw the arrow, if present, or the cursor, if here.
3096      */
3097     if (flags & DRAW_ARROW)
3098         draw_arrow(dr, ds, lx + TILE_SIZE/2, ly + TILE_SIZE/2, ddx, ddy,
3099                    (flags & DRAW_CURSOR) ? COL_CURSOR : COL_ARROW);
3100     else if (flags & DRAW_CURSOR)
3101         draw_rect_outline(dr,
3102                           lx + TILE_SIZE/2 - CURSOR_SIZE,
3103                           ly + TILE_SIZE/2 - CURSOR_SIZE,
3104                           2*CURSOR_SIZE+1, 2*CURSOR_SIZE+1,
3105                           COL_CURSOR);
3106
3107     /*
3108      * Draw the edges.
3109      */
3110     if (flags & DRAW_EDGE_L)
3111         draw_rect(dr, lx, ly, EDGE_THICKNESS, TILE_SIZE, COL_EDGE);
3112     if (flags & DRAW_EDGE_R)
3113         draw_rect(dr, lx + TILE_SIZE - EDGE_THICKNESS + 1, ly,
3114                   EDGE_THICKNESS - 1, TILE_SIZE, COL_EDGE);
3115     if (flags & DRAW_EDGE_U)
3116         draw_rect(dr, lx, ly, TILE_SIZE, EDGE_THICKNESS, COL_EDGE);
3117     if (flags & DRAW_EDGE_D)
3118         draw_rect(dr, lx, ly + TILE_SIZE - EDGE_THICKNESS + 1,
3119                   TILE_SIZE, EDGE_THICKNESS - 1, COL_EDGE);
3120     if (flags & DRAW_CORNER_UL)
3121         draw_rect(dr, lx, ly, EDGE_THICKNESS, EDGE_THICKNESS, COL_EDGE);
3122     if (flags & DRAW_CORNER_UR)
3123         draw_rect(dr, lx + TILE_SIZE - EDGE_THICKNESS + 1, ly,
3124                   EDGE_THICKNESS - 1, EDGE_THICKNESS, COL_EDGE);
3125     if (flags & DRAW_CORNER_DL)
3126         draw_rect(dr, lx, ly + TILE_SIZE - EDGE_THICKNESS + 1,
3127                   EDGE_THICKNESS, EDGE_THICKNESS - 1, COL_EDGE);
3128     if (flags & DRAW_CORNER_DR)
3129         draw_rect(dr, lx + TILE_SIZE - EDGE_THICKNESS + 1,
3130                   ly + TILE_SIZE - EDGE_THICKNESS + 1,
3131                   EDGE_THICKNESS - 1, EDGE_THICKNESS - 1, COL_EDGE);
3132
3133     /*
3134      * Draw the dots.
3135      */
3136     for (dy = 0; dy < 3; dy++)
3137         for (dx = 0; dx < 3; dx++) {
3138             int dotval = (flags >> (DOT_SHIFT_C + DOT_SHIFT_M*(dy*3+dx)));
3139             dotval &= (1 << DOT_SHIFT_M)-1;
3140
3141             if (dotval)
3142                 draw_circle(dr, lx+dx*TILE_SIZE/2, ly+dy*TILE_SIZE/2,
3143                             DOT_SIZE,
3144                             (dotval == 1 ? COL_WHITEDOT : COL_BLACKDOT),
3145                             COL_BLACKDOT);
3146         }
3147
3148     unclip(dr);
3149     draw_update(dr, lx, ly, TILE_SIZE, TILE_SIZE);
3150 }
3151
3152 static void game_redraw(drawing *dr, game_drawstate *ds,
3153                         const game_state *oldstate, const game_state *state,
3154                         int dir, const game_ui *ui,
3155                         float animtime, float flashtime)
3156 {
3157     int w = ds->w, h = ds->h;
3158     int x, y, flashing = FALSE;
3159
3160     if (flashtime > 0) {
3161         int frame = (int)(flashtime / FLASH_TIME);
3162         flashing = (frame % 2 == 0);
3163     }
3164
3165     if (ds->dragging) {
3166         assert(ds->bl);
3167         blitter_load(dr, ds->bl, ds->dragx, ds->dragy);
3168         draw_update(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE);
3169         ds->dragging = FALSE;
3170     }
3171     if (ds->cur_visible) {
3172         assert(ds->cur_bl);
3173         blitter_load(dr, ds->cur_bl, ds->cx, ds->cy);
3174         draw_update(dr, ds->cx, ds->cy, CURSOR_SIZE*2+1, CURSOR_SIZE*2+1);
3175         ds->cur_visible = FALSE;
3176     }
3177
3178     if (!ds->started) {
3179         draw_rect(dr, 0, 0, DRAW_WIDTH, DRAW_HEIGHT, COL_BACKGROUND);
3180         draw_rect(dr, BORDER - EDGE_THICKNESS + 1, BORDER - EDGE_THICKNESS + 1,
3181                   w*TILE_SIZE + EDGE_THICKNESS*2 - 1,
3182                   h*TILE_SIZE + EDGE_THICKNESS*2 - 1, COL_EDGE);
3183         draw_update(dr, 0, 0, DRAW_WIDTH, DRAW_HEIGHT);
3184         ds->started = TRUE;
3185     }
3186
3187     check_complete(state, NULL, ds->colour_scratch);
3188
3189     for (y = 0; y < h; y++)
3190         for (x = 0; x < w; x++) {
3191             unsigned long flags = 0;
3192             int ddx = 0, ddy = 0;
3193             space *sp;
3194             int dx, dy;
3195
3196             /*
3197              * Set up the flags for this square. Firstly, see if we
3198              * have edges.
3199              */
3200             if (SPACE(state, x*2, y*2+1).flags & F_EDGE_SET)
3201                 flags |= DRAW_EDGE_L;
3202             if (SPACE(state, x*2+2, y*2+1).flags & F_EDGE_SET)
3203                 flags |= DRAW_EDGE_R;
3204             if (SPACE(state, x*2+1, y*2).flags & F_EDGE_SET)
3205                 flags |= DRAW_EDGE_U;
3206             if (SPACE(state, x*2+1, y*2+2).flags & F_EDGE_SET)
3207                 flags |= DRAW_EDGE_D;
3208
3209             /*
3210              * Also, mark corners of neighbouring edges.
3211              */
3212             if ((x > 0 && SPACE(state, x*2-1, y*2).flags & F_EDGE_SET) ||
3213                 (y > 0 && SPACE(state, x*2, y*2-1).flags & F_EDGE_SET))
3214                 flags |= DRAW_CORNER_UL;
3215             if ((x+1 < w && SPACE(state, x*2+3, y*2).flags & F_EDGE_SET) ||
3216                 (y > 0 && SPACE(state, x*2+2, y*2-1).flags & F_EDGE_SET))
3217                 flags |= DRAW_CORNER_UR;
3218             if ((x > 0 && SPACE(state, x*2-1, y*2+2).flags & F_EDGE_SET) ||
3219                 (y+1 < h && SPACE(state, x*2, y*2+3).flags & F_EDGE_SET))
3220                 flags |= DRAW_CORNER_DL;
3221             if ((x+1 < w && SPACE(state, x*2+3, y*2+2).flags & F_EDGE_SET) ||
3222                 (y+1 < h && SPACE(state, x*2+2, y*2+3).flags & F_EDGE_SET))
3223                 flags |= DRAW_CORNER_DR;
3224
3225             /*
3226              * If this square is part of a valid region, paint it
3227              * that region's colour. Exception: if we're flashing,
3228              * everything goes briefly back to background colour.
3229              */
3230             sp = &SPACE(state, x*2+1, y*2+1);
3231             if (ds->colour_scratch[y*w+x] && !flashing) {
3232                 flags |= (ds->colour_scratch[y*w+x] == 2 ?
3233                           DRAW_BLACK : DRAW_WHITE);
3234             }
3235
3236             /*
3237              * If this square is associated with a dot but it isn't
3238              * part of a valid region, draw an arrow in it pointing
3239              * in the direction of that dot.
3240              * 
3241              * Exception: if this is the source point of an active
3242              * drag, we don't draw the arrow.
3243              */
3244             if ((sp->flags & F_TILE_ASSOC) && !ds->colour_scratch[y*w+x]) {
3245                 if (ui->dragging && ui->srcx == x*2+1 && ui->srcy == y*2+1) {
3246                     /* don't do it */
3247                 } else if (sp->doty != y*2+1 || sp->dotx != x*2+1) {
3248                     flags |= DRAW_ARROW;
3249                     ddy = sp->doty - (y*2+1);
3250                     ddx = sp->dotx - (x*2+1);
3251                 }
3252             }
3253
3254             /*
3255              * Now go through the nine possible places we could
3256              * have dots.
3257              */
3258             for (dy = 0; dy < 3; dy++)
3259                 for (dx = 0; dx < 3; dx++) {
3260                     sp = &SPACE(state, x*2+dx, y*2+dy);
3261                     if (sp->flags & F_DOT) {
3262                         unsigned long dotval = (sp->flags & F_DOT_BLACK ?
3263                                                 DOT_BLACK : DOT_WHITE);
3264                         flags |= dotval << (DOT_SHIFT_C +
3265                                             DOT_SHIFT_M*(dy*3+dx));
3266                     }
3267                 }
3268
3269             /*
3270              * Now work out if we have to draw a cursor for this square;
3271              * cursors-on-lines are taken care of below.
3272              */
3273             if (ui->cur_visible &&
3274                 ui->cur_x == x*2+1 && ui->cur_y == y*2+1 &&
3275                 !(SPACE(state, x*2+1, y*2+1).flags & F_DOT))
3276                 flags |= DRAW_CURSOR;
3277
3278             /*
3279              * Now we have everything we're going to need. Draw the
3280              * square.
3281              */
3282             if (ds->grid[y*w+x] != flags ||
3283                 ds->dx[y*w+x] != ddx ||
3284                 ds->dy[y*w+x] != ddy) {
3285                 draw_square(dr, ds, x, y, flags, ddx, ddy);
3286                 ds->grid[y*w+x] = flags;
3287                 ds->dx[y*w+x] = ddx;
3288                 ds->dy[y*w+x] = ddy;
3289             }
3290         }
3291
3292     /*
3293      * Draw a cursor. This secondary blitter is much less invasive than trying
3294      * to fix up all of the rest of the code with sufficient flags to be able to
3295      * display this sensibly.
3296      */
3297     if (ui->cur_visible) {
3298         space *sp = &SPACE(state, ui->cur_x, ui->cur_y);
3299         ds->cur_visible = TRUE;
3300         ds->cx = SCOORD(ui->cur_x) - CURSOR_SIZE;
3301         ds->cy = SCOORD(ui->cur_y) - CURSOR_SIZE;
3302         blitter_save(dr, ds->cur_bl, ds->cx, ds->cy);
3303         if (sp->flags & F_DOT) {
3304             /* draw a red dot (over the top of whatever would be there already) */
3305             draw_circle(dr, SCOORD(ui->cur_x), SCOORD(ui->cur_y), DOT_SIZE,
3306                         COL_CURSOR, COL_BLACKDOT);
3307         } else if (sp->type != s_tile) {
3308             /* draw an edge/vertex square; tile cursors are dealt with above. */
3309             int dx = (ui->cur_x % 2) ? CURSOR_SIZE : CURSOR_SIZE/3;
3310             int dy = (ui->cur_y % 2) ? CURSOR_SIZE : CURSOR_SIZE/3;
3311             int x1 = SCOORD(ui->cur_x)-dx, y1 = SCOORD(ui->cur_y)-dy;
3312             int xs = dx*2+1, ys = dy*2+1;
3313
3314             draw_rect(dr, x1, y1, xs, ys, COL_CURSOR);
3315         }
3316         draw_update(dr, ds->cx, ds->cy, CURSOR_SIZE*2+1, CURSOR_SIZE*2+1);
3317     }
3318
3319     if (ui->dragging) {
3320         ds->dragging = TRUE;
3321         ds->dragx = ui->dx - TILE_SIZE/2;
3322         ds->dragy = ui->dy - TILE_SIZE/2;
3323         blitter_save(dr, ds->bl, ds->dragx, ds->dragy);
3324         draw_arrow(dr, ds, ui->dx, ui->dy,
3325                    SCOORD(ui->dotx) - ui->dx,
3326                    SCOORD(ui->doty) - ui->dy, COL_ARROW);
3327     }
3328 #ifdef EDITOR
3329     {
3330         char buf[256];
3331         if (state->cdiff != -1)
3332             sprintf(buf, "Puzzle is %s.", galaxies_diffnames[state->cdiff]);
3333         else
3334             buf[0] = '\0';
3335         status_bar(dr, buf);
3336     }
3337 #endif
3338 }
3339
3340 static float game_anim_length(const game_state *oldstate,
3341                               const game_state *newstate, int dir, game_ui *ui)
3342 {
3343     return 0.0F;
3344 }
3345
3346 static float game_flash_length(const game_state *oldstate,
3347                                const game_state *newstate, int dir, game_ui *ui)
3348 {
3349     if ((!oldstate->completed && newstate->completed) &&
3350         !(newstate->used_solve))
3351         return 3 * FLASH_TIME;
3352     else
3353         return 0.0F;
3354 }
3355
3356 static int game_status(const game_state *state)
3357 {
3358     return state->completed ? +1 : 0;
3359 }
3360
3361 static int game_timing_state(const game_state *state, game_ui *ui)
3362 {
3363     return TRUE;
3364 }
3365
3366 #ifndef EDITOR
3367 static void game_print_size(const game_params *params, float *x, float *y)
3368 {
3369    int pw, ph;
3370
3371    /*
3372     * 8mm squares by default. (There isn't all that much detail
3373     * that needs to go in each square.)
3374     */
3375    game_compute_size(params, 800, &pw, &ph);
3376    *x = pw / 100.0F;
3377    *y = ph / 100.0F;
3378 }
3379
3380 static void game_print(drawing *dr, const game_state *state, int sz)
3381 {
3382     int w = state->w, h = state->h;
3383     int white, black, blackish;
3384     int x, y, i, j;
3385     int *colours, *dsf;
3386     int *coords = NULL;
3387     int ncoords = 0, coordsize = 0;
3388
3389     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
3390     game_drawstate ads, *ds = &ads;
3391     ds->tilesize = sz;
3392
3393     white = print_mono_colour(dr, 1);
3394     black = print_mono_colour(dr, 0);
3395     blackish = print_hatched_colour(dr, HATCH_X);
3396
3397     /*
3398      * Get the completion information.
3399      */
3400     dsf = snewn(w * h, int);
3401     colours = snewn(w * h, int);
3402     check_complete(state, dsf, colours);
3403
3404     /*
3405      * Draw the grid.
3406      */
3407     print_line_width(dr, TILE_SIZE / 64);
3408     for (x = 1; x < w; x++)
3409         draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), black);
3410     for (y = 1; y < h; y++)
3411         draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), black);
3412
3413     /*
3414      * Shade the completed regions. Just in case any particular
3415      * printing platform deals badly with adjacent
3416      * similarly-hatched regions, we'll fill each one as a single
3417      * polygon.
3418      */
3419     for (i = 0; i < w*h; i++) {
3420         j = dsf_canonify(dsf, i);
3421         if (colours[j] != 0) {
3422             int dx, dy, t;
3423
3424             /*
3425              * This is the first square we've run into belonging to
3426              * this polyomino, which means an edge of the polyomino
3427              * is certain to be to our left. (After we finish
3428              * tracing round it, we'll set the colours[] entry to
3429              * zero to prevent accidentally doing it again.)
3430              */
3431
3432             x = i % w;
3433             y = i / w;
3434             dx = -1;
3435             dy = 0;
3436             ncoords = 0;
3437             while (1) {
3438                 /*
3439                  * We are currently sitting on square (x,y), which
3440                  * we know to be in our polyomino, and we also know
3441                  * that (x+dx,y+dy) is not. The way I visualise
3442                  * this is that we're standing to the right of a
3443                  * boundary line, stretching our left arm out to
3444                  * point to the exterior square on the far side.
3445                  */
3446
3447                 /*
3448                  * First, check if we've gone round the entire
3449                  * polyomino.
3450                  */
3451                 if (ncoords > 0 &&
3452                     (x == i%w && y == i/w && dx == -1 && dy == 0))
3453                     break;
3454
3455                 /*
3456                  * Add to our coordinate list the coordinate
3457                  * backwards and to the left of where we are.
3458                  */
3459                 if (ncoords + 2 > coordsize) {
3460                     coordsize = (ncoords * 3 / 2) + 64;
3461                     coords = sresize(coords, coordsize, int);
3462                 }
3463                 coords[ncoords++] = COORD((2*x+1 + dx + dy) / 2);
3464                 coords[ncoords++] = COORD((2*y+1 + dy - dx) / 2);
3465
3466                 /*
3467                  * Follow the edge round. If the square directly in
3468                  * front of us is not part of the polyomino, we
3469                  * turn right; if it is and so is the square in
3470                  * front of (x+dx,y+dy), we turn left; otherwise we
3471                  * go straight on.
3472                  */
3473                 if (x-dy < 0 || x-dy >= w || y+dx < 0 || y+dx >= h ||
3474                     dsf_canonify(dsf, (y+dx)*w+(x-dy)) != j) {
3475                     /* Turn right. */
3476                     t = dx;
3477                     dx = -dy;
3478                     dy = t;
3479                 } else if (x+dx-dy >= 0 && x+dx-dy < w &&
3480                            y+dy+dx >= 0 && y+dy+dx < h &&
3481                            dsf_canonify(dsf, (y+dy+dx)*w+(x+dx-dy)) == j) {
3482                     /* Turn left. */
3483                     x += dx;
3484                     y += dy;
3485                     t = dx;
3486                     dx = dy;
3487                     dy = -t;
3488                     x -= dx;
3489                     y -= dy;
3490                 } else {
3491                     /* Straight on. */
3492                     x -= dy;
3493                     y += dx;
3494                 }
3495             }
3496
3497             /*
3498              * Now we have our polygon complete, so fill it.
3499              */
3500             draw_polygon(dr, coords, ncoords/2,
3501                          colours[j] == 2 ? blackish : -1, black);
3502
3503             /*
3504              * And mark this polyomino as done.
3505              */
3506             colours[j] = 0;
3507         }
3508     }
3509
3510     /*
3511      * Draw the edges.
3512      */
3513     for (y = 0; y <= h; y++)
3514         for (x = 0; x <= w; x++) {
3515             if (x < w && SPACE(state, x*2+1, y*2).flags & F_EDGE_SET)
3516                 draw_rect(dr, COORD(x)-EDGE_THICKNESS, COORD(y)-EDGE_THICKNESS,
3517                           EDGE_THICKNESS * 2 + TILE_SIZE, EDGE_THICKNESS * 2,
3518                           black);
3519             if (y < h && SPACE(state, x*2, y*2+1).flags & F_EDGE_SET)
3520                 draw_rect(dr, COORD(x)-EDGE_THICKNESS, COORD(y)-EDGE_THICKNESS,
3521                           EDGE_THICKNESS * 2, EDGE_THICKNESS * 2 + TILE_SIZE,
3522                           black);
3523         }
3524
3525     /*
3526      * Draw the dots.
3527      */
3528     for (y = 0; y <= 2*h; y++)
3529         for (x = 0; x <= 2*w; x++)
3530             if (SPACE(state, x, y).flags & F_DOT) {
3531                 draw_circle(dr, (int)COORD(x/2.0), (int)COORD(y/2.0), DOT_SIZE,
3532                             (SPACE(state, x, y).flags & F_DOT_BLACK ?
3533                              black : white), black);
3534             }
3535
3536     sfree(dsf);
3537     sfree(colours);
3538     sfree(coords);
3539 }
3540 #endif
3541
3542 #ifdef COMBINED
3543 #define thegame galaxies
3544 #endif
3545
3546 const struct game thegame = {
3547     "Galaxies", "games.galaxies", "galaxies",
3548     default_params,
3549     game_fetch_preset,
3550     decode_params,
3551     encode_params,
3552     free_params,
3553     dup_params,
3554     TRUE, game_configure, custom_params,
3555     validate_params,
3556     new_game_desc,
3557     validate_desc,
3558     new_game,
3559     dup_game,
3560     free_game,
3561 #ifdef EDITOR
3562     FALSE, NULL,
3563 #else
3564     TRUE, solve_game,
3565 #endif
3566     TRUE, game_can_format_as_text_now, game_text_format,
3567     new_ui,
3568     free_ui,
3569     encode_ui,
3570     decode_ui,
3571     game_changed_state,
3572     interpret_move,
3573     execute_move,
3574     PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
3575     game_colours,
3576     game_new_drawstate,
3577     game_free_drawstate,
3578     game_redraw,
3579     game_anim_length,
3580     game_flash_length,
3581     game_status,
3582 #ifdef EDITOR
3583     FALSE, FALSE, NULL, NULL,
3584     TRUE,                              /* wants_statusbar */
3585 #else
3586     TRUE, FALSE, game_print_size, game_print,
3587     FALSE,                             /* wants_statusbar */
3588 #endif
3589     FALSE, game_timing_state,
3590     REQUIRE_RBUTTON,                   /* flags */
3591 };
3592
3593 #ifdef STANDALONE_SOLVER
3594
3595 const char *quis;
3596
3597 #include <time.h>
3598
3599 static void usage_exit(const char *msg)
3600 {
3601     if (msg)
3602         fprintf(stderr, "%s: %s\n", quis, msg);
3603     fprintf(stderr, "Usage: %s [--seed SEED] --soak <params> | [game_id [game_id ...]]\n", quis);
3604     exit(1);
3605 }
3606
3607 static void dump_state(game_state *state)
3608 {
3609     char *temp = game_text_format(state);
3610     printf("%s\n", temp);
3611     sfree(temp);
3612 }
3613
3614 static int gen(game_params *p, random_state *rs, int debug)
3615 {
3616     char *desc;
3617     int diff;
3618     game_state *state;
3619
3620 #ifndef DEBUGGING
3621     solver_show_working = debug;
3622 #endif
3623     printf("Generating a %dx%d %s puzzle.\n",
3624            p->w, p->h, galaxies_diffnames[p->diff]);
3625
3626     desc = new_game_desc(p, rs, NULL, 0);
3627     state = new_game(NULL, p, desc);
3628     dump_state(state);
3629
3630     diff = solver_state(state, DIFF_UNREASONABLE);
3631     printf("Generated %s game %dx%d:%s\n",
3632            galaxies_diffnames[diff], p->w, p->h, desc);
3633     dump_state(state);
3634
3635     free_game(state);
3636     sfree(desc);
3637
3638     return diff;
3639 }
3640
3641 static void soak(game_params *p, random_state *rs)
3642 {
3643     time_t tt_start, tt_now, tt_last;
3644     char *desc;
3645     game_state *st;
3646     int diff, n = 0, i, diffs[DIFF_MAX], ndots = 0, nspaces = 0;
3647
3648 #ifndef DEBUGGING
3649     solver_show_working = 0;
3650 #endif
3651     tt_start = tt_now = time(NULL);
3652     for (i = 0; i < DIFF_MAX; i++) diffs[i] = 0;
3653     maxtries = 1;
3654
3655     printf("Soak-generating a %dx%d grid, max. diff %s.\n",
3656            p->w, p->h, galaxies_diffnames[p->diff]);
3657     printf("   [");
3658     for (i = 0; i < DIFF_MAX; i++)
3659         printf("%s%s", (i == 0) ? "" : ", ", galaxies_diffnames[i]);
3660     printf("]\n");
3661
3662     while (1) {
3663         desc = new_game_desc(p, rs, NULL, 0);
3664         st = new_game(NULL, p, desc);
3665         diff = solver_state(st, p->diff);
3666         nspaces += st->w*st->h;
3667         for (i = 0; i < st->sx*st->sy; i++)
3668             if (st->grid[i].flags & F_DOT) ndots++;
3669         free_game(st);
3670         sfree(desc);
3671
3672         diffs[diff]++;
3673         n++;
3674         tt_last = time(NULL);
3675         if (tt_last > tt_now) {
3676             tt_now = tt_last;
3677             printf("%d total, %3.1f/s, [",
3678                    n, (double)n / ((double)tt_now - tt_start));
3679             for (i = 0; i < DIFF_MAX; i++)
3680                 printf("%s%.1f%%", (i == 0) ? "" : ", ",
3681                        100.0 * ((double)diffs[i] / (double)n));
3682             printf("], %.1f%% dots\n",
3683                    100.0 * ((double)ndots / (double)nspaces));
3684         }
3685     }
3686 }
3687
3688 int main(int argc, char **argv)
3689 {
3690     game_params *p;
3691     char *id = NULL, *desc, *err;
3692     game_state *s;
3693     int diff, do_soak = 0, verbose = 0;
3694     random_state *rs;
3695     time_t seed = time(NULL);
3696
3697     quis = argv[0];
3698     while (--argc > 0) {
3699         char *p = *++argv;
3700         if (!strcmp(p, "-v")) {
3701             verbose = 1;
3702         } else if (!strcmp(p, "--seed")) {
3703             if (argc == 0) usage_exit("--seed needs an argument");
3704             seed = (time_t)atoi(*++argv);
3705             argc--;
3706         } else if (!strcmp(p, "--soak")) {
3707             do_soak = 1;
3708         } else if (*p == '-') {
3709             usage_exit("unrecognised option");
3710         } else {
3711             id = p;
3712         }
3713     }
3714
3715     maxtries = 50;
3716
3717     p = default_params();
3718     rs = random_new((void*)&seed, sizeof(time_t));
3719
3720     if (do_soak) {
3721         if (!id) usage_exit("need one argument for --soak");
3722         decode_params(p, *argv);
3723         soak(p, rs);
3724         return 0;
3725     }
3726
3727     if (!id) {
3728         while (1) {
3729             p->w = random_upto(rs, 15) + 3;
3730             p->h = random_upto(rs, 15) + 3;
3731             p->diff = random_upto(rs, DIFF_UNREASONABLE);
3732             diff = gen(p, rs, 0);
3733         }
3734         return 0;
3735     }
3736
3737     desc = strchr(id, ':');
3738     if (!desc) {
3739         decode_params(p, id);
3740         gen(p, rs, verbose);
3741     } else {
3742 #ifndef DEBUGGING
3743         solver_show_working = 1;
3744 #endif
3745         *desc++ = '\0';
3746         decode_params(p, id);
3747         err = validate_desc(p, desc);
3748         if (err) {
3749             fprintf(stderr, "%s: %s\n", argv[0], err);
3750             exit(1);
3751         }
3752         s = new_game(NULL, p, desc);
3753         diff = solver_state(s, DIFF_UNREASONABLE);
3754         dump_state(s);
3755         printf("Puzzle is %s.\n", galaxies_diffnames[diff]);
3756         free_game(s);
3757     }
3758
3759     free_params(p);
3760
3761     return 0;
3762 }
3763
3764 #endif
3765
3766 #ifdef STANDALONE_PICTURE_GENERATOR
3767
3768 /*
3769  * Main program for the standalone picture generator. To use it,
3770  * simply provide it with an XBM-format bitmap file (note XBM, not
3771  * XPM) on standard input, and it will output a game ID in return.
3772  * For example:
3773  *
3774  *   $ ./galaxiespicture < badly-drawn-cat.xbm
3775  *   11x11:eloMBLzFeEzLNMWifhaWYdDbixCymBbBMLoDdewGg
3776  *
3777  * If you want a puzzle with a non-standard difficulty level, pass
3778  * a partial parameters string as a command-line argument (e.g.
3779  * `./galaxiespicture du < foo.xbm', where `du' is the same suffix
3780  * which if it appeared in a random-seed game ID would set the
3781  * difficulty level to Unreasonable). However, be aware that if the
3782  * generator fails to produce an adequately difficult puzzle too
3783  * many times then it will give up and return an easier one (just
3784  * as it does during normal GUI play). To be sure you really have
3785  * the difficulty you asked for, use galaxiessolver to
3786  * double-check.
3787  * 
3788  * (Perhaps I ought to include an option to make this standalone
3789  * generator carry on looping until it really does get the right
3790  * difficulty. Hmmm.)
3791  */
3792
3793 #include <time.h>
3794
3795 int main(int argc, char **argv)
3796 {
3797     game_params *par;
3798     char *params, *desc;
3799     random_state *rs;
3800     time_t seed = time(NULL);
3801     char buf[4096];
3802     int i;
3803     int x, y;
3804
3805     par = default_params();
3806     if (argc > 1)
3807         decode_params(par, argv[1]);   /* get difficulty */
3808     par->w = par->h = -1;
3809
3810     /*
3811      * Now read an XBM file from standard input. This is simple and
3812      * hacky and will do very little error detection, so don't feed
3813      * it bogus data.
3814      */
3815     picture = NULL;
3816     x = y = 0;
3817     while (fgets(buf, sizeof(buf), stdin)) {
3818         buf[strcspn(buf, "\r\n")] = '\0';
3819         if (!strncmp(buf, "#define", 7)) {
3820             /*
3821              * Lines starting `#define' give the width and height.
3822              */
3823             char *num = buf + strlen(buf);
3824             char *symend;
3825
3826             while (num > buf && isdigit((unsigned char)num[-1]))
3827                 num--;
3828             symend = num;
3829             while (symend > buf && isspace((unsigned char)symend[-1]))
3830                 symend--;
3831
3832             if (symend-5 >= buf && !strncmp(symend-5, "width", 5))
3833                 par->w = atoi(num);
3834             else if (symend-6 >= buf && !strncmp(symend-6, "height", 6))
3835                 par->h = atoi(num);
3836         } else {
3837             /*
3838              * Otherwise, break the string up into words and take
3839              * any word of the form `0x' plus hex digits to be a
3840              * byte.
3841              */
3842             char *p, *wordstart;
3843
3844             if (!picture) {
3845                 if (par->w < 0 || par->h < 0) {
3846                     printf("failed to read width and height\n");
3847                     return 1;
3848                 }
3849                 picture = snewn(par->w * par->h, int);
3850                 for (i = 0; i < par->w * par->h; i++)
3851                     picture[i] = -1;
3852             }
3853
3854             p = buf;
3855             while (*p) {
3856                 while (*p && (*p == ',' || isspace((unsigned char)*p)))
3857                     p++;
3858                 wordstart = p;
3859                 while (*p && !(*p == ',' || *p == '}' ||
3860                                isspace((unsigned char)*p)))
3861                     p++;
3862                 if (*p)
3863                     *p++ = '\0';
3864
3865                 if (wordstart[0] == '0' &&
3866                     (wordstart[1] == 'x' || wordstart[1] == 'X') &&
3867                     !wordstart[2 + strspn(wordstart+2,
3868                                           "0123456789abcdefABCDEF")]) {
3869                     unsigned long byte = strtoul(wordstart+2, NULL, 16);
3870                     for (i = 0; i < 8; i++) {
3871                         int bit = (byte >> i) & 1;
3872                         if (y < par->h && x < par->w)
3873                             picture[y * par->w + x] = bit;
3874                         x++;
3875                     }
3876
3877                     if (x >= par->w) {
3878                         x = 0;
3879                         y++;
3880                     }
3881                 }
3882             }
3883         }
3884     }
3885
3886     for (i = 0; i < par->w * par->h; i++)
3887         if (picture[i] < 0) {
3888             fprintf(stderr, "failed to read enough bitmap data\n");
3889             return 1;
3890         }
3891
3892     rs = random_new((void*)&seed, sizeof(time_t));
3893
3894     desc = new_game_desc(par, rs, NULL, FALSE);
3895     params = encode_params(par, FALSE);
3896     printf("%s:%s\n", params, desc);
3897
3898     sfree(desc);
3899     sfree(params);
3900     free_params(par);
3901     random_free(rs);
3902
3903     return 0;
3904 }
3905
3906 #endif
3907
3908 /* vim: set shiftwidth=4 tabstop=8: */