chiark / gitweb /
New puzzle: `Loopy', an implementation of Nikoli's `Slither Link' or
[sgt-puzzles.git] / loopy.c
1 /*
2  * loopy.c: An implementation of the Nikoli game 'Loop the loop'.
3  * (c) Mike Pinna, 2005
4  *
5  * vim: set shiftwidth=4 :set textwidth=80:
6  */ 
7
8 /*
9  * TODO:
10  *
11  *  - setting very high recursion depth seems to cause memory
12  *    munching: are we recursing before checking completion, by any
13  *    chance?
14  *
15  *  - there's an interesting deductive technique which makes use of
16  *    topology rather than just graph theory. Each _square_ in the
17  *    grid is either inside or outside the loop; you can tell that
18  *    two squares are on the same side of the loop if they're
19  *    separated by an x (or, more generally, by a path crossing no
20  *    LINE_UNKNOWNs and an even number of LINE_YESes), and on the
21  *    opposite side of the loop if they're separated by a line (or
22  *    an odd number of LINE_YESes and no LINE_UNKNOWNs). Oh, and
23  *    any square separated from the outside of the grid by a
24  *    LINE_YES or a LINE_NO is on the inside or outside
25  *    respectively. So if you can track this for all squares, you
26  *    can occasionally spot that two squares are separated by a
27  *    LINE_UNKNOWN but their relative insideness is known, and
28  *    therefore deduce the state of the edge between them.
29  *     + An efficient way to track this would be by augmenting the
30  *       disjoint set forest data structure. Each element, along
31  *       with a pointer to a parent member of its equivalence
32  *       class, would also carry a one-bit field indicating whether
33  *       it was equal or opposite to its parent. Then you could
34  *       keep flipping a bit as you ascended the tree during
35  *       dsf_canonify(), and hence you'd be able to return the
36  *       relationship of the input value to its ultimate parent
37  *       (and also you could then get all those bits right when you
38  *       went back up the tree rewriting). So you'd be able to
39  *       query whether any two elements were known-equal,
40  *       known-opposite, or not-known, and you could add new
41  *       equalities or oppositenesses to increase your knowledge.
42  *       (Of course the algorithm would have to fail an assertion
43  *       if you tried to tell it two things it already knew to be
44  *       opposite were equal, or vice versa!)
45  */
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <assert.h>
51 #include <ctype.h>
52 #include <math.h>
53
54 #include "puzzles.h"
55 #include "tree234.h"
56
57 #define PREFERRED_TILE_SIZE 32
58 #define TILE_SIZE (ds->tilesize)
59 #define LINEWIDTH TILE_SIZE / 16
60 #define BORDER (TILE_SIZE / 2)
61
62 #define FLASH_TIME 0.4F
63
64 #define HL_COUNT(state) ((state)->w * ((state)->h + 1))
65 #define VL_COUNT(state) (((state)->w + 1) * (state)->h)
66 #define DOT_COUNT(state) (((state)->w + 1) * ((state)->h + 1))
67 #define SQUARE_COUNT(state) ((state)->w * (state)->h)
68
69 #define ABOVE_SQUARE(state, i, j) ((state)->hl[(i) + (state)->w * (j)])
70 #define BELOW_SQUARE(state, i, j) ABOVE_SQUARE(state, i, (j)+1)
71
72 #define LEFTOF_SQUARE(state, i, j)  ((state)->vl[(i) + ((state)->w + 1) * (j)])
73 #define RIGHTOF_SQUARE(state, i, j) LEFTOF_SQUARE(state, (i)+1, j)
74
75 #define LEGAL_DOT(state, i, j) ((i) >= 0 && (j) >= 0 &&                 \
76                                 (i) <= (state)->w && (j) <= (state)->h)
77
78 /*
79  * These macros return rvalues only, but can cope with being passed
80  * out-of-range coordinates.
81  */
82 #define ABOVE_DOT(state, i, j) ((!LEGAL_DOT(state, i, j) || j <= 0) ?  \
83                                 LINE_NO : LV_ABOVE_DOT(state, i, j))
84 #define BELOW_DOT(state, i, j) ((!LEGAL_DOT(state, i, j) || j >= (state)->h) ? \
85                                 LINE_NO : LV_BELOW_DOT(state, i, j))
86
87 #define LEFTOF_DOT(state, i, j)  ((!LEGAL_DOT(state, i, j) || i <= 0) ? \
88                                   LINE_NO : LV_LEFTOF_DOT(state, i, j))
89 #define RIGHTOF_DOT(state, i, j) ((!LEGAL_DOT(state, i, j) || i >= (state)->w)?\
90                                   LINE_NO : LV_RIGHTOF_DOT(state, i, j))
91
92 /*
93  * These macros expect to be passed valid coordinates, and return
94  * lvalues.
95  */
96 #define LV_BELOW_DOT(state, i, j) ((state)->vl[(i) + ((state)->w + 1) * (j)])
97 #define LV_ABOVE_DOT(state, i, j) LV_BELOW_DOT(state, i, (j)-1)
98
99 #define LV_RIGHTOF_DOT(state, i, j) ((state)->hl[(i) + (state)->w * (j)])
100 #define LV_LEFTOF_DOT(state, i, j)  LV_RIGHTOF_DOT(state, (i)-1, j)
101
102 #define CLUE_AT(state, i, j) ((i < 0 || i >= (state)->w || \
103                                j < 0 || j >= (state)->h) ? \
104                              ' ' : LV_CLUE_AT(state, i, j))
105                              
106 #define LV_CLUE_AT(state, i, j) ((state)->clues[(i) + (state)->w * (j)])
107
108 #define OPP(dir) (dir == LINE_UNKNOWN ? LINE_UNKNOWN : \
109                   dir == LINE_YES ? LINE_NO : LINE_YES)
110
111 static char *game_text_format(game_state *state);
112
113 enum {
114     COL_BACKGROUND,
115     COL_FOREGROUND,
116     COL_HIGHLIGHT,
117     NCOLOURS
118 };
119
120 enum line_state { LINE_UNKNOWN, LINE_YES, LINE_NO };
121
122 enum direction { UP, DOWN, LEFT, RIGHT };
123
124 struct game_params {
125     int w, h, rec;
126 };
127
128 struct game_state {
129     int w, h;
130     
131     /* Put ' ' in a square that doesn't get a clue */
132     char *clues;
133     
134     /* Arrays of line states, stored left-to-right, top-to-bottom */
135     char *hl, *vl;
136
137     int solved;
138     int cheated;
139
140     int recursion_depth;
141 };
142
143 static game_state *dup_game(game_state *state)
144 {
145     game_state *ret = snew(game_state);
146
147     ret->h = state->h;
148     ret->w = state->w;
149     ret->solved = state->solved;
150     ret->cheated = state->cheated;
151
152     ret->clues   = snewn(SQUARE_COUNT(state), char);
153     memcpy(ret->clues, state->clues, SQUARE_COUNT(state));
154
155     ret->hl      = snewn(HL_COUNT(state), char);
156     memcpy(ret->hl, state->hl, HL_COUNT(state));
157
158     ret->vl      = snewn(VL_COUNT(state), char);
159     memcpy(ret->vl, state->vl, VL_COUNT(state));
160
161     ret->recursion_depth = state->recursion_depth;
162
163     return ret;
164 }
165
166 static void free_game(game_state *state)
167 {
168     if (state) {
169         sfree(state->clues);
170         sfree(state->hl);
171         sfree(state->vl);
172         sfree(state);
173     }
174 }
175
176 enum solver_status {
177     SOLVER_SOLVED,    /* This is the only solution the solver could find */
178     SOLVER_MISTAKE,   /* This is definitely not a solution */
179     SOLVER_AMBIGUOUS, /* This _might_ be an ambiguous solution */
180     SOLVER_INCOMPLETE /* This may be a partial solution */
181 };
182
183 typedef struct solver_state {
184   game_state *state;
185    /* XXX dot_atleastone[i,j, dline] is equivalent to */
186    /*     dot_atmostone[i,j,OPP_DLINE(dline)] */
187   char *dot_atleastone;
188   char *dot_atmostone;
189 /*   char *dline_identical; */
190   int recursion_remaining;
191   enum solver_status solver_status;
192   int *dotdsf, *looplen;
193 } solver_state;
194
195 static solver_state *new_solver_state(game_state *state) {
196     solver_state *ret = snew(solver_state);
197     int i;
198
199     ret->state = dup_game(state);
200     
201     ret->dot_atmostone = snewn(DOT_COUNT(state), char);
202     memset(ret->dot_atmostone, 0, DOT_COUNT(state));
203     ret->dot_atleastone = snewn(DOT_COUNT(state), char);
204     memset(ret->dot_atleastone, 0, DOT_COUNT(state));
205
206 #if 0
207     dline_identical = snewn(DOT_COUNT(state), char);
208     memset(dline_identical, 0, DOT_COUNT(state));
209 #endif
210
211     ret->recursion_remaining = state->recursion_depth;
212     ret->solver_status = SOLVER_INCOMPLETE; /* XXX This may be a lie */
213
214     ret->dotdsf = snewn(DOT_COUNT(state), int);
215     ret->looplen = snewn(DOT_COUNT(state), int);
216     for (i = 0; i < DOT_COUNT(state); i++) {
217         ret->dotdsf[i] = i;
218         ret->looplen[i] = 1;
219     }
220
221     return ret;
222 }
223
224 static void free_solver_state(solver_state *sstate) {
225     if (sstate) {
226         free_game(sstate->state);
227         sfree(sstate->dot_atleastone);
228         sfree(sstate->dot_atmostone);
229         /*    sfree(sstate->dline_identical); */
230     }
231 }
232
233 static solver_state *dup_solver_state(solver_state *sstate) {
234     game_state *state = dup_game(sstate->state);
235
236     solver_state *ret = snew(solver_state);
237
238     ret->state = dup_game(state);
239
240     ret->dot_atmostone = snewn(DOT_COUNT(state), char);
241     memcpy(ret->dot_atmostone, sstate->dot_atmostone, DOT_COUNT(state));
242
243     ret->dot_atleastone = snewn(DOT_COUNT(state), char);
244     memcpy(ret->dot_atleastone, sstate->dot_atleastone, DOT_COUNT(state));
245
246 #if 0
247     ret->dline_identical = snewn((state->w + 1) * (state->h + 1), char);
248     memcpy(ret->dline_identical, state->dot_atmostone, 
249            (state->w + 1) * (state->h + 1));
250 #endif
251
252     ret->recursion_remaining = sstate->recursion_remaining;
253     ret->solver_status = sstate->solver_status;
254
255     ret->dotdsf = snewn(DOT_COUNT(state), int);
256     ret->looplen = snewn(DOT_COUNT(state), int);
257     memcpy(ret->dotdsf, sstate->dotdsf, DOT_COUNT(state) * sizeof(int));
258     memcpy(ret->looplen, sstate->looplen, DOT_COUNT(state) * sizeof(int));
259
260     return ret;
261 }
262
263 /*
264  * Merge two dots due to the existence of an edge between them.
265  * Updates the dsf tracking equivalence classes, and keeps track of
266  * the length of path each dot is currently a part of.
267  */
268 static void merge_dots(solver_state *sstate, int x1, int y1, int x2, int y2)
269 {
270     int i, j, len;
271
272     i = y1 * (sstate->state->w + 1) + x1;
273     j = y2 * (sstate->state->w + 1) + x2;
274
275     i = dsf_canonify(sstate->dotdsf, i);
276     j = dsf_canonify(sstate->dotdsf, j);
277
278     if (i != j) {
279         len = sstate->looplen[i] + sstate->looplen[j];
280         dsf_merge(sstate->dotdsf, i, j);
281         i = dsf_canonify(sstate->dotdsf, i);
282         sstate->looplen[i] = len;
283     }
284 }
285
286 /* Count the number of lines of a particular type currently going into the
287  * given dot.  Lines going off the edge of the board are assumed fixed no. */
288 static int dot_order(const game_state* state, int i, int j, char line_type)
289 {
290     int n = 0;
291
292     if (i > 0) {
293         if (LEFTOF_DOT(state, i, j) == line_type)
294             ++n;
295     } else {
296         if (line_type == LINE_NO)
297             ++n;
298     }
299     if (i < state->w) {
300         if (RIGHTOF_DOT(state, i, j) == line_type)
301             ++n;
302     } else {
303         if (line_type == LINE_NO)
304             ++n;
305     }
306     if (j > 0) {
307         if (ABOVE_DOT(state, i, j) == line_type)
308             ++n;
309     } else {
310         if (line_type == LINE_NO)
311             ++n;
312     }
313     if (j < state->h) {
314         if (BELOW_DOT(state, i, j) == line_type)
315             ++n;
316     } else {
317         if (line_type == LINE_NO)
318             ++n;
319     }
320
321     return n;
322 }
323 /* Count the number of lines of a particular type currently surrounding the
324  * given square */
325 static int square_order(const game_state* state, int i, int j, char line_type)
326 {
327     int n = 0;
328
329     if (ABOVE_SQUARE(state, i, j) == line_type)
330         ++n;
331     if (BELOW_SQUARE(state, i, j) == line_type)
332         ++n;
333     if (LEFTOF_SQUARE(state, i, j) == line_type)
334         ++n;
335     if (RIGHTOF_SQUARE(state, i, j) == line_type)
336         ++n;
337
338     return n;
339 }
340
341 /* Set all lines bordering a dot of type old_type to type new_type */
342 static void dot_setall(game_state *state, int i, int j,
343                        char old_type, char new_type)
344 {
345 /*    printf("dot_setall([%d,%d], %d, %d)\n", i, j, old_type, new_type); */
346     if (i > 0        && LEFTOF_DOT(state, i, j) == old_type)
347         LV_LEFTOF_DOT(state, i, j) = new_type;
348     if (i < state->w && RIGHTOF_DOT(state, i, j) == old_type)
349         LV_RIGHTOF_DOT(state, i, j) = new_type;
350     if (j > 0        && ABOVE_DOT(state, i, j) == old_type)
351         LV_ABOVE_DOT(state, i, j) = new_type;
352     if (j < state->h && BELOW_DOT(state, i, j) == old_type)
353         LV_BELOW_DOT(state, i, j) = new_type;
354 }
355 /* Set all lines bordering a square of type old_type to type new_type */
356 static void square_setall(game_state *state, int i, int j,
357                           char old_type, char new_type)
358 {
359     if (ABOVE_SQUARE(state, i, j) == old_type)
360         ABOVE_SQUARE(state, i, j) = new_type;
361     if (BELOW_SQUARE(state, i, j) == old_type)
362         BELOW_SQUARE(state, i, j) = new_type;
363     if (LEFTOF_SQUARE(state, i, j) == old_type)
364         LEFTOF_SQUARE(state, i, j) = new_type;
365     if (RIGHTOF_SQUARE(state, i, j) == old_type)
366         RIGHTOF_SQUARE(state, i, j) = new_type;
367 }
368
369 static game_params *default_params(void)
370 {
371     game_params *ret = snew(game_params);
372
373     ret->h = 10;
374     ret->w = 10;
375     ret->rec = 0; 
376
377     return ret;
378 }
379
380 static game_params *dup_params(game_params *params)
381 {
382     game_params *ret = snew(game_params);
383     *ret = *params;                       /* structure copy */
384     return ret;
385 }
386
387 static const struct {
388     char *desc;
389     game_params params;
390 } loopy_presets[] = {
391     { "4x4 Easy",   {  4,  4, 0 } },
392     { "4x4 Hard",   {  4,  4, 2 } },
393     { "7x7 Easy",   {  7,  7, 0 } },
394     { "7x7 Hard",   {  7,  7, 0 } },
395     { "10x10 Easy", { 10, 10, 0 } },
396     { "10x10 Hard", { 10, 10, 2 } },
397     { "15x15 Easy", { 15, 15, 0 } },
398     { "20x30 Easy", { 20, 30, 0 } }
399 };
400
401 static int game_fetch_preset(int i, char **name, game_params **params)
402 {
403     game_params tmppar;
404
405     if (i < 0 || i >= lenof(loopy_presets))
406         return FALSE;
407
408     tmppar = loopy_presets[i].params;
409     *params = dup_params(&tmppar);
410     *name = dupstr(loopy_presets[i].desc);
411
412     return TRUE;
413 }
414
415 static void free_params(game_params *params)
416 {
417     sfree(params);
418 }
419
420 static void decode_params(game_params *params, char const *string)
421 {
422     params->h = params->w = atoi(string);
423     params->rec = 0;
424     while (*string && isdigit((unsigned char)*string)) string++;
425     if (*string == 'x') {
426         string++;
427         params->h = atoi(string);
428         while (*string && isdigit((unsigned char)*string)) string++;
429     }
430     if (*string == 'r') {
431         string++;
432         params->rec = atoi(string);
433         while (*string && isdigit((unsigned char)*string)) string++;
434     }
435 }
436
437 static char *encode_params(game_params *params, int full)
438 {
439     char str[80];
440     sprintf(str, "%dx%d", params->w, params->h);
441     if (full)
442         sprintf(str + strlen(str), "r%d", params->rec);
443     return dupstr(str);
444 }
445
446 static config_item *game_configure(game_params *params)
447 {
448     config_item *ret;
449     char buf[80];
450
451     ret = snewn(4, config_item);
452
453     ret[0].name = "Width";
454     ret[0].type = C_STRING;
455     sprintf(buf, "%d", params->w);
456     ret[0].sval = dupstr(buf);
457     ret[0].ival = 0;
458
459     ret[1].name = "Height";
460     ret[1].type = C_STRING;
461     sprintf(buf, "%d", params->h);
462     ret[1].sval = dupstr(buf);
463     ret[1].ival = 0;
464
465     ret[2].name = "Recursion depth";
466     ret[2].type = C_STRING;
467     sprintf(buf, "%d", params->rec);
468     ret[2].sval = dupstr(buf);
469     ret[2].ival = 0;
470
471     ret[3].name = NULL;
472     ret[3].type = C_END;
473     ret[3].sval = NULL;
474     ret[3].ival = 0;
475
476     return ret;
477 }
478
479 static game_params *custom_params(config_item *cfg)
480 {
481     game_params *ret = snew(game_params);
482
483     ret->w = atoi(cfg[0].sval);
484     ret->h = atoi(cfg[1].sval);
485     ret->rec = atoi(cfg[2].sval);
486
487     return ret;
488 }
489
490 static char *validate_params(game_params *params, int full)
491 {
492     if (params->w < 4 || params->h < 4)
493         return "Width and height must both be at least 4";
494     if (params->rec < 0)
495         return "Recursion depth can't be negative";
496     return NULL;
497 }
498
499 /* We're going to store a list of current candidate squares for lighting.
500  * Each square gets a 'score', which tells us how adding that square right
501  * now would affect the length of the solution loop.  We're trying to
502  * maximise that quantity so will bias our random selection of squares to
503  * light towards those with high scores */
504 struct square { 
505     int score;
506     int random;
507     int x, y;
508 };
509
510 static int get_square_cmpfn(void *v1, void *v2) 
511 {
512     struct square *s1 = (struct square *)v1;
513     struct square *s2 = (struct square *)v2;
514     int r;
515     
516     r = s1->x - s2->x;
517     if (r)
518         return r;
519
520     r = s1->y - s2->y;
521     if (r)
522         return r;
523
524     return 0;
525 }
526
527 static int square_sort_cmpfn(void *v1, void *v2)
528 {
529     struct square *s1 = (struct square *)v1;
530     struct square *s2 = (struct square *)v2;
531     int r;
532
533     r = s2->score - s1->score;
534     if (r) {
535         return r;
536     }
537
538     r = s1->random - s2->random;
539     if (r) {
540         return r;
541     }
542
543     /*
544      * It's _just_ possible that two squares might have been given
545      * the same random value. In that situation, fall back to
546      * comparing based on the coordinates. This introduces a tiny
547      * directional bias, but not a significant one.
548      */
549     return get_square_cmpfn(v1, v2);
550 }
551
552 static void print_tree(tree234 *tree)
553 {
554 #if 0
555     int i = 0;
556     struct square *s;
557     printf("Print tree:\n");
558     while (i < count234(tree)) {
559         s = (struct square *)index234(tree, i);
560         assert(s);
561         printf("  [%d,%d], %d, %d\n", s->x, s->y, s->score, s->random);
562         ++i;
563     }
564 #endif
565 }
566
567 enum { SQUARE_LIT, SQUARE_UNLIT };
568
569 #define SQUARE_STATE(i, j)                 \
570     (((i) < 0 || (i) >= params->w ||       \
571       (j) < 0 || (j) >= params->h) ?       \
572      SQUARE_UNLIT :  LV_SQUARE_STATE(i,j))
573
574 #define LV_SQUARE_STATE(i, j) board[(i) + params->w * (j)]
575
576 static void print_board(const game_params *params, const char *board)
577 {
578 #if 0
579     int i,j;
580
581     printf(" ");
582     for (i = 0; i < params->w; i++) {
583         printf("%d", i%10);
584     }
585     printf("\n");
586     for (j = 0; j < params->h; j++) {
587         printf("%d", j%10);
588         for (i = 0; i < params->w; i++) {
589             printf("%c", SQUARE_STATE(i, j) ? ' ' : 'O');
590         }
591         printf("\n");
592     }
593 #endif
594 }
595
596 static char *new_fullyclued_board(game_params *params, random_state *rs)
597 {
598     char *clues;
599     char *board;
600     int i, j, a, b, c;
601     game_state s;
602     game_state *state = &s;
603     int board_area = SQUARE_COUNT(params);
604     int t;
605
606     struct square *square, *tmpsquare, *sq;
607     struct square square_pos;
608
609     /* These will contain exactly the same information, sorted into different
610      * orders */
611     tree234 *lightable_squares_sorted, *lightable_squares_gettable;
612
613 #define SQUARE_REACHABLE(i,j)                      \
614      (t = (SQUARE_STATE(i-1, j) == SQUARE_LIT ||      \
615            SQUARE_STATE(i+1, j) == SQUARE_LIT ||      \
616            SQUARE_STATE(i, j-1) == SQUARE_LIT ||      \
617            SQUARE_STATE(i, j+1) == SQUARE_LIT),       \
618 /*      printf("SQUARE_REACHABLE(%d,%d) = %d\n", i, j, t), */ \
619       t)
620
621
622     /* One situation in which we may not light a square is if that'll leave one
623      * square above/below and one left/right of us unlit, separated by a lit
624      * square diagnonal from us */
625 #define SQUARE_DIAGONAL_VIOLATION(i, j, h, v)           \
626     (t = (SQUARE_STATE((i)+(h), (j))     == SQUARE_UNLIT && \
627           SQUARE_STATE((i),     (j)+(v)) == SQUARE_UNLIT && \
628           SQUARE_STATE((i)+(h), (j)+(v)) == SQUARE_LIT),    \
629 /*     t ? printf("SQUARE_DIAGONAL_VIOLATION(%d, %d, %d, %d)\n",
630                   i, j, h, v) : 0,*/ \
631      t)
632
633     /* We also may not light a square if it will form a loop of lit squares
634      * around some unlit squares, as then the game soln won't have a single
635      * loop */
636 #define SQUARE_LOOP_VIOLATION(i, j, lit1, lit2) \
637     (SQUARE_STATE((i)+1, (j)) == lit1    &&     \
638      SQUARE_STATE((i)-1, (j)) == lit1    &&     \
639      SQUARE_STATE((i), (j)+1) == lit2    &&     \
640      SQUARE_STATE((i), (j)-1) == lit2)
641
642 #define CAN_LIGHT_SQUARE(i, j)                                 \
643     (SQUARE_REACHABLE(i, j)                                 && \
644      !SQUARE_DIAGONAL_VIOLATION(i, j, -1, -1)               && \
645      !SQUARE_DIAGONAL_VIOLATION(i, j, +1, -1)               && \
646      !SQUARE_DIAGONAL_VIOLATION(i, j, -1, +1)               && \
647      !SQUARE_DIAGONAL_VIOLATION(i, j, +1, +1)               && \
648      !SQUARE_LOOP_VIOLATION(i, j, SQUARE_LIT, SQUARE_UNLIT) && \
649      !SQUARE_LOOP_VIOLATION(i, j, SQUARE_UNLIT, SQUARE_LIT))
650
651 #define IS_LIGHTING_CANDIDATE(i, j)        \
652     (SQUARE_STATE(i, j) == SQUARE_UNLIT && \
653      CAN_LIGHT_SQUARE(i,j))
654
655     /* The 'score' of a square reflects its current desirability for selection
656      * as the next square to light.  We want to encourage moving into uncharted
657      * areas so we give scores according to how many of the square's neighbours
658      * are currently unlit. */
659
660    /* UNLIT    SCORE
661     *   3        2
662     *   2        0
663     *   1       -2
664     */
665 #define SQUARE_SCORE(i,j)                  \
666     (2*((SQUARE_STATE(i-1, j) == SQUARE_UNLIT)  +   \
667         (SQUARE_STATE(i+1, j) == SQUARE_UNLIT)  +   \
668         (SQUARE_STATE(i, j-1) == SQUARE_UNLIT)  +   \
669         (SQUARE_STATE(i, j+1) == SQUARE_UNLIT)) - 4)
670
671     /* When a square gets lit, this defines how far away from that square we
672      * need to go recomputing scores */
673 #define SCORE_DISTANCE 1
674
675     board = snewn(board_area, char);
676     clues = snewn(board_area, char);
677
678     state->h = params->h;
679     state->w = params->w;
680     state->clues = clues;
681
682     /* Make a board */
683     memset(board, SQUARE_UNLIT, board_area);
684     
685     /* Seed the board with a single lit square near the middle */
686     i = params->w / 2;
687     j = params->h / 2;
688     if (params->w & 1 && random_bits(rs, 1))
689         ++i;
690     if (params->h & 1 && random_bits(rs, 1))
691         ++j;
692
693     LV_SQUARE_STATE(i, j) = SQUARE_LIT;
694
695     /* We need a way of favouring squares that will increase our loopiness.
696      * We do this by maintaining a list of all candidate squares sorted by
697      * their score and choose randomly from that with appropriate skew. 
698      * In order to avoid consistently biasing towards particular squares, we
699      * need the sort order _within_ each group of scores to be completely
700      * random.  But it would be abusing the hospitality of the tree234 data
701      * structure if our comparison function were nondeterministic :-).  So with
702      * each square we associate a random number that does not change during a
703      * particular run of the generator, and use that as a secondary sort key.
704      * Yes, this means we will be biased towards particular random squares in
705      * any one run but that doesn't actually matter. */
706     
707     lightable_squares_sorted   = newtree234(square_sort_cmpfn);
708     lightable_squares_gettable = newtree234(get_square_cmpfn);
709 #define ADD_SQUARE(s)                                          \
710     do {                                                       \
711 /*      printf("ADD SQUARE: [%d,%d], %d, %d\n",
712                s->x, s->y, s->score, s->random);*/ \
713         sq = add234(lightable_squares_sorted, s);              \
714         assert(sq == s);                                       \
715         sq = add234(lightable_squares_gettable, s);            \
716         assert(sq == s);                                       \
717     } while (0)
718
719 #define REMOVE_SQUARE(s)                                       \
720     do {                                                       \
721 /*      printf("DELETE SQUARE: [%d,%d], %d, %d\n",
722                s->x, s->y, s->score, s->random);*/ \
723         sq = del234(lightable_squares_sorted, s);              \
724         assert(sq);                                            \
725         sq = del234(lightable_squares_gettable, s);            \
726         assert(sq);                                            \
727     } while (0)
728         
729 #define HANDLE_DIR(a, b)                                       \
730     square = snew(struct square);                              \
731     square->x = (i)+(a);                                       \
732     square->y = (j)+(b);                                       \
733     square->score = 2;                                         \
734     square->random = random_bits(rs, 31);                      \
735     ADD_SQUARE(square);
736     HANDLE_DIR(-1, 0);
737     HANDLE_DIR( 1, 0);
738     HANDLE_DIR( 0,-1);
739     HANDLE_DIR( 0, 1);
740 #undef HANDLE_DIR
741     
742     /* Light squares one at a time until the board is interesting enough */
743     while (TRUE)
744     {
745         /* We have count234(lightable_squares) possibilities, and in
746          * lightable_squares_sorted they are sorted with the most desirable
747          * first.  */
748         c = count234(lightable_squares_sorted);
749         if (c == 0)
750             break;
751         assert(c == count234(lightable_squares_gettable));
752
753         /* Check that the best square available is any good */
754         square = (struct square *)index234(lightable_squares_sorted, 0);
755         assert(square);
756
757         if (square->score <= 0)
758             break;
759
760         print_tree(lightable_squares_sorted);
761         assert(square->score == SQUARE_SCORE(square->x, square->y));
762         assert(SQUARE_STATE(square->x, square->y) == SQUARE_UNLIT);
763         assert(square->x >= 0 && square->x < params->w);
764         assert(square->y >= 0 && square->y < params->h);
765 /*        printf("LIGHT SQUARE: [%d,%d], score = %d\n", square->x, square->y, square->score); */
766
767         /* Update data structures */
768         LV_SQUARE_STATE(square->x, square->y) = SQUARE_LIT;
769         REMOVE_SQUARE(square);
770
771         print_board(params, board);
772
773         /* We might have changed the score of any squares up to 2 units away in
774          * any direction */
775         for (b = -SCORE_DISTANCE; b <= SCORE_DISTANCE; b++) {
776             for (a = -SCORE_DISTANCE; a <= SCORE_DISTANCE; a++) {
777                 if (!a && !b) 
778                     continue;
779                 square_pos.x = square->x + a;
780                 square_pos.y = square->y + b;
781 /*                printf("Refreshing score for [%d,%d]:\n", square_pos.x, square_pos.y); */
782                 if (square_pos.x < 0 || square_pos.x >= params->w ||
783                     square_pos.y < 0 || square_pos.y >= params->h) {
784 /*                    printf("  Out of bounds\n"); */
785                    continue; 
786                 }
787                 tmpsquare = find234(lightable_squares_gettable, &square_pos,
788                                     NULL);
789                 if (tmpsquare) {
790 /*                    printf(" Removing\n"); */
791                     assert(tmpsquare->x == square_pos.x);
792                     assert(tmpsquare->y == square_pos.y);
793                     assert(SQUARE_STATE(tmpsquare->x, tmpsquare->y) == 
794                            SQUARE_UNLIT);
795                     REMOVE_SQUARE(tmpsquare);
796                 } else {
797 /*                    printf(" Creating\n"); */
798                     tmpsquare = snew(struct square);
799                     tmpsquare->x = square_pos.x;
800                     tmpsquare->y = square_pos.y;
801                     tmpsquare->random = random_bits(rs, 31);
802                 }
803                 tmpsquare->score = SQUARE_SCORE(tmpsquare->x, tmpsquare->y);
804
805                 if (IS_LIGHTING_CANDIDATE(tmpsquare->x, tmpsquare->y)) {
806 /*                    printf(" Adding\n"); */
807                     ADD_SQUARE(tmpsquare);
808                 } else {
809 /*                    printf(" Destroying\n"); */
810                     sfree(tmpsquare);
811                 }
812             }
813         }
814 /*        printf("\n\n"); */
815     }
816
817     while ((square = delpos234(lightable_squares_gettable, 0)) != NULL)
818         sfree(square);
819     freetree234(lightable_squares_gettable);
820     freetree234(lightable_squares_sorted);
821
822     /* Copy out all the clues */
823     for (j = 0; j < params->h; ++j) {
824         for (i = 0; i < params->w; ++i) {
825             c = SQUARE_STATE(i, j);
826             LV_CLUE_AT(state, i, j) = '0';
827             if (SQUARE_STATE(i-1, j) != c) ++LV_CLUE_AT(state, i, j);
828             if (SQUARE_STATE(i+1, j) != c) ++LV_CLUE_AT(state, i, j);
829             if (SQUARE_STATE(i, j-1) != c) ++LV_CLUE_AT(state, i, j);
830             if (SQUARE_STATE(i, j+1) != c) ++LV_CLUE_AT(state, i, j);
831         }
832     }
833
834     sfree(board);
835     return clues;
836 }
837
838 static solver_state *solve_game_rec(const solver_state *sstate);
839
840 static int game_has_unique_soln(const game_state *state)
841 {
842     int ret;
843     solver_state *sstate_new;
844     solver_state *sstate = new_solver_state((game_state *)state);
845     
846     sstate_new = solve_game_rec(sstate);
847
848     ret = (sstate_new->solver_status == SOLVER_SOLVED);
849
850     free_solver_state(sstate_new);
851     free_solver_state(sstate);
852
853     return ret;
854 }
855
856 /* Remove clues one at a time at random. */
857 static game_state *remove_clues(game_state *state, random_state *rs)
858 {
859     int *square_list, squares;
860     game_state *ret = dup_game(state), *saved_ret;
861     int n;
862
863     /* We need to remove some clues.  We'll do this by forming a list of all
864      * available equivalence classes, shuffling it, then going along one at a
865      * time clearing every member of each equivalence class, where removing a
866      * class doesn't render the board unsolvable. */
867     squares = state->w * state->h;
868     square_list = snewn(squares, int);
869     for (n = 0; n < squares; ++n) {
870         square_list[n] = n;
871     }
872
873     shuffle(square_list, squares, sizeof(int), rs);
874     
875     for (n = 0; n < squares; ++n) {
876         saved_ret = dup_game(ret);
877         LV_CLUE_AT(ret, square_list[n] % state->w,
878                    square_list[n] / state->w) = ' ';
879         if (game_has_unique_soln(ret)) {
880             free_game(saved_ret);
881         } else {
882             free_game(ret);
883             ret = saved_ret;
884         }
885     }
886
887     return ret;
888 }
889
890 static char *validate_desc(game_params *params, char *desc);
891
892 static char *new_game_desc(game_params *params, random_state *rs,
893                            char **aux, int interactive)
894 {
895     /* solution and description both use run-length encoding in obvious ways */
896     char *retval;
897     char *description = snewn(SQUARE_COUNT(params) + 1, char);
898     char *dp = description;
899     int i, j;
900     int empty_count;
901     game_state *state = snew(game_state), *state_new;
902
903     state->h = params->h;
904     state->w = params->w;
905
906     state->hl = snewn(HL_COUNT(params), char);
907     state->vl = snewn(VL_COUNT(params), char);
908     memset(state->hl, LINE_UNKNOWN, HL_COUNT(params));
909     memset(state->vl, LINE_UNKNOWN, VL_COUNT(params));
910
911     state->solved = state->cheated = FALSE;
912     state->recursion_depth = params->rec;
913
914     /* Get a new random solvable board with all its clues filled in.  Yes, this
915      * can loop for ever if the params are suitably unfavourable, but
916      * preventing games smaller than 4x4 seems to stop this happening */
917     do {
918         state->clues = new_fullyclued_board(params, rs);
919     } while (!game_has_unique_soln(state));
920
921     state_new = remove_clues(state, rs);
922     free_game(state);
923     state = state_new;
924
925     empty_count = 0;
926     for (j = 0; j < params->h; ++j) {
927         for (i = 0; i < params->w; ++i) {
928             if (CLUE_AT(state, i, j) == ' ') {
929                 if (empty_count > 25) {
930                     dp += sprintf(dp, "%c", empty_count + 'a' - 1);
931                     empty_count = 0;
932                 }
933                 empty_count++;
934             } else {
935                 if (empty_count) {
936                     dp += sprintf(dp, "%c", empty_count + 'a' - 1);
937                     empty_count = 0;
938                 }
939                 dp += sprintf(dp, "%c", CLUE_AT(state, i, j));
940             }
941         }
942     }
943     if (empty_count)
944         dp += sprintf(dp, "%c", empty_count + 'a' - 1);
945
946     sfree(state);
947     retval = dupstr(description);
948     sfree(description);
949     
950     assert(!validate_desc(params, retval));
951
952     return retval;
953 }
954
955 /* We require that the params pass the test in validate_params and that the
956  * description fills the entire game area */
957 static char *validate_desc(game_params *params, char *desc)
958 {
959     int count = 0;
960
961     for (; *desc; ++desc) {
962         if (*desc >= '0' && *desc <= '9') {
963             count++;
964             continue;
965         }
966         if (*desc >= 'a') {
967             count += *desc - 'a' + 1;
968             continue;
969         }
970         return "Unknown character in description";
971     }
972
973     if (count < SQUARE_COUNT(params))
974         return "Description too short for board size";
975     if (count > SQUARE_COUNT(params))
976         return "Description too long for board size";
977
978     return NULL;
979 }
980
981 static game_state *new_game(midend *me, game_params *params, char *desc)
982 {
983     int i,j;
984     game_state *state = snew(game_state);
985     int empties_to_make = 0;
986     int n;
987     const char *dp = desc;
988
989     state->recursion_depth = params->rec;
990     
991     state->h = params->h;
992     state->w = params->w;
993
994     state->clues = snewn(SQUARE_COUNT(params), char);
995     state->hl    = snewn(HL_COUNT(params), char);
996     state->vl    = snewn(VL_COUNT(params), char);
997
998     state->solved = state->cheated = FALSE;
999
1000     for (j = 0 ; j < params->h; ++j) {
1001         for (i = 0 ; i < params->w; ++i) {
1002             if (empties_to_make) {
1003                 empties_to_make--;
1004                 LV_CLUE_AT(state, i, j) = ' ';
1005                 continue;
1006             }
1007
1008             assert(*dp);
1009             n = *dp - '0';
1010             if (n >=0 && n < 10) {
1011                 LV_CLUE_AT(state, i, j) = *dp;
1012             } else {
1013                 n = *dp - 'a' + 1;
1014                 assert(n > 0);
1015                 LV_CLUE_AT(state, i, j) = ' ';
1016                 empties_to_make = n - 1;
1017             }
1018             ++dp;
1019         }
1020     }
1021
1022     memset(state->hl, LINE_UNKNOWN, HL_COUNT(params));
1023     memset(state->vl, LINE_UNKNOWN, VL_COUNT(params));
1024
1025     return state;
1026 }
1027
1028 enum { LOOP_NONE=0, LOOP_SOLN, LOOP_NOT_SOLN };
1029
1030 /* Starting at dot [i,j] moves around 'state' removing lines until it's clear
1031  * whether or not the starting dot was on a loop.  Returns boolean specifying
1032  * whether a loop was found.  loop_status calls this and assumes that if state
1033  * has any lines set, this function will always remove at least one.  */
1034 static int destructively_find_loop(game_state *state)
1035 {
1036     int a, b, i, j, new_i, new_j, n;
1037     char *lp;
1038
1039     lp = (char *)memchr(state->hl, LINE_YES, HL_COUNT(state));
1040     if (!lp) {
1041         /* We know we're going to return false but we have to fulfil our
1042          * contract */
1043         lp = (char *)memchr(state->vl, LINE_YES, VL_COUNT(state));
1044         if (lp)
1045             *lp = LINE_NO;
1046         
1047         return FALSE;
1048     }
1049
1050     n = lp - state->hl;
1051
1052     i = n % state->w;
1053     j = n / state->w;
1054
1055     assert(i + j * state->w == n); /* because I'm feeling stupid */
1056     /* Save start position */
1057     a = i;
1058     b = j;
1059
1060     /* Delete one line from the potential loop */
1061     if (LEFTOF_DOT(state, i, j) == LINE_YES) {
1062         LV_LEFTOF_DOT(state, i, j) = LINE_NO;
1063         i--;
1064     } else if (ABOVE_DOT(state, i, j) == LINE_YES) {
1065         LV_ABOVE_DOT(state, i, j) = LINE_NO;
1066         j--;
1067     } else if (RIGHTOF_DOT(state, i, j) == LINE_YES) {
1068         LV_RIGHTOF_DOT(state, i, j) = LINE_NO;
1069         i++;
1070     } else if (BELOW_DOT(state, i, j) == LINE_YES) {
1071         LV_BELOW_DOT(state, i, j) = LINE_NO;
1072         j++;
1073     } else {
1074         return FALSE;
1075     }
1076
1077     do {
1078         /* From the current position of [i,j] there needs to be exactly one
1079          * line */
1080         new_i = new_j = -1;
1081
1082 #define HANDLE_DIR(dir_dot, x, y)                    \
1083         if (dir_dot(state, i, j) == LINE_YES) {      \
1084             if (new_i != -1 || new_j != -1)          \
1085                 return FALSE;                        \
1086             new_i = (i)+(x);                         \
1087             new_j = (j)+(y);                         \
1088             LV_##dir_dot(state, i, j) = LINE_NO;     \
1089         }
1090         HANDLE_DIR(ABOVE_DOT,    0, -1);
1091         HANDLE_DIR(BELOW_DOT,    0, +1);
1092         HANDLE_DIR(LEFTOF_DOT,  -1,  0);
1093         HANDLE_DIR(RIGHTOF_DOT, +1,  0);
1094 #undef HANDLE_DIR
1095         if (new_i == -1 || new_j == -1) {
1096             return FALSE;
1097         }
1098
1099         i = new_i;
1100         j = new_j;
1101     } while (i != a || j != b);
1102
1103     return TRUE;
1104 }
1105
1106 static int loop_status(game_state *state)
1107 {
1108     int i, j, n;
1109     game_state *tmpstate;
1110     int loop_found = FALSE, non_loop_found = FALSE, any_lines_found = FALSE;
1111
1112 #define BAD_LOOP_FOUND \
1113     do { free_game(tmpstate); return LOOP_NOT_SOLN; } while(0)
1114
1115     /* Repeatedly look for loops until we either run out of lines to consider
1116      * or discover for sure that the board fails on the grounds of having no
1117      * loop */
1118     tmpstate = dup_game(state);
1119
1120     while (TRUE) {
1121         if (!memchr(tmpstate->hl, LINE_YES, HL_COUNT(tmpstate)) &&
1122             !memchr(tmpstate->vl, LINE_YES, VL_COUNT(tmpstate))) {
1123             break;
1124         }
1125         any_lines_found = TRUE;
1126
1127         if (loop_found) 
1128             BAD_LOOP_FOUND;
1129         if (destructively_find_loop(tmpstate)) {
1130             loop_found = TRUE;
1131             if (non_loop_found)
1132                 BAD_LOOP_FOUND;
1133         } else {
1134             non_loop_found = TRUE;
1135         }
1136     }
1137
1138     free_game(tmpstate);
1139
1140     if (!any_lines_found)
1141         return LOOP_NONE;
1142     
1143     if (non_loop_found) {
1144         assert(!loop_found); /* should have dealt with this already */
1145         return LOOP_NONE;
1146     }
1147
1148     /* Check that every clue is satisfied */
1149     for (j = 0; j < state->h; ++j) {
1150         for (i = 0; i < state->w; ++i) {
1151             n = CLUE_AT(state, i, j);
1152             if (n != ' ') {
1153                 if (square_order(state, i, j, LINE_YES) != n - '0') {
1154                     return LOOP_NOT_SOLN;
1155                 }
1156             }
1157         }
1158     }
1159
1160     return LOOP_SOLN;
1161 }
1162
1163 /* Sums the lengths of the numbers in range [0,n) */
1164 /* See equivalent function in solo.c for justification of this. */
1165 int len_0_to_n(int n)
1166 {
1167     int len = 1; /* Counting 0 as a bit of a special case */
1168     int i;
1169
1170     for (i = 1; i < n; i *= 10) {
1171         len += max(n - i, 0);
1172     }
1173
1174     return len;
1175 }
1176
1177 static char *encode_solve_move(const game_state *state)
1178 {
1179     int len, i, j;
1180     char *ret, *p;
1181     /* This is going to return a string representing the moves needed to set
1182      * every line in a grid to be the same as the ones in 'state'.  The exact
1183      * length of this string is predictable. */
1184
1185     len = 1;  /* Count the 'S' prefix */
1186     /* Numbers in horizontal lines */
1187     /* Horizontal lines, x position */
1188     len += len_0_to_n(state->w) * (state->h + 1);
1189     /* Horizontal lines, y position */
1190     len += len_0_to_n(state->h + 1) * (state->w);
1191     /* Vertical lines, y position */
1192     len += len_0_to_n(state->h) * (state->w + 1);
1193     /* Vertical lines, x position */
1194     len += len_0_to_n(state->w + 1) * (state->h);
1195     /* For each line we also have two letters and a comma */
1196     len += 3 * (HL_COUNT(state) + VL_COUNT(state));
1197
1198     ret = snewn(len + 1, char);
1199     p = ret;
1200
1201     p += sprintf(p, "S");
1202
1203     for (j = 0; j < state->h + 1; ++j) {
1204         for (i = 0; i < state->w; ++i) {
1205             switch (RIGHTOF_DOT(state, i, j)) {
1206                 case LINE_YES:
1207                     p += sprintf(p, "%d,%dhy", i, j);
1208                     break;
1209                 case LINE_NO:
1210                     p += sprintf(p, "%d,%dhn", i, j);
1211                     break;
1212 /*                default: */
1213                     /* I'm going to forgive this because I think the results
1214                      * are cute. */
1215 /*                    assert(!"Solver produced incomplete solution!"); */
1216             }
1217         }
1218     }
1219
1220     for (j = 0; j < state->h; ++j) {
1221         for (i = 0; i < state->w + 1; ++i) {
1222             switch (BELOW_DOT(state, i, j)) {
1223                 case LINE_YES:
1224                     p += sprintf(p, "%d,%dvy", i, j);
1225                     break;
1226                 case LINE_NO:
1227                     p += sprintf(p, "%d,%dvn", i, j);
1228                     break;
1229 /*                default: */
1230                     /* I'm going to forgive this because I think the results
1231                      * are cute. */
1232 /*                    assert(!"Solver produced incomplete solution!"); */
1233             }
1234         }
1235     }
1236
1237     /* No point in doing sums like that if they're going to be wrong */
1238     assert(strlen(ret) <= (size_t)len);
1239     return dupstr(ret);
1240 }
1241
1242 /* BEGIN SOLVER IMPLEMENTATION */
1243
1244    /* For each pair of lines through each dot we store a bit for whether
1245     * exactly one of those lines is ON, and in separate arrays we store whether
1246     * at least one is on and whether at most 1 is on.  (If we know both or
1247     * neither is on that's already stored more directly.)  That's six bits per
1248     * dot.  Bit number n represents the lines shown in dot_type_dirs[n]. */
1249
1250 enum dline {
1251     DLINE_VERT  = 0,
1252     DLINE_HORIZ = 1,
1253     DLINE_UL    = 2,
1254     DLINE_DR    = 3,
1255     DLINE_UR    = 4,
1256     DLINE_DL    = 5
1257 };
1258
1259 #define OPP_DLINE(dline) (dline ^ 1)
1260    
1261
1262 #define SQUARE_DLINES                                                          \
1263                    HANDLE_DLINE(DLINE_UL, RIGHTOF_SQUARE, BELOW_SQUARE, 1, 1); \
1264                    HANDLE_DLINE(DLINE_UR, LEFTOF_SQUARE,  BELOW_SQUARE, 0, 1); \
1265                    HANDLE_DLINE(DLINE_DL, RIGHTOF_SQUARE, ABOVE_SQUARE, 1, 0); \
1266                    HANDLE_DLINE(DLINE_DR, LEFTOF_SQUARE,  ABOVE_SQUARE, 0, 0); 
1267
1268 #define DOT_DLINES                                                       \
1269                    HANDLE_DLINE(DLINE_VERT,  ABOVE_DOT,  BELOW_DOT);     \
1270                    HANDLE_DLINE(DLINE_HORIZ, LEFTOF_DOT, RIGHTOF_DOT);   \
1271                    HANDLE_DLINE(DLINE_UL,    ABOVE_DOT,  LEFTOF_DOT);    \
1272                    HANDLE_DLINE(DLINE_UR,    ABOVE_DOT,  RIGHTOF_DOT);   \
1273                    HANDLE_DLINE(DLINE_DL,    BELOW_DOT,  LEFTOF_DOT);    \
1274                    HANDLE_DLINE(DLINE_DR,    BELOW_DOT,  RIGHTOF_DOT); 
1275
1276 static void array_setall(char *array, char from, char to, int len)
1277 {
1278     char *p = array, *p_old = p;
1279     int len_remaining = len;
1280
1281     while ((p = memchr(p, from, len_remaining))) {
1282         *p = to;
1283         len_remaining -= p - p_old;
1284         p_old = p;
1285     }
1286 }
1287
1288
1289 static int game_states_equal(const game_state *state1,
1290                              const game_state *state2) 
1291 {
1292     /* This deliberately doesn't check _all_ fields, just the ones that make a
1293      * game state 'interesting' from the POV of the solver */
1294     /* XXX review this */
1295     if (state1 == state2)
1296         return 1;
1297
1298     if (!state1 || !state2)
1299         return 0;
1300
1301     if (state1->w != state2->w || state1->h != state2->h)
1302         return 0;
1303
1304     if (memcmp(state1->hl, state2->hl, HL_COUNT(state1)))
1305         return 0;
1306
1307     if (memcmp(state1->vl, state2->vl, VL_COUNT(state1)))
1308         return 0;
1309
1310     return 1;
1311 }
1312
1313 static int solver_states_equal(const solver_state *sstate1,
1314                                const solver_state *sstate2)
1315 {
1316     if (!sstate1) {
1317         if (!sstate2)
1318             return TRUE;
1319         else
1320             return FALSE;
1321     }
1322     
1323     if (!game_states_equal(sstate1->state, sstate2->state)) {
1324         return 0;
1325     }
1326
1327     /* XXX fields missing, needs review */
1328     /* XXX we're deliberately not looking at solver_state as it's only a cache */
1329
1330     if (memcmp(sstate1->dot_atleastone, sstate2->dot_atleastone,
1331                DOT_COUNT(sstate1->state))) {
1332         return 0;
1333     }
1334
1335     if (memcmp(sstate1->dot_atmostone, sstate2->dot_atmostone,
1336                DOT_COUNT(sstate1->state))) {
1337         return 0;
1338     }
1339
1340     /* handle dline_identical here */
1341
1342     return 1;
1343 }
1344
1345 static void dot_setall_dlines(solver_state *sstate, enum dline dl, int i, int j,
1346                               enum line_state line_old, enum line_state line_new) 
1347 {
1348     game_state *state = sstate->state;
1349
1350     /* First line in dline */
1351     switch (dl) {                                             
1352         case DLINE_UL:                                                  
1353         case DLINE_UR:                                                  
1354         case DLINE_VERT:                                                  
1355             if (j > 0 && ABOVE_DOT(state, i, j) == line_old)            
1356                 LV_ABOVE_DOT(state, i, j) = line_new;                   
1357             break;                                                          
1358         case DLINE_DL:                                                  
1359         case DLINE_DR:                                                  
1360             if (j <= (state)->h && BELOW_DOT(state, i, j) == line_old)  
1361                 LV_BELOW_DOT(state, i, j) = line_new;                   
1362             break;
1363         case DLINE_HORIZ:                                                  
1364             if (i > 0 && LEFTOF_DOT(state, i, j) == line_old)           
1365                 LV_LEFTOF_DOT(state, i, j) = line_new;                  
1366             break;                                                          
1367     }
1368
1369     /* Second line in dline */
1370     switch (dl) {                                             
1371         case DLINE_UL:                                                  
1372         case DLINE_DL:                                                  
1373             if (i > 0 && LEFTOF_DOT(state, i, j) == line_old)           
1374                 LV_LEFTOF_DOT(state, i, j) = line_new;                  
1375             break;                                                          
1376         case DLINE_UR:                                                  
1377         case DLINE_DR:                                                  
1378         case DLINE_HORIZ:                                                  
1379             if (i <= (state)->w && RIGHTOF_DOT(state, i, j) == line_old)
1380                 LV_RIGHTOF_DOT(state, i, j) = line_new;                 
1381             break;                                                          
1382         case DLINE_VERT:                                                  
1383             if (j <= (state)->h && BELOW_DOT(state, i, j) == line_old)  
1384                 LV_BELOW_DOT(state, i, j) = line_new;                   
1385             break;                                                          
1386     }
1387 }
1388
1389 static void update_solver_status(solver_state *sstate)
1390 {
1391     if (sstate->solver_status == SOLVER_INCOMPLETE) {
1392         switch (loop_status(sstate->state)) {
1393             case LOOP_NONE:
1394                 sstate->solver_status = SOLVER_INCOMPLETE;
1395                 break;
1396             case LOOP_SOLN:
1397                 if (sstate->solver_status != SOLVER_AMBIGUOUS)
1398                     sstate->solver_status = SOLVER_SOLVED;
1399                 break;
1400             case LOOP_NOT_SOLN:
1401                 sstate->solver_status = SOLVER_MISTAKE;
1402                 break;
1403         }
1404     }
1405 }
1406
1407
1408 /* This will return a dynamically allocated solver_state containing the (more)
1409  * solved grid */
1410 static solver_state *solve_game_rec(const solver_state *sstate_start)
1411 {
1412    int i, j;
1413    int current_yes, current_no, desired;
1414    solver_state *sstate, *sstate_saved, *sstate_tmp;
1415    int t;
1416 /*   char *text; */
1417    solver_state *sstate_rec_solved;
1418    int recursive_soln_count;
1419
1420 #if 0
1421    printf("solve_game_rec: recursion_remaining = %d\n", 
1422           sstate_start->recursion_remaining);
1423 #endif
1424
1425    sstate = dup_solver_state((solver_state *)sstate_start);
1426
1427 #if 0
1428    text = game_text_format(sstate->state);
1429    printf("%s\n", text);
1430    sfree(text);
1431 #endif
1432    
1433 #define RETURN_IF_SOLVED                                 \
1434    do {                                                  \
1435        update_solver_status(sstate);                     \
1436        if (sstate->solver_status != SOLVER_INCOMPLETE) { \
1437            free_solver_state(sstate_saved);              \
1438            return sstate;                                \
1439        }                                                 \
1440    } while (0)
1441
1442    sstate_saved = NULL;
1443    RETURN_IF_SOLVED;
1444
1445 nonrecursive_solver:
1446    
1447    while (1) {
1448        sstate_saved = dup_solver_state(sstate);
1449
1450        /* First we do the 'easy' work, that might cause concrete results */
1451
1452        /* Per-square deductions */
1453        for (j = 0; j < sstate->state->h; ++j) {
1454            for (i = 0; i < sstate->state->w; ++i) {
1455                /* Begin rules that look at the clue (if there is one) */
1456                desired = CLUE_AT(sstate->state, i, j);
1457                if (desired == ' ')
1458                    continue;
1459                desired = desired - '0';
1460                current_yes = square_order(sstate->state, i, j, LINE_YES);
1461                current_no  = square_order(sstate->state, i, j, LINE_NO);
1462
1463                if (desired <= current_yes) {
1464                    square_setall(sstate->state, i, j, LINE_UNKNOWN, LINE_NO);
1465                    continue;
1466                }
1467
1468                if (4 - desired <= current_no) {
1469                    square_setall(sstate->state, i, j, LINE_UNKNOWN, LINE_YES);
1470                }
1471            }
1472        }
1473
1474        RETURN_IF_SOLVED;
1475
1476        /* Per-dot deductions */
1477        for (j = 0; j < sstate->state->h + 1; ++j) {
1478            for (i = 0; i < sstate->state->w + 1; ++i) {
1479                switch (dot_order(sstate->state, i, j, LINE_YES)) {
1480                case 0:
1481                    if (dot_order(sstate->state, i, j, LINE_NO) == 3) {
1482                        dot_setall(sstate->state, i, j, LINE_UNKNOWN, LINE_NO);
1483                    }
1484                    break;
1485                case 1:
1486                    switch (dot_order(sstate->state, i, j, LINE_NO)) {
1487 #define H1(dline, dir1_dot, dir2_dot, dot_howmany)                             \
1488                        if (dir1_dot(sstate->state, i, j) == LINE_UNKNOWN) {    \
1489                            if (dir2_dot(sstate->state, i, j) == LINE_UNKNOWN){ \
1490                                sstate->dot_howmany                             \
1491                                  [i + (sstate->state->w + 1) * j] |= 1<<dline; \
1492                            }                                                   \
1493                        }
1494                        case 1: 
1495 #define HANDLE_DLINE(dline, dir1_dot, dir2_dot)                               \
1496                            H1(dline, dir1_dot, dir2_dot, dot_atleastone)
1497                            /* 1 yes, 1 no, so exactly one of unknowns is yes */
1498                            DOT_DLINES;
1499 #undef HANDLE_DLINE
1500                            /* fall through */
1501                        case 0: 
1502 #define HANDLE_DLINE(dline, dir1_dot, dir2_dot)                               \
1503                            H1(dline, dir1_dot, dir2_dot, dot_atmostone)
1504                            /* 1 yes, fewer than 2 no, so at most one of
1505                             * unknowns is yes */
1506                            DOT_DLINES;
1507 #undef HANDLE_DLINE
1508 #undef H1
1509                            break;
1510                        case 2: /* 1 yes, 2 no */
1511                            dot_setall(sstate->state, i, j, 
1512                                       LINE_UNKNOWN, LINE_YES);
1513                            break;
1514                    }
1515                    break;
1516                case 2:
1517                case 3:
1518                    dot_setall(sstate->state, i, j, LINE_UNKNOWN, LINE_NO);
1519                }
1520 #define HANDLE_DLINE(dline, dir1_dot, dir2_dot)                               \
1521                if (sstate->dot_atleastone                                     \
1522                      [i + (sstate->state->w + 1) * j] & 1<<dline) {           \
1523                    sstate->dot_atmostone                                      \
1524                      [i + (sstate->state->w + 1) * j] |= 1<<OPP_DLINE(dline); \
1525                }
1526                /* If at least one of a dline in a dot is YES, at most one of
1527                 * the opposite dline to that dot must be YES. */
1528                DOT_DLINES;
1529 #undef HANDLE_DLINE
1530            }
1531        }
1532        
1533        /* More obscure per-square operations */
1534        for (j = 0; j < sstate->state->h; ++j) {
1535            for (i = 0; i < sstate->state->w; ++i) {
1536 #define H1(dline, dir1_sq, dir2_sq, a, b, dot_howmany, line_query, line_set)  \
1537                if (sstate->dot_howmany[i+a + (sstate->state->w + 1) * (j+b)] &\
1538                        1<<dline) {                                            \
1539                    t = dir1_sq(sstate->state, i, j);                          \
1540                    if (t == line_query)                                       \
1541                        dir2_sq(sstate->state, i, j) = line_set;               \
1542                    else {                                                     \
1543                        t = dir2_sq(sstate->state, i, j);                      \
1544                        if (t == line_query)                                   \
1545                            dir1_sq(sstate->state, i, j) = line_set;           \
1546                    }                                                          \
1547                }
1548 #define HANDLE_DLINE(dline, dir1_sq, dir2_sq, a, b)                 \
1549                H1(dline, dir1_sq, dir2_sq, a, b, dot_atmostone,     \
1550                   LINE_YES, LINE_NO)
1551                /* If at most one of the DLINE is on, and one is definitely on,
1552                 * set the other to definitely off */
1553                SQUARE_DLINES;
1554 #undef HANDLE_DLINE
1555
1556 #define HANDLE_DLINE(dline, dir1_sq, dir2_sq, a, b)                 \
1557                H1(dline, dir1_sq, dir2_sq, a, b, dot_atleastone,    \
1558                   LINE_NO, LINE_YES)
1559                /* If at least one of the DLINE is on, and one is definitely
1560                 * off, set the other to definitely on */
1561                SQUARE_DLINES;
1562 #undef HANDLE_DLINE
1563 #undef H1
1564
1565                switch (CLUE_AT(sstate->state, i, j)) {
1566                    case '0':
1567                    case '1':
1568 #define HANDLE_DLINE(dline, dir1_sq, dir2_sq, a, b)                          \
1569                        /* At most one of any DLINE can be set */             \
1570                        sstate->dot_atmostone                                 \
1571                          [i+a + (sstate->state->w + 1) * (j+b)] |= 1<<dline; \
1572                        /* This DLINE provides enough YESes to solve the clue */\
1573                        if (sstate->dot_atleastone                            \
1574                              [i+a + (sstate->state->w + 1) * (j+b)] &        \
1575                            1<<dline) {                                       \
1576                            dot_setall_dlines(sstate, OPP_DLINE(dline),       \
1577                                              i+(1-a), j+(1-b),               \
1578                                              LINE_UNKNOWN, LINE_NO);         \
1579                        }
1580                        SQUARE_DLINES;
1581 #undef HANDLE_DLINE
1582                        break;
1583                    case '2':
1584 #define H1(dline, dot_at1one, dot_at2one, a, b)                          \
1585                if (sstate->dot_at1one                                    \
1586                      [i+a + (sstate->state->w + 1) * (j+b)] &            \
1587                    1<<dline) {                                           \
1588                    sstate->dot_at2one                                    \
1589                      [i+(1-a) + (sstate->state->w + 1) * (j+(1-b))] |=   \
1590                        1<<OPP_DLINE(dline);                              \
1591                }
1592 #define HANDLE_DLINE(dline, dir1_sq, dir2_sq, a, b)             \
1593             H1(dline, dot_atleastone, dot_atmostone, a, b);     \
1594             H1(dline, dot_atmostone, dot_atleastone, a, b); 
1595                        /* If at least one of one DLINE is set, at most one of
1596                         * the opposing one is and vice versa */
1597                        SQUARE_DLINES;
1598 #undef HANDLE_DLINE
1599 #undef H1
1600                        break;
1601                    case '3':
1602                    case '4':
1603 #define HANDLE_DLINE(dline, dir1_sq, dir2_sq, a, b)                           \
1604                        /* At least one of any DLINE can be set */             \
1605                        sstate->dot_atleastone                                 \
1606                          [i+a + (sstate->state->w + 1) * (j+b)] |= 1<<dline;  \
1607                        /* This DLINE provides enough NOs to solve the clue */ \
1608                        if (sstate->dot_atmostone                              \
1609                              [i+a + (sstate->state->w + 1) * (j+b)] &         \
1610                            1<<dline) {                                        \
1611                            dot_setall_dlines(sstate, OPP_DLINE(dline),        \
1612                                              i+(1-a), j+(1-b),                \
1613                                              LINE_UNKNOWN, LINE_YES);         \
1614                        }
1615                        SQUARE_DLINES;
1616 #undef HANDLE_DLINE
1617                        break;
1618                }
1619            }
1620        }
1621
1622        if (solver_states_equal(sstate, sstate_saved)) {
1623            int edgecount = 0, clues = 0, satclues = 0, sm1clues = 0;
1624            int d;
1625
1626            /*
1627             * Go through the grid and update for all the new edges.
1628             * Since merge_dots() is idempotent, the simplest way to
1629             * do this is just to update for _all_ the edges.
1630             * 
1631             * Also, while we're here, we count the edges, count the
1632             * clues, count the satisfied clues, and count the
1633             * satisfied-minus-one clues.
1634             */
1635            for (j = 0; j <= sstate->state->h; ++j) {
1636                for (i = 0; i <= sstate->state->w; ++i) {
1637                    if (RIGHTOF_DOT(sstate->state, i, j) == LINE_YES) {
1638                        merge_dots(sstate, i, j, i+1, j);
1639                        edgecount++;
1640                    }
1641                    if (BELOW_DOT(sstate->state, i, j) == LINE_YES) {
1642                        merge_dots(sstate, i, j, i, j+1);
1643                        edgecount++;
1644                    }
1645
1646                    if (CLUE_AT(sstate->state, i, j) != ' ') {
1647                        int c = CLUE_AT(sstate->state, i, j) - '0';
1648                        int o = square_order(sstate->state, i, j, LINE_YES);
1649                        if (o == c)
1650                            satclues++;
1651                        else if (o == c-1)
1652                            sm1clues++;
1653                        clues++;
1654                    }
1655                }
1656            }
1657
1658            /*
1659             * Now go through looking for LINE_UNKNOWN edges which
1660             * connect two dots that are already in the same
1661             * equivalence class. If we find one, test to see if the
1662             * loop it would create is a solution.
1663             */
1664            for (j = 0; j <= sstate->state->h; ++j) {
1665                for (i = 0; i <= sstate->state->w; ++i) {
1666                    for (d = 0; d < 2; d++) {
1667                        int i2, j2, eqclass, val;
1668
1669                        if (d == 0) {
1670                            if (RIGHTOF_DOT(sstate->state, i, j) !=
1671                                LINE_UNKNOWN)
1672                                continue;
1673                            i2 = i+1;
1674                            j2 = j;
1675                        } else {
1676                            if (BELOW_DOT(sstate->state, i, j) !=
1677                                LINE_UNKNOWN)
1678                                continue;
1679                            i2 = i;
1680                            j2 = j+1;
1681                        }
1682
1683                        eqclass = dsf_canonify(sstate->dotdsf,
1684                                               j * (sstate->state->w+1) + i);
1685                        if (eqclass != dsf_canonify(sstate->dotdsf,
1686                                                    j2 * (sstate->state->w+1) +
1687                                                    i2))
1688                            continue;
1689
1690                        val = LINE_NO;  /* loop is bad until proven otherwise */
1691
1692                        /*
1693                         * This edge would form a loop. Next
1694                         * question: how long would the loop be?
1695                         * Would it equal the total number of edges
1696                         * (plus the one we'd be adding if we added
1697                         * it)?
1698                         */
1699                        if (sstate->looplen[eqclass] == edgecount + 1) {
1700                            int sm1_nearby;
1701                            int cx, cy;
1702
1703                            /*
1704                             * This edge would form a loop which
1705                             * took in all the edges in the entire
1706                             * grid. So now we need to work out
1707                             * whether it would be a valid solution
1708                             * to the puzzle, which means we have to
1709                             * check if it satisfies all the clues.
1710                             * This means that every clue must be
1711                             * either satisfied or satisfied-minus-
1712                             * 1, and also that the number of
1713                             * satisfied-minus-1 clues must be at
1714                             * most two and they must lie on either
1715                             * side of this edge.
1716                             */
1717                            sm1_nearby = 0;
1718                            cx = i - (j2-j);
1719                            cy = j - (i2-i);
1720                            if (CLUE_AT(sstate->state, cx,cy) != ' ' &&
1721                                square_order(sstate->state, cx,cy, LINE_YES) ==
1722                                CLUE_AT(sstate->state, cx,cy) - '0' - 1)
1723                                sm1_nearby++;
1724                            if (CLUE_AT(sstate->state, i, j) != ' ' &&
1725                                square_order(sstate->state, i, j, LINE_YES) ==
1726                                CLUE_AT(sstate->state, i, j) - '0' - 1)
1727                                sm1_nearby++;
1728                            if (sm1clues == sm1_nearby &&
1729                                sm1clues + satclues == clues)
1730                                val = LINE_YES;  /* loop is good! */
1731                        }
1732
1733                        /*
1734                         * Right. Now we know that adding this edge
1735                         * would form a loop, and we know whether
1736                         * that loop would be a viable solution or
1737                         * not.
1738                         * 
1739                         * If adding this edge produces a solution,
1740                         * then we know we've found _a_ solution but
1741                         * we don't know that it's _the_ solution -
1742                         * if it were provably the solution then
1743                         * we'd have deduced this edge some time ago
1744                         * without the need to do loop detection. So
1745                         * in this state we return SOLVER_AMBIGUOUS,
1746                         * which has the effect that hitting Solve
1747                         * on a user-provided puzzle will fill in a
1748                         * solution but using the solver to
1749                         * construct new puzzles won't consider this
1750                         * a reasonable deduction for the user to
1751                         * make.
1752                         */
1753                        if (d == 0)
1754                            LV_RIGHTOF_DOT(sstate->state, i, j) = val;
1755                        else
1756                            LV_BELOW_DOT(sstate->state, i, j) = val;
1757                        if (val == LINE_YES) {
1758                            sstate->solver_status = SOLVER_AMBIGUOUS;
1759                            goto finished_loop_checking;
1760                        }
1761                    }
1762                }
1763            }
1764
1765            finished_loop_checking:
1766
1767            RETURN_IF_SOLVED;
1768        }
1769
1770        if (solver_states_equal(sstate, sstate_saved)) {
1771            /* Solver has stopped making progress so we terminate */
1772            free_solver_state(sstate_saved); 
1773            break;
1774        }
1775
1776        free_solver_state(sstate_saved); 
1777    }
1778
1779    if (sstate->solver_status == SOLVER_SOLVED ||
1780        sstate->solver_status == SOLVER_AMBIGUOUS) {
1781        /* s/LINE_UNKNOWN/LINE_NO/g */
1782        array_setall(sstate->state->hl, LINE_UNKNOWN, LINE_NO, 
1783                HL_COUNT(sstate->state));
1784        array_setall(sstate->state->vl, LINE_UNKNOWN, LINE_NO, 
1785                VL_COUNT(sstate->state));
1786        return sstate;
1787    }
1788
1789    /* Perform recursive calls */
1790    if (sstate->recursion_remaining) {
1791        sstate->recursion_remaining--;
1792    
1793        sstate_saved = dup_solver_state(sstate);
1794
1795        recursive_soln_count = 0;
1796        sstate_rec_solved = NULL;
1797
1798        /* Memory management: 
1799         * sstate_saved won't be modified but needs to be freed when we have
1800         * finished with it.
1801         * sstate is expected to contain our 'best' solution by the time we
1802         * finish this section of code.  It's the thing we'll try adding lines
1803         * to, seeing if they make it more solvable.
1804         * If sstate_rec_solved is non-NULL, it will supersede sstate
1805         * eventually.  sstate_tmp should not hold a value persistently.
1806         */
1807
1808        /* NB SOLVER_AMBIGUOUS is like SOLVER_SOLVED except the solver is aware
1809         * of the possibility of additional solutions.  So as soon as we have a
1810         * SOLVER_AMBIGUOUS we can safely propagate it back to our caller, but
1811         * if we get a SOLVER_SOLVED we want to keep trying in case we find
1812         * further solutions and have to mark it ambiguous.
1813         */
1814
1815 #define DO_RECURSIVE_CALL(dir_dot)                                         \
1816        if (dir_dot(sstate->state, i, j) == LINE_UNKNOWN) {                 \
1817            debug(("Trying " #dir_dot " at [%d,%d]\n", i, j));               \
1818            LV_##dir_dot(sstate->state, i, j) = LINE_YES;                   \
1819            sstate_tmp = solve_game_rec(sstate);                            \
1820            switch (sstate_tmp->solver_status) {                            \
1821                case SOLVER_AMBIGUOUS:                                      \
1822                    debug(("Solver ambiguous, returning\n"));                \
1823                    sstate_rec_solved = sstate_tmp;                         \
1824                    goto finished_recursion;                                \
1825                case SOLVER_SOLVED:                                         \
1826                    switch (++recursive_soln_count) {                       \
1827                        case 1:                                             \
1828                            debug(("One solution found\n"));                 \
1829                            sstate_rec_solved = sstate_tmp;                 \
1830                            break;                                          \
1831                        case 2:                                             \
1832                            debug(("Ambiguous solutions found\n"));          \
1833                            free_solver_state(sstate_tmp);                  \
1834                            sstate_rec_solved->solver_status = SOLVER_AMBIGUOUS;\
1835                            goto finished_recursion;                        \
1836                        default:                                            \
1837                            assert(!"recursive_soln_count out of range");   \
1838                            break;                                          \
1839                    }                                                       \
1840                    break;                                                  \
1841                case SOLVER_MISTAKE:                                        \
1842                    debug(("Non-solution found\n"));                         \
1843                    free_solver_state(sstate_tmp);                          \
1844                    free_solver_state(sstate_saved);                        \
1845                    LV_##dir_dot(sstate->state, i, j) = LINE_NO;            \
1846                    goto nonrecursive_solver;                               \
1847                case SOLVER_INCOMPLETE:                                     \
1848                    debug(("Recursive step inconclusive\n"));                \
1849                    free_solver_state(sstate_tmp);                          \
1850                    break;                                                  \
1851            }                                                               \
1852            free_solver_state(sstate);                                      \
1853            sstate = dup_solver_state(sstate_saved);                        \
1854        }
1855        
1856        for (j = 0; j < sstate->state->h + 1; ++j) {
1857            for (i = 0; i < sstate->state->w + 1; ++i) {
1858                /* Only perform recursive calls on 'loose ends' */
1859                if (dot_order(sstate->state, i, j, LINE_YES) == 1) {
1860                    if (LEFTOF_DOT(sstate->state, i, j) == LINE_UNKNOWN)
1861                        DO_RECURSIVE_CALL(LEFTOF_DOT);
1862                    if (RIGHTOF_DOT(sstate->state, i, j) == LINE_UNKNOWN)
1863                        DO_RECURSIVE_CALL(RIGHTOF_DOT);
1864                    if (ABOVE_DOT(sstate->state, i, j) == LINE_UNKNOWN)
1865                        DO_RECURSIVE_CALL(ABOVE_DOT);
1866                    if (BELOW_DOT(sstate->state, i, j) == LINE_UNKNOWN)
1867                        DO_RECURSIVE_CALL(BELOW_DOT);
1868                }
1869            }
1870        }
1871
1872 finished_recursion:
1873
1874        if (sstate_rec_solved) {
1875            free_solver_state(sstate);
1876            sstate = sstate_rec_solved;
1877        } 
1878    }
1879
1880    return sstate;
1881 }
1882
1883 /* XXX bits of solver that may come in handy one day */
1884 #if 0
1885 #define HANDLE_DLINE(dline, dir1_dot, dir2_dot)                         \
1886                    /* dline from this dot that's entirely unknown must have 
1887                     * both lines identical */                           \
1888                    if (dir1_dot(sstate->state, i, j) == LINE_UNKNOWN &&       \
1889                        dir2_dot(sstate->state, i, j) == LINE_UNKNOWN) {       \
1890                        sstate->dline_identical[i + (sstate->state->w + 1) * j] |= \
1891                            1<<dline;                                    \
1892                    } else if (sstate->dline_identical[i +
1893                                                       (sstate->state->w + 1) * j] &\
1894                               1<<dline) {                                   \
1895                        /* If they're identical and one is known do the obvious 
1896                         * thing */                                      \
1897                        t = dir1_dot(sstate->state, i, j);                     \
1898                        if (t != LINE_UNKNOWN)                           \
1899                            dir2_dot(sstate->state, i, j) = t;                 \
1900                        else {                                           \
1901                            t = dir2_dot(sstate->state, i, j);                 \
1902                            if (t != LINE_UNKNOWN)                       \
1903                                dir1_dot(sstate->state, i, j) = t;             \
1904                        }                                                \
1905                    }                                                    \
1906                    DOT_DLINES;
1907 #undef HANDLE_DLINE
1908 #endif
1909
1910 #if 0
1911 #define HANDLE_DLINE(dline, dir1_sq, dir2_sq, a, b) \
1912                        if (sstate->dline_identical[i+a +                     \
1913                                                    (sstate->state->w + 1) * (j+b)] &\
1914                            1<<dline) {                                       \
1915                            dir1_sq(sstate->state, i, j) = LINE_YES;                \
1916                            dir2_sq(sstate->state, i, j) = LINE_YES;                \
1917                        }
1918                        /* If two lines are the same they must be on */
1919                        SQUARE_DLINES;
1920 #undef HANDLE_DLINE
1921 #endif
1922
1923
1924 #if 0
1925 #define HANDLE_DLINE(dline, dir1_sq, dir2_sq, a, b) \
1926                if (sstate->dot_atmostone[i+a + (sstate->state->w + 1) * (j+b)] &  \
1927                    1<<dline) {                                   \
1928                    if (square_order(sstate->state, i, j,  LINE_UNKNOWN) - 1 ==  \
1929                        CLUE_AT(sstate->state, i, j) - '0') {      \
1930                        square_setall(sstate->state, i, j, LINE_UNKNOWN, LINE_YES); \
1931                            /* XXX the following may overwrite known data! */ \
1932                        dir1_sq(sstate->state, i, j) = LINE_UNKNOWN;  \
1933                        dir2_sq(sstate->state, i, j) = LINE_UNKNOWN;  \
1934                    }                                  \
1935                }
1936                SQUARE_DLINES;
1937 #undef HANDLE_DLINE
1938 #endif
1939
1940 #if 0
1941 #define HANDLE_DLINE(dline, dir1_sq, dir2_sq, a, b) \
1942                        if (sstate->dline_identical[i+a + 
1943                                                    (sstate->state->w + 1) * (j+b)] &\
1944                            1<<dline) {                                       \
1945                            dir1_sq(sstate->state, i, j) = LINE_NO;                 \
1946                            dir2_sq(sstate->state, i, j) = LINE_NO;                 \
1947                        }
1948                        /* If two lines are the same they must be off */
1949                        SQUARE_DLINES;
1950 #undef HANDLE_DLINE
1951 #endif
1952
1953 static char *solve_game(game_state *state, game_state *currstate,
1954                         char *aux, char **error)
1955 {
1956     char *soln = NULL;
1957     solver_state *sstate, *new_sstate;
1958
1959     sstate = new_solver_state(state);
1960     new_sstate = solve_game_rec(sstate);
1961
1962     if (new_sstate->solver_status == SOLVER_SOLVED) {
1963         soln = encode_solve_move(new_sstate->state);
1964     } else if (new_sstate->solver_status == SOLVER_AMBIGUOUS) {
1965         soln = encode_solve_move(new_sstate->state);
1966         /**error = "Solver found ambiguous solutions"; */
1967     } else {
1968         soln = encode_solve_move(new_sstate->state);
1969         /**error = "Solver failed"; */
1970     }
1971
1972     free_solver_state(new_sstate);
1973     free_solver_state(sstate);
1974
1975     return soln;
1976 }
1977
1978 static char *game_text_format(game_state *state)
1979 {
1980     int i, j;
1981     int len;
1982     char *ret, *rp;
1983
1984     len = (2 * state->w + 2) * (2 * state->h + 1);
1985     rp = ret = snewn(len + 1, char);
1986     
1987 #define DRAW_HL                          \
1988     switch (ABOVE_SQUARE(state, i, j)) { \
1989         case LINE_YES:                   \
1990             rp += sprintf(rp, " -");     \
1991             break;                       \
1992         case LINE_NO:                    \
1993             rp += sprintf(rp, " x");     \
1994             break;                       \
1995         case LINE_UNKNOWN:               \
1996             rp += sprintf(rp, "  ");     \
1997             break;                       \
1998         default:                         \
1999             assert(!"Illegal line state for HL");\
2000     }
2001
2002 #define DRAW_VL                          \
2003     switch (LEFTOF_SQUARE(state, i, j)) {\
2004         case LINE_YES:                   \
2005             rp += sprintf(rp, "|");      \
2006             break;                       \
2007         case LINE_NO:                    \
2008             rp += sprintf(rp, "x");      \
2009             break;                       \
2010         case LINE_UNKNOWN:               \
2011             rp += sprintf(rp, " ");      \
2012             break;                       \
2013         default:                         \
2014             assert(!"Illegal line state for VL");\
2015     }
2016     
2017     for (j = 0; j < state->h; ++j) {
2018         for (i = 0; i < state->w; ++i) {
2019             DRAW_HL;
2020         }
2021         rp += sprintf(rp, " \n");
2022         for (i = 0; i < state->w; ++i) {
2023             DRAW_VL;
2024             rp += sprintf(rp, "%c", CLUE_AT(state, i, j));
2025         }
2026         DRAW_VL;
2027         rp += sprintf(rp, "\n");
2028     }
2029     for (i = 0; i < state->w; ++i) {
2030         DRAW_HL;
2031     }
2032     rp += sprintf(rp, " \n");
2033     
2034     assert(strlen(ret) == len);
2035     return ret;
2036 }
2037
2038 static game_ui *new_ui(game_state *state)
2039 {
2040     return NULL;
2041 }
2042
2043 static void free_ui(game_ui *ui)
2044 {
2045 }
2046
2047 static char *encode_ui(game_ui *ui)
2048 {
2049     return NULL;
2050 }
2051
2052 static void decode_ui(game_ui *ui, char *encoding)
2053 {
2054 }
2055
2056 static void game_changed_state(game_ui *ui, game_state *oldstate,
2057                                game_state *newstate)
2058 {
2059 }
2060
2061 struct game_drawstate {
2062     int started;
2063     int tilesize;
2064     int flashing;
2065     char *hl, *vl;
2066 };
2067
2068 static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
2069                             int x, int y, int button)
2070 {
2071     int hl_selected;
2072     int i, j, p, q; 
2073     char *ret, buf[80];
2074     char button_char = ' ';
2075     enum line_state old_state;
2076
2077     button &= ~MOD_MASK;
2078
2079     /* Around each line is a diamond-shaped region where points within that
2080      * region are closer to this line than any other.  We assume any click
2081      * within a line's diamond was meant for that line.  It would all be a lot
2082      * simpler if the / and % operators respected modulo arithmetic properly
2083      * for negative numbers. */
2084     
2085     x -= BORDER;
2086     y -= BORDER;
2087
2088     /* Get the coordinates of the square the click was in */
2089     i = (x + TILE_SIZE) / TILE_SIZE - 1; 
2090     j = (y + TILE_SIZE) / TILE_SIZE - 1;
2091
2092     /* Get the precise position inside square [i,j] */
2093     p = (x + TILE_SIZE) % TILE_SIZE;
2094     q = (y + TILE_SIZE) % TILE_SIZE;
2095
2096     /* After this bit of magic [i,j] will correspond to the point either above
2097      * or to the left of the line selected */
2098     if (p > q) { 
2099         if (TILE_SIZE - p > q) {
2100             hl_selected = TRUE;
2101         } else {
2102             hl_selected = FALSE;
2103             ++i;
2104         }
2105     } else {
2106         if (TILE_SIZE - q > p) {
2107             hl_selected = FALSE;
2108         } else {
2109             hl_selected = TRUE;
2110             ++j;
2111         }
2112     }
2113
2114     if (i < 0 || j < 0)
2115         return NULL;
2116
2117     if (hl_selected) {
2118         if (i >= state->w || j >= state->h + 1)
2119             return NULL;
2120     } else { 
2121         if (i >= state->w + 1 || j >= state->h)
2122             return NULL;
2123     }
2124
2125     /* I think it's only possible to play this game with mouse clicks, sorry */
2126     /* Maybe will add mouse drag support some time */
2127     if (hl_selected)
2128         old_state = RIGHTOF_DOT(state, i, j);
2129     else
2130         old_state = BELOW_DOT(state, i, j);
2131
2132     switch (button) {
2133         case LEFT_BUTTON:
2134             switch (old_state) {
2135                 case LINE_UNKNOWN:
2136                     button_char = 'y';
2137                     break;
2138                 case LINE_YES:
2139                 case LINE_NO:
2140                     button_char = 'u';
2141                     break;
2142             }
2143             break;
2144         case MIDDLE_BUTTON:
2145             button_char = 'u';
2146             break;
2147         case RIGHT_BUTTON:
2148             switch (old_state) {
2149                 case LINE_UNKNOWN:
2150                     button_char = 'n';
2151                     break;
2152                 case LINE_NO:
2153                 case LINE_YES:
2154                     button_char = 'u';
2155                     break;
2156             }
2157             break;
2158         default:
2159             return NULL;
2160     }
2161
2162
2163     sprintf(buf, "%d,%d%c%c", i, j, hl_selected ? 'h' : 'v', button_char);
2164     ret = dupstr(buf);
2165
2166     return ret;
2167 }
2168
2169 static game_state *execute_move(game_state *state, char *move)
2170 {
2171     int i, j;
2172     game_state *newstate = dup_game(state);
2173
2174     if (move[0] == 'S') {
2175         move++;
2176         newstate->cheated = TRUE;
2177     }
2178
2179     while (*move) {
2180         i = atoi(move);
2181         move = strchr(move, ',');
2182         if (!move)
2183             goto fail;
2184         j = atoi(++move);
2185         move += strspn(move, "1234567890");
2186         switch (*(move++)) {
2187             case 'h':
2188                 if (i >= newstate->w || j > newstate->h)
2189                     goto fail;
2190                 switch (*(move++)) {
2191                     case 'y':
2192                         LV_RIGHTOF_DOT(newstate, i, j) = LINE_YES;
2193                         break;
2194                     case 'n':
2195                         LV_RIGHTOF_DOT(newstate, i, j) = LINE_NO;
2196                         break;
2197                     case 'u':
2198                         LV_RIGHTOF_DOT(newstate, i, j) = LINE_UNKNOWN;
2199                         break;
2200                     default:
2201                         goto fail;
2202                 }
2203                 break;
2204             case 'v':
2205                 if (i > newstate->w || j >= newstate->h)
2206                     goto fail;
2207                 switch (*(move++)) {
2208                     case 'y':
2209                         LV_BELOW_DOT(newstate, i, j) = LINE_YES;
2210                         break;
2211                     case 'n':
2212                         LV_BELOW_DOT(newstate, i, j) = LINE_NO;
2213                         break;
2214                     case 'u':
2215                         LV_BELOW_DOT(newstate, i, j) = LINE_UNKNOWN;
2216                         break;
2217                     default:
2218                         goto fail;
2219                 }
2220                 break;
2221             default:
2222                 goto fail;
2223         }
2224     }
2225
2226     /*
2227      * Check for completion.
2228      */
2229     for (j = 0; j <= newstate->h; j++) {
2230         for (i = 0; i < newstate->w; i++)
2231             if (LV_RIGHTOF_DOT(newstate, i, j) == LINE_YES)
2232                 break;
2233         if (i < newstate->w)
2234             break;
2235     }
2236     if (j <= newstate->h) {
2237         int prevdir = 'R';
2238         int x = i, y = j;
2239         int looplen, count;
2240
2241         /*
2242          * We've found a horizontal edge at (i,j). Follow it round
2243          * to see if it's part of a loop.
2244          */
2245         looplen = 0;
2246         while (1) {
2247             int order = dot_order(newstate, x, y, LINE_YES);
2248             if (order != 2)
2249                 goto completion_check_done;
2250
2251             if (LEFTOF_DOT(newstate, x, y) == LINE_YES && prevdir != 'L') {
2252                 x--;
2253                 prevdir = 'R';
2254             } else if (RIGHTOF_DOT(newstate, x, y) == LINE_YES &&
2255                        prevdir != 'R') {
2256                 x++;
2257                 prevdir = 'L';
2258             } else if (ABOVE_DOT(newstate, x, y) == LINE_YES &&
2259                        prevdir != 'U') {
2260                 y--;
2261                 prevdir = 'D';
2262             } else if (BELOW_DOT(newstate, x, y) == LINE_YES &&
2263                        prevdir != 'D') {
2264                 y++;
2265                 prevdir = 'U';
2266             } else {
2267                 assert(!"Can't happen");   /* dot_order guarantees success */
2268             }
2269
2270             looplen++;
2271
2272             if (x == i && y == j)
2273                 break;
2274         }
2275
2276         if (x != i || y != j || looplen == 0)
2277             goto completion_check_done;
2278
2279         /*
2280          * We've traced our way round a loop, and we know how many
2281          * line segments were involved. Count _all_ the line
2282          * segments in the grid, to see if the loop includes them
2283          * all.
2284          */
2285         count = 0;
2286         for (j = 0; j <= newstate->h; j++)
2287             for (i = 0; i <= newstate->w; i++)
2288                 count += ((RIGHTOF_DOT(newstate, i, j) == LINE_YES) +
2289                           (BELOW_DOT(newstate, i, j) == LINE_YES));
2290         assert(count >= looplen);
2291         if (count != looplen)
2292             goto completion_check_done;
2293
2294         /*
2295          * The grid contains one closed loop and nothing else.
2296          * Check that all the clues are satisfied.
2297          */
2298         for (j = 0; j < newstate->h; ++j) {
2299             for (i = 0; i < newstate->w; ++i) {
2300                 int n = CLUE_AT(newstate, i, j);
2301                 if (n != ' ') {
2302                     if (square_order(newstate, i, j, LINE_YES) != n - '0') {
2303                         goto completion_check_done;
2304                     }
2305                 }
2306             }
2307         }
2308
2309         /*
2310          * Completed!
2311          */
2312         newstate->solved = TRUE;
2313     }
2314
2315 completion_check_done:
2316     return newstate;
2317
2318 fail:
2319     free_game(newstate);
2320     return NULL;
2321 }
2322
2323 /* ----------------------------------------------------------------------
2324  * Drawing routines.
2325  */
2326
2327 #define SIZE(d) ((d) * TILE_SIZE + 2 * BORDER + 1)
2328
2329 static void game_compute_size(game_params *params, int tilesize,
2330                               int *x, int *y)
2331 {
2332     struct { int tilesize; } ads, *ds = &ads;
2333     ads.tilesize = tilesize;
2334
2335     *x = SIZE(params->w);
2336     *y = SIZE(params->h);
2337 }
2338
2339 static void game_set_size(drawing *dr, game_drawstate *ds,
2340                           game_params *params, int tilesize)
2341 {
2342     ds->tilesize = tilesize;
2343 }
2344
2345 static float *game_colours(frontend *fe, game_state *state, int *ncolours)
2346 {
2347     float *ret = snewn(4 * NCOLOURS, float);
2348
2349     frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
2350
2351     ret[COL_FOREGROUND * 3 + 0] = 0.0F;
2352     ret[COL_FOREGROUND * 3 + 1] = 0.0F;
2353     ret[COL_FOREGROUND * 3 + 2] = 0.0F;
2354
2355     ret[COL_HIGHLIGHT * 3 + 0] = 1.0F;
2356     ret[COL_HIGHLIGHT * 3 + 1] = 1.0F;
2357     ret[COL_HIGHLIGHT * 3 + 2] = 1.0F;
2358
2359     *ncolours = NCOLOURS;
2360     return ret;
2361 }
2362
2363 static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
2364 {
2365     struct game_drawstate *ds = snew(struct game_drawstate);
2366
2367     ds->tilesize = 0;
2368     ds->started = 0;
2369     ds->hl = snewn(HL_COUNT(state), char);
2370     ds->vl = snewn(VL_COUNT(state), char);
2371     ds->flashing = 0;
2372
2373     memset(ds->hl, LINE_UNKNOWN, HL_COUNT(state));
2374     memset(ds->vl, LINE_UNKNOWN, VL_COUNT(state));
2375
2376     return ds;
2377 }
2378
2379 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
2380 {
2381     sfree(ds->hl);
2382     sfree(ds->vl);
2383     sfree(ds);
2384 }
2385
2386 static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
2387                         game_state *state, int dir, game_ui *ui,
2388                         float animtime, float flashtime)
2389 {
2390     int i, j;
2391     int w = state->w, h = state->h;
2392     char c[2];
2393     int line_colour, flash_changed;
2394
2395     if (!ds->started) {
2396         /*
2397          * The initial contents of the window are not guaranteed and
2398          * can vary with front ends. To be on the safe side, all games
2399          * should start by drawing a big background-colour rectangle
2400          * covering the whole window.
2401          */
2402         draw_rect(dr, 0, 0, SIZE(state->w), SIZE(state->h), COL_BACKGROUND);
2403
2404         /* Draw dots */
2405         for (j = 0; j < h + 1; ++j) {
2406             for (i = 0; i < w + 1; ++i) {
2407                 draw_rect(dr, 
2408                           BORDER + i * TILE_SIZE - LINEWIDTH/2,
2409                           BORDER + j * TILE_SIZE - LINEWIDTH/2,
2410                           LINEWIDTH, LINEWIDTH, COL_FOREGROUND);
2411             }
2412         }
2413
2414         /* Draw clues */
2415         for (j = 0; j < h; ++j) {
2416             for (i = 0; i < w; ++i) {
2417                 c[0] = CLUE_AT(state, i, j);
2418                 c[1] = '\0';
2419                 draw_text(dr, 
2420                           BORDER + i * TILE_SIZE + TILE_SIZE/2,
2421                           BORDER + j * TILE_SIZE + TILE_SIZE/2,
2422                           FONT_VARIABLE, TILE_SIZE/2, 
2423                           ALIGN_VCENTRE | ALIGN_HCENTRE, COL_FOREGROUND, c);
2424             }
2425         }
2426         draw_update(dr, 0, 0,
2427                     state->w * TILE_SIZE + 2*BORDER + 1,
2428                     state->h * TILE_SIZE + 2*BORDER + 1);
2429         ds->started = TRUE;
2430     }
2431
2432     if (flashtime > 0 && 
2433         (flashtime <= FLASH_TIME/3 ||
2434          flashtime >= FLASH_TIME*2/3)) {
2435         flash_changed = !ds->flashing;
2436         ds->flashing = TRUE;
2437         line_colour = COL_HIGHLIGHT;
2438     } else {
2439         flash_changed = ds->flashing;
2440         ds->flashing = FALSE;
2441         line_colour = COL_FOREGROUND;
2442     }
2443
2444 #define CROSS_SIZE (3 * LINEWIDTH / 2)
2445     
2446 #define CLEAR_VL(i, j) do {                                                \
2447                            draw_rect(dr,                                   \
2448                                  BORDER + i * TILE_SIZE - CROSS_SIZE,      \
2449                                  BORDER + j * TILE_SIZE + LINEWIDTH/2,     \
2450                                  CROSS_SIZE * 2,                           \
2451                                  TILE_SIZE - LINEWIDTH,                    \
2452                                  COL_BACKGROUND);                          \
2453                            draw_update(dr,                                 \
2454                                        BORDER + i * TILE_SIZE - CROSS_SIZE, \
2455                                        BORDER + j * TILE_SIZE - CROSS_SIZE, \
2456                                        CROSS_SIZE*2,                       \
2457                                        TILE_SIZE + CROSS_SIZE*2);          \
2458                         } while (0)
2459
2460 #define CLEAR_HL(i, j) do {                                                \
2461                            draw_rect(dr,                                   \
2462                                  BORDER + i * TILE_SIZE + LINEWIDTH/2,     \
2463                                  BORDER + j * TILE_SIZE - CROSS_SIZE,      \
2464                                  TILE_SIZE - LINEWIDTH,                    \
2465                                  CROSS_SIZE * 2,                           \
2466                                  COL_BACKGROUND);                          \
2467                            draw_update(dr,                                 \
2468                                        BORDER + i * TILE_SIZE - CROSS_SIZE, \
2469                                        BORDER + j * TILE_SIZE - CROSS_SIZE, \
2470                                        TILE_SIZE + CROSS_SIZE*2,           \
2471                                        CROSS_SIZE*2);                      \
2472                         } while (0)
2473
2474     /* Vertical lines */
2475     for (j = 0; j < h; ++j) {
2476         for (i = 0; i < w + 1; ++i) {
2477             switch (BELOW_DOT(state, i, j)) {
2478                 case LINE_UNKNOWN:
2479                     if (ds->vl[i + (w + 1) * j] != BELOW_DOT(state, i, j)) {
2480                         CLEAR_VL(i, j);
2481                     }
2482                     break;
2483                 case LINE_YES:
2484                     if (ds->vl[i + (w + 1) * j] != BELOW_DOT(state, i, j) ||
2485                         flash_changed) {
2486                         CLEAR_VL(i, j);
2487                         draw_rect(dr,
2488                                   BORDER + i * TILE_SIZE - LINEWIDTH/2,
2489                                   BORDER + j * TILE_SIZE + LINEWIDTH/2,
2490                                   LINEWIDTH, TILE_SIZE - LINEWIDTH, 
2491                                   line_colour);
2492                     }
2493                     break;
2494                 case LINE_NO:
2495                     if (ds->vl[i + (w + 1) * j] != BELOW_DOT(state, i, j)) {
2496                         CLEAR_VL(i, j);
2497                         draw_line(dr,
2498                                  BORDER + i * TILE_SIZE - CROSS_SIZE,
2499                                  BORDER + j * TILE_SIZE + TILE_SIZE/2 - CROSS_SIZE,
2500                                  BORDER + i * TILE_SIZE + CROSS_SIZE - 1,
2501                                  BORDER + j * TILE_SIZE + TILE_SIZE/2 + CROSS_SIZE - 1,
2502                                   COL_FOREGROUND);
2503                         draw_line(dr,
2504                                  BORDER + i * TILE_SIZE + CROSS_SIZE - 1,
2505                                  BORDER + j * TILE_SIZE + TILE_SIZE/2 - CROSS_SIZE,
2506                                  BORDER + i * TILE_SIZE - CROSS_SIZE,
2507                                  BORDER + j * TILE_SIZE + TILE_SIZE/2 + CROSS_SIZE - 1,
2508                                   COL_FOREGROUND);
2509                     }
2510                     break;
2511             }
2512             ds->vl[i + (w + 1) * j] = BELOW_DOT(state, i, j);
2513         }
2514     }
2515
2516     /* Horizontal lines */
2517     for (j = 0; j < h + 1; ++j) {
2518         for (i = 0; i < w; ++i) {
2519             switch (RIGHTOF_DOT(state, i, j)) {
2520                 case LINE_UNKNOWN:
2521                     if (ds->hl[i + w * j] != RIGHTOF_DOT(state, i, j)) {
2522                         CLEAR_HL(i, j);
2523                 }
2524                         break;
2525                 case LINE_YES:
2526                     if (ds->hl[i + w * j] != RIGHTOF_DOT(state, i, j) ||
2527                         flash_changed) {
2528                         CLEAR_HL(i, j);
2529                         draw_rect(dr,
2530                                   BORDER + i * TILE_SIZE + LINEWIDTH/2,
2531                                   BORDER + j * TILE_SIZE - LINEWIDTH/2,
2532                                   TILE_SIZE - LINEWIDTH, LINEWIDTH, 
2533                                   line_colour);
2534                         break;
2535                     }
2536                 case LINE_NO:
2537                     if (ds->hl[i + w * j] != RIGHTOF_DOT(state, i, j)) {
2538                         CLEAR_HL(i, j);
2539                         draw_line(dr,
2540                                  BORDER + i * TILE_SIZE + TILE_SIZE/2 - CROSS_SIZE,
2541                                  BORDER + j * TILE_SIZE + CROSS_SIZE - 1,
2542                                  BORDER + i * TILE_SIZE + TILE_SIZE/2 + CROSS_SIZE - 1,
2543                                  BORDER + j * TILE_SIZE - CROSS_SIZE,
2544                                   COL_FOREGROUND);
2545                         draw_line(dr,
2546                                  BORDER + i * TILE_SIZE + TILE_SIZE/2 - CROSS_SIZE,
2547                                  BORDER + j * TILE_SIZE - CROSS_SIZE,
2548                                  BORDER + i * TILE_SIZE + TILE_SIZE/2 + CROSS_SIZE - 1,
2549                                  BORDER + j * TILE_SIZE + CROSS_SIZE - 1,
2550                                   COL_FOREGROUND);
2551                         break;
2552                     }
2553             }
2554             ds->hl[i + w * j] = RIGHTOF_DOT(state, i, j);
2555         }
2556     }
2557 }
2558
2559 static float game_anim_length(game_state *oldstate, game_state *newstate,
2560                               int dir, game_ui *ui)
2561 {
2562     return 0.0F;
2563 }
2564
2565 static float game_flash_length(game_state *oldstate, game_state *newstate,
2566                                int dir, game_ui *ui)
2567 {
2568     if (!oldstate->solved  &&  newstate->solved &&
2569         !oldstate->cheated && !newstate->cheated) {
2570         return FLASH_TIME;
2571     }
2572
2573     return 0.0F;
2574 }
2575
2576 static int game_wants_statusbar(void)
2577 {
2578     return FALSE;
2579 }
2580
2581 static int game_timing_state(game_state *state, game_ui *ui)
2582 {
2583     return TRUE;
2584 }
2585
2586 static void game_print_size(game_params *params, float *x, float *y)
2587 {
2588     int pw, ph;
2589
2590     /*
2591      * I'll use 7mm squares by default.
2592      */
2593     game_compute_size(params, 700, &pw, &ph);
2594     *x = pw / 100.0F;
2595     *y = ph / 100.0F;
2596 }
2597
2598 static void game_print(drawing *dr, game_state *state, int tilesize)
2599 {
2600     int w = state->w, h = state->h;
2601     int ink = print_mono_colour(dr, 0);
2602     int x, y;
2603     game_drawstate ads, *ds = &ads;
2604     ds->tilesize = tilesize;
2605
2606     /*
2607      * Dots. I'll deliberately make the dots a bit wider than the
2608      * lines, so you can still see them. (And also because it's
2609      * annoyingly tricky to make them _exactly_ the same size...)
2610      */
2611     for (y = 0; y <= h; y++)
2612         for (x = 0; x <= w; x++)
2613             draw_circle(dr, BORDER + x * TILE_SIZE, BORDER + y * TILE_SIZE,
2614                         LINEWIDTH, ink, ink);
2615
2616     /*
2617      * Clues.
2618      */
2619     for (y = 0; y < h; y++)
2620         for (x = 0; x < w; x++)
2621             if (CLUE_AT(state, x, y) != ' ') {
2622                 char c[2];
2623
2624                 c[0] = CLUE_AT(state, x, y);
2625                 c[1] = '\0';
2626                 draw_text(dr, 
2627                           BORDER + x * TILE_SIZE + TILE_SIZE/2,
2628                           BORDER + y * TILE_SIZE + TILE_SIZE/2,
2629                           FONT_VARIABLE, TILE_SIZE/2, 
2630                           ALIGN_VCENTRE | ALIGN_HCENTRE, ink, c);
2631             }
2632
2633     /*
2634      * Lines. (At the moment, I'm not bothering with crosses.)
2635      */
2636     for (y = 0; y <= h; y++)
2637         for (x = 0; x < w; x++)
2638             if (RIGHTOF_DOT(state, x, y) == LINE_YES)
2639                 draw_rect(dr, BORDER + x * TILE_SIZE,
2640                           BORDER + y * TILE_SIZE - LINEWIDTH/2,
2641                           TILE_SIZE, (LINEWIDTH/2) * 2 + 1, ink);
2642     for (y = 0; y < h; y++)
2643         for (x = 0; x <= w; x++)
2644             if (BELOW_DOT(state, x, y) == LINE_YES)
2645                 draw_rect(dr, BORDER + x * TILE_SIZE - LINEWIDTH/2,
2646                           BORDER + y * TILE_SIZE,
2647                           (LINEWIDTH/2) * 2 + 1, TILE_SIZE, ink);
2648 }
2649
2650 #ifdef COMBINED
2651 #define thegame loopy
2652 #endif
2653
2654 const struct game thegame = {
2655     "Loopy", "games.loopy",
2656     default_params,
2657     game_fetch_preset,
2658     decode_params,
2659     encode_params,
2660     free_params,
2661     dup_params,
2662     TRUE, game_configure, custom_params,
2663     validate_params,
2664     new_game_desc,
2665     validate_desc,
2666     new_game,
2667     dup_game,
2668     free_game,
2669     1, solve_game,
2670     TRUE, game_text_format,
2671     new_ui,
2672     free_ui,
2673     encode_ui,
2674     decode_ui,
2675     game_changed_state,
2676     interpret_move,
2677     execute_move,
2678     PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
2679     game_colours,
2680     game_new_drawstate,
2681     game_free_drawstate,
2682     game_redraw,
2683     game_anim_length,
2684     game_flash_length,
2685     TRUE, FALSE, game_print_size, game_print,
2686     game_wants_statusbar,
2687     FALSE, game_timing_state,
2688     0,                                       /* mouse_priorities */
2689 };