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