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