chiark / gitweb /
Fix premature completion flash in Tracks.
[sgt-puzzles.git] / pearl.c
1 /*
2  * pearl.c: Nikoli's `Masyu' puzzle. 
3  */
4
5 /*
6  * TODO:
7  *
8  *  - The current keyboard cursor mechanism works well on ordinary PC
9  *    keyboards, but for platforms with only arrow keys and a select
10  *    button or two, we may at some point need a simpler one which can
11  *    handle 'x' markings without needing shift keys. For instance, a
12  *    cursor with twice the grid resolution, so that it can range
13  *    across face centres, edge centres and vertices; 'clicks' on face
14  *    centres begin a drag as currently, clicks on edges toggle
15  *    markings, and clicks on vertices are ignored (but it would be
16  *    too confusing not to let the cursor rest on them). But I'm
17  *    pretty sure that would be less pleasant to play on a full
18  *    keyboard, so probably a #ifdef would be the thing.
19  *
20  *  - Generation is still pretty slow, due to difficulty coming up in
21  *    the first place with a loop that makes a soluble puzzle even
22  *    with all possible clues filled in.
23  *     + A possible alternative strategy to further tuning of the
24  *       existing loop generator would be to throw the entire
25  *       mechanism out and instead write a different generator from
26  *       scratch which evolves the solution along with the puzzle:
27  *       place a few clues, nail down a bit of the loop, place another
28  *       clue, nail down some more, etc. However, I don't have a
29  *       detailed plan for any such mechanism, so it may be a pipe
30  *       dream.
31  */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <assert.h>
37 #include <ctype.h>
38 #include <math.h>
39
40 #include "puzzles.h"
41 #include "grid.h"
42 #include "loopgen.h"
43
44 #define SWAP(i,j) do { int swaptmp = (i); (i) = (j); (j) = swaptmp; } while (0)
45
46 #define NOCLUE 0
47 #define CORNER 1
48 #define STRAIGHT 2
49
50 #define R 1
51 #define U 2
52 #define L 4
53 #define D 8
54
55 #define DX(d) ( ((d)==R) - ((d)==L) )
56 #define DY(d) ( ((d)==D) - ((d)==U) )
57
58 #define F(d) (((d << 2) | (d >> 2)) & 0xF)
59 #define C(d) (((d << 3) | (d >> 1)) & 0xF)
60 #define A(d) (((d << 1) | (d >> 3)) & 0xF)
61
62 #define LR (L | R)
63 #define RL (R | L)
64 #define UD (U | D)
65 #define DU (D | U)
66 #define LU (L | U)
67 #define UL (U | L)
68 #define LD (L | D)
69 #define DL (D | L)
70 #define RU (R | U)
71 #define UR (U | R)
72 #define RD (R | D)
73 #define DR (D | R)
74 #define BLANK 0
75 #define UNKNOWN 15
76
77 #define bLR (1 << LR)
78 #define bRL (1 << RL)
79 #define bUD (1 << UD)
80 #define bDU (1 << DU)
81 #define bLU (1 << LU)
82 #define bUL (1 << UL)
83 #define bLD (1 << LD)
84 #define bDL (1 << DL)
85 #define bRU (1 << RU)
86 #define bUR (1 << UR)
87 #define bRD (1 << RD)
88 #define bDR (1 << DR)
89 #define bBLANK (1 << BLANK)
90
91 enum {
92     COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT,
93     COL_CURSOR_BACKGROUND = COL_LOWLIGHT,
94     COL_BLACK, COL_WHITE,
95     COL_ERROR, COL_GRID, COL_FLASH,
96     COL_DRAGON, COL_DRAGOFF,
97     NCOLOURS
98 };
99
100 /* Macro ickery copied from slant.c */
101 #define DIFFLIST(A) \
102     A(EASY,Easy,e) \
103     A(TRICKY,Tricky,t)
104 #define ENUM(upper,title,lower) DIFF_ ## upper,
105 #define TITLE(upper,title,lower) #title,
106 #define ENCODE(upper,title,lower) #lower
107 #define CONFIG(upper,title,lower) ":" #title
108 enum { DIFFLIST(ENUM) DIFFCOUNT };
109 static char const *const pearl_diffnames[] = { DIFFLIST(TITLE) "(count)" };
110 static char const pearl_diffchars[] = DIFFLIST(ENCODE);
111 #define DIFFCONFIG DIFFLIST(CONFIG)
112
113 struct game_params {
114     int w, h;
115     int difficulty;
116     int nosolve;        /* XXX remove me! */
117 };
118
119 struct shared_state {
120     int w, h, sz;
121     char *clues;         /* size w*h */
122     int refcnt;
123 };
124
125 #define INGRID(state, gx, gy) ((gx) >= 0 && (gx) < (state)->shared->w && \
126                                (gy) >= 0 && (gy) < (state)->shared->h)
127 struct game_state {
128     struct shared_state *shared;
129     char *lines;        /* size w*h: lines placed */
130     char *errors;       /* size w*h: errors detected */
131     char *marks;        /* size w*h: 'no line here' marks placed. */
132     int completed, used_solve;
133     int loop_length;    /* filled in by check_completion when complete. */
134 };
135
136 #define DEFAULT_PRESET 3
137
138 static const struct game_params pearl_presets[] = {
139     {6, 6,      DIFF_EASY},
140     {6, 6,      DIFF_TRICKY},
141     {8, 8,      DIFF_EASY},
142     {8, 8,      DIFF_TRICKY},
143     {10, 10,    DIFF_EASY},
144     {10, 10,    DIFF_TRICKY},
145     {12, 8,     DIFF_EASY},
146     {12, 8,     DIFF_TRICKY},
147 };
148
149 static game_params *default_params(void)
150 {
151     game_params *ret = snew(game_params);
152
153     *ret = pearl_presets[DEFAULT_PRESET];
154     ret->nosolve = FALSE;
155
156     return ret;
157 }
158
159 static int game_fetch_preset(int i, char **name, game_params **params)
160 {
161     game_params *ret;
162     char buf[64];
163
164     if (i < 0 || i >= lenof(pearl_presets)) return FALSE;
165
166     ret = default_params();
167     *ret = pearl_presets[i]; /* struct copy */
168     *params = ret;
169
170     sprintf(buf, "%dx%d %s",
171             pearl_presets[i].w, pearl_presets[i].h,
172             pearl_diffnames[pearl_presets[i].difficulty]);
173     *name = dupstr(buf);
174
175     return TRUE;
176 }
177
178 static void free_params(game_params *params)
179 {
180     sfree(params);
181 }
182
183 static game_params *dup_params(const game_params *params)
184 {
185     game_params *ret = snew(game_params);
186     *ret = *params;                    /* structure copy */
187     return ret;
188 }
189
190 static void decode_params(game_params *ret, char const *string)
191 {
192     ret->w = ret->h = atoi(string);
193     while (*string && isdigit((unsigned char) *string)) ++string;
194     if (*string == 'x') {
195         string++;
196         ret->h = atoi(string);
197         while (*string && isdigit((unsigned char)*string)) string++;
198     }
199
200     ret->difficulty = DIFF_EASY;
201     if (*string == 'd') {
202         int i;
203         string++;
204         for (i = 0; i < DIFFCOUNT; i++)
205             if (*string == pearl_diffchars[i])
206                 ret->difficulty = i;
207         if (*string) string++;
208     }
209
210     ret->nosolve = FALSE;
211     if (*string == 'n') {
212         ret->nosolve = TRUE;
213         string++;
214     }
215 }
216
217 static char *encode_params(const game_params *params, int full)
218 {
219     char buf[256];
220     sprintf(buf, "%dx%d", params->w, params->h);
221     if (full)
222         sprintf(buf + strlen(buf), "d%c%s",
223                 pearl_diffchars[params->difficulty],
224                 params->nosolve ? "n" : "");
225     return dupstr(buf);
226 }
227
228 static config_item *game_configure(const game_params *params)
229 {
230     config_item *ret;
231     char buf[64];
232
233     ret = snewn(5, config_item);
234
235     ret[0].name = "Width";
236     ret[0].type = C_STRING;
237     sprintf(buf, "%d", params->w);
238     ret[0].sval = dupstr(buf);
239     ret[0].ival = 0;
240
241     ret[1].name = "Height";
242     ret[1].type = C_STRING;
243     sprintf(buf, "%d", params->h);
244     ret[1].sval = dupstr(buf);
245     ret[1].ival = 0;
246
247     ret[2].name = "Difficulty";
248     ret[2].type = C_CHOICES;
249     ret[2].sval = DIFFCONFIG;
250     ret[2].ival = params->difficulty;
251
252     ret[3].name = "Allow unsoluble";
253     ret[3].type = C_BOOLEAN;
254     ret[3].sval = NULL;
255     ret[3].ival = params->nosolve;
256
257     ret[4].name = NULL;
258     ret[4].type = C_END;
259     ret[4].sval = NULL;
260     ret[4].ival = 0;
261
262     return ret;
263 }
264
265 static game_params *custom_params(const config_item *cfg)
266 {
267     game_params *ret = snew(game_params);
268
269     ret->w = atoi(cfg[0].sval);
270     ret->h = atoi(cfg[1].sval);
271     ret->difficulty = cfg[2].ival;
272     ret->nosolve = cfg[3].ival;
273
274     return ret;
275 }
276
277 static char *validate_params(const game_params *params, int full)
278 {
279     if (params->w < 5) return "Width must be at least five";
280     if (params->h < 5) return "Height must be at least five";
281     if (params->difficulty < 0 || params->difficulty >= DIFFCOUNT)
282         return "Unknown difficulty level";
283
284     return NULL;
285 }
286
287 /* ----------------------------------------------------------------------
288  * Solver.
289  */
290
291 int pearl_solve(int w, int h, char *clues, char *result,
292                 int difficulty, int partial)
293 {
294     int W = 2*w+1, H = 2*h+1;
295     short *workspace;
296     int *dsf, *dsfsize;
297     int x, y, b, d;
298     int ret = -1;
299
300     /*
301      * workspace[(2*y+1)*W+(2*x+1)] indicates the possible nature
302      * of the square (x,y), as a logical OR of bitfields.
303      * 
304      * workspace[(2*y)*W+(2*x+1)], for x odd and y even, indicates
305      * whether the horizontal edge between (x,y) and (x+1,y) is
306      * connected (1), disconnected (2) or unknown (3).
307      * 
308      * workspace[(2*y+1)*W+(2*x)], indicates the same about the
309      * vertical edge between (x,y) and (x,y+1).
310      * 
311      * Initially, every square is considered capable of being in
312      * any of the seven possible states (two straights, four
313      * corners and empty), except those corresponding to clue
314      * squares which are more restricted.
315      * 
316      * Initially, all edges are unknown, except the ones around the
317      * grid border which are known to be disconnected.
318      */
319     workspace = snewn(W*H, short);
320     for (x = 0; x < W*H; x++)
321         workspace[x] = 0;
322     /* Square states */
323     for (y = 0; y < h; y++)
324         for (x = 0; x < w; x++)
325             switch (clues[y*w+x]) {
326               case CORNER:
327                 workspace[(2*y+1)*W+(2*x+1)] = bLU|bLD|bRU|bRD;
328                 break;
329               case STRAIGHT:
330                 workspace[(2*y+1)*W+(2*x+1)] = bLR|bUD;
331                 break;
332               default:
333                 workspace[(2*y+1)*W+(2*x+1)] = bLR|bUD|bLU|bLD|bRU|bRD|bBLANK;
334                 break;
335             }
336     /* Horizontal edges */
337     for (y = 0; y <= h; y++)
338         for (x = 0; x < w; x++)
339             workspace[(2*y)*W+(2*x+1)] = (y==0 || y==h ? 2 : 3);
340     /* Vertical edges */
341     for (y = 0; y < h; y++)
342         for (x = 0; x <= w; x++)
343             workspace[(2*y+1)*W+(2*x)] = (x==0 || x==w ? 2 : 3);
344
345     /*
346      * We maintain a dsf of connected squares, together with a
347      * count of the size of each equivalence class.
348      */
349     dsf = snewn(w*h, int);
350     dsfsize = snewn(w*h, int);
351
352     /*
353      * Now repeatedly try to find something we can do.
354      */
355     while (1) {
356         int done_something = FALSE;
357
358 #ifdef SOLVER_DIAGNOSTICS
359         for (y = 0; y < H; y++) {
360             for (x = 0; x < W; x++)
361                 printf("%*x", (x&1) ? 5 : 2, workspace[y*W+x]);
362             printf("\n");
363         }
364 #endif
365
366         /*
367          * Go through the square state words, and discard any
368          * square state which is inconsistent with known facts
369          * about the edges around the square.
370          */
371         for (y = 0; y < h; y++)
372             for (x = 0; x < w; x++) {
373                 for (b = 0; b < 0xD; b++)
374                     if (workspace[(2*y+1)*W+(2*x+1)] & (1<<b)) {
375                         /*
376                          * If any edge of this square is known to
377                          * be connected when state b would require
378                          * it disconnected, or vice versa, discard
379                          * the state.
380                          */
381                         for (d = 1; d <= 8; d += d) {
382                             int ex = 2*x+1 + DX(d), ey = 2*y+1 + DY(d);
383                             if (workspace[ey*W+ex] ==
384                                 ((b & d) ? 2 : 1)) {
385                                 workspace[(2*y+1)*W+(2*x+1)] &= ~(1<<b);
386 #ifdef SOLVER_DIAGNOSTICS
387                                 printf("edge (%d,%d)-(%d,%d) rules out state"
388                                        " %d for square (%d,%d)\n",
389                                        ex/2, ey/2, (ex+1)/2, (ey+1)/2,
390                                        b, x, y);
391 #endif
392                                 done_something = TRUE;
393                                 break;
394                             }
395                         }
396                     }
397
398                 /*
399                  * Consistency check: each square must have at
400                  * least one state left!
401                  */
402                 if (!workspace[(2*y+1)*W+(2*x+1)]) {
403 #ifdef SOLVER_DIAGNOSTICS
404                     printf("edge check at (%d,%d): inconsistency\n", x, y);
405 #endif
406                     ret = 0;
407                     goto cleanup;
408                 }
409             }
410
411         /*
412          * Now go through the states array again, and nail down any
413          * unknown edge if one of its neighbouring squares makes it
414          * known.
415          */
416         for (y = 0; y < h; y++)
417             for (x = 0; x < w; x++) {
418                 int edgeor = 0, edgeand = 15;
419
420                 for (b = 0; b < 0xD; b++)
421                     if (workspace[(2*y+1)*W+(2*x+1)] & (1<<b)) {
422                         edgeor |= b;
423                         edgeand &= b;
424                     }
425
426                 /*
427                  * Now any bit clear in edgeor marks a disconnected
428                  * edge, and any bit set in edgeand marks a
429                  * connected edge.
430                  */
431
432                 /* First check consistency: neither bit is both! */
433                 if (edgeand & ~edgeor) {
434 #ifdef SOLVER_DIAGNOSTICS
435                     printf("square check at (%d,%d): inconsistency\n", x, y);
436 #endif
437                     ret = 0;
438                     goto cleanup;
439                 }
440
441                 for (d = 1; d <= 8; d += d) {
442                     int ex = 2*x+1 + DX(d), ey = 2*y+1 + DY(d);
443
444                     if (!(edgeor & d) && workspace[ey*W+ex] == 3) {
445                         workspace[ey*W+ex] = 2;
446                         done_something = TRUE;
447 #ifdef SOLVER_DIAGNOSTICS
448                         printf("possible states of square (%d,%d) force edge"
449                                " (%d,%d)-(%d,%d) to be disconnected\n",
450                                x, y, ex/2, ey/2, (ex+1)/2, (ey+1)/2);
451 #endif
452                     } else if ((edgeand & d) && workspace[ey*W+ex] == 3) {
453                         workspace[ey*W+ex] = 1;
454                         done_something = TRUE;
455 #ifdef SOLVER_DIAGNOSTICS
456                         printf("possible states of square (%d,%d) force edge"
457                                " (%d,%d)-(%d,%d) to be connected\n",
458                                x, y, ex/2, ey/2, (ex+1)/2, (ey+1)/2);
459 #endif
460                     }
461                 }
462             }
463
464         if (done_something)
465             continue;
466
467         /*
468          * Now for longer-range clue-based deductions (using the
469          * rules that a corner clue must connect to two straight
470          * squares, and a straight clue must connect to at least
471          * one corner square).
472          */
473         for (y = 0; y < h; y++)
474             for (x = 0; x < w; x++)
475                 switch (clues[y*w+x]) {
476                   case CORNER:
477                     for (d = 1; d <= 8; d += d) {
478                         int ex = 2*x+1 + DX(d), ey = 2*y+1 + DY(d);
479                         int fx = ex + DX(d), fy = ey + DY(d);
480                         int type = d | F(d);
481
482                         if (workspace[ey*W+ex] == 1) {
483                             /*
484                              * If a corner clue is connected on any
485                              * edge, then we can immediately nail
486                              * down the square beyond that edge as
487                              * being a straight in the appropriate
488                              * direction.
489                              */
490                             if (workspace[fy*W+fx] != (1<<type)) {
491                                 workspace[fy*W+fx] = (1<<type);
492                                 done_something = TRUE;
493 #ifdef SOLVER_DIAGNOSTICS
494                                 printf("corner clue at (%d,%d) forces square "
495                                        "(%d,%d) into state %d\n", x, y,
496                                        fx/2, fy/2, type);
497 #endif
498                                 
499                             }
500                         } else if (workspace[ey*W+ex] == 3) {
501                             /*
502                              * Conversely, if a corner clue is
503                              * separated by an unknown edge from a
504                              * square which _cannot_ be a straight
505                              * in the appropriate direction, we can
506                              * mark that edge as disconnected.
507                              */
508                             if (!(workspace[fy*W+fx] & (1<<type))) {
509                                 workspace[ey*W+ex] = 2;
510                                 done_something = TRUE;
511 #ifdef SOLVER_DIAGNOSTICS
512                                 printf("corner clue at (%d,%d), plus square "
513                                        "(%d,%d) not being state %d, "
514                                        "disconnects edge (%d,%d)-(%d,%d)\n",
515                                        x, y, fx/2, fy/2, type,
516                                        ex/2, ey/2, (ex+1)/2, (ey+1)/2);
517 #endif
518
519                             }
520                         }
521                     }
522
523                     break;
524                   case STRAIGHT:
525                     /*
526                      * If a straight clue is between two squares
527                      * neither of which is capable of being a
528                      * corner connected to it, then the straight
529                      * clue cannot point in that direction.
530                      */
531                     for (d = 1; d <= 2; d += d) {
532                         int fx = 2*x+1 + 2*DX(d), fy = 2*y+1 + 2*DY(d);
533                         int gx = 2*x+1 - 2*DX(d), gy = 2*y+1 - 2*DY(d);
534                         int type = d | F(d);
535
536                         if (!(workspace[(2*y+1)*W+(2*x+1)] & (1<<type)))
537                             continue;
538
539                         if (!(workspace[fy*W+fx] & ((1<<(F(d)|A(d))) |
540                                                     (1<<(F(d)|C(d))))) &&
541                             !(workspace[gy*W+gx] & ((1<<(  d |A(d))) |
542                                                     (1<<(  d |C(d)))))) {
543                             workspace[(2*y+1)*W+(2*x+1)] &= ~(1<<type);
544                             done_something = TRUE;
545 #ifdef SOLVER_DIAGNOSTICS
546                             printf("straight clue at (%d,%d) cannot corner at "
547                                    "(%d,%d) or (%d,%d) so is not state %d\n",
548                                    x, y, fx/2, fy/2, gx/2, gy/2, type);
549 #endif
550                         }
551                                                     
552                     }
553
554                     /*
555                      * If a straight clue with known direction is
556                      * connected on one side to a known straight,
557                      * then on the other side it must be a corner.
558                      */
559                     for (d = 1; d <= 8; d += d) {
560                         int fx = 2*x+1 + 2*DX(d), fy = 2*y+1 + 2*DY(d);
561                         int gx = 2*x+1 - 2*DX(d), gy = 2*y+1 - 2*DY(d);
562                         int type = d | F(d);
563
564                         if (workspace[(2*y+1)*W+(2*x+1)] != (1<<type))
565                             continue;
566
567                         if (!(workspace[fy*W+fx] &~ (bLR|bUD)) &&
568                             (workspace[gy*W+gx] &~ (bLU|bLD|bRU|bRD))) {
569                             workspace[gy*W+gx] &= (bLU|bLD|bRU|bRD);
570                             done_something = TRUE;
571 #ifdef SOLVER_DIAGNOSTICS
572                             printf("straight clue at (%d,%d) connecting to "
573                                    "straight at (%d,%d) makes (%d,%d) a "
574                                    "corner\n", x, y, fx/2, fy/2, gx/2, gy/2);
575 #endif
576                         }
577                                                     
578                     }
579                     break;
580                 }
581
582         if (done_something)
583             continue;
584
585         /*
586          * Now detect shortcut loops.
587          */
588
589         {
590             int nonblanks, loopclass;
591
592             dsf_init(dsf, w*h);
593             for (x = 0; x < w*h; x++)
594                 dsfsize[x] = 1;
595
596             /*
597              * First go through the edge entries and update the dsf
598              * of which squares are connected to which others. We
599              * also track the number of squares in each equivalence
600              * class, and count the overall number of
601              * known-non-blank squares.
602              *
603              * In the process of doing this, we must notice if a
604              * loop has already been formed. If it has, we blank
605              * out any square which isn't part of that loop
606              * (failing a consistency check if any such square does
607              * not have BLANK as one of its remaining options) and
608              * exit the deduction loop with success.
609              */
610             nonblanks = 0;
611             loopclass = -1;
612             for (y = 1; y < H-1; y++)
613                 for (x = 1; x < W-1; x++)
614                     if ((y ^ x) & 1) {
615                         /*
616                          * (x,y) are the workspace coordinates of
617                          * an edge field. Compute the normal-space
618                          * coordinates of the squares it connects.
619                          */
620                         int ax = (x-1)/2, ay = (y-1)/2, ac = ay*w+ax;
621                         int bx = x/2, by = y/2, bc = by*w+bx;
622
623                         /*
624                          * If the edge is connected, do the dsf
625                          * thing.
626                          */
627                         if (workspace[y*W+x] == 1) {
628                             int ae, be;
629
630                             ae = dsf_canonify(dsf, ac);
631                             be = dsf_canonify(dsf, bc);
632
633                             if (ae == be) {
634                                 /*
635                                  * We have a loop!
636                                  */
637                                 if (loopclass != -1) {
638                                     /*
639                                      * In fact, we have two
640                                      * separate loops, which is
641                                      * doom.
642                                      */
643 #ifdef SOLVER_DIAGNOSTICS
644                                     printf("two loops found in grid!\n");
645 #endif
646                                     ret = 0;
647                                     goto cleanup;
648                                 }
649                                 loopclass = ae;
650                             } else {
651                                 /*
652                                  * Merge the two equivalence
653                                  * classes.
654                                  */
655                                 int size = dsfsize[ae] + dsfsize[be];
656                                 dsf_merge(dsf, ac, bc);
657                                 ae = dsf_canonify(dsf, ac);
658                                 dsfsize[ae] = size;
659                             }
660                         }
661                     } else if ((y & x) & 1) {
662                         /*
663                          * (x,y) are the workspace coordinates of a
664                          * square field. If the square is
665                          * definitely not blank, count it.
666                          */
667                         if (!(workspace[y*W+x] & bBLANK))
668                             nonblanks++;
669                     }
670
671             /*
672              * If we discovered an existing loop above, we must now
673              * blank every square not part of it, and exit the main
674              * deduction loop.
675              */
676             if (loopclass != -1) {
677 #ifdef SOLVER_DIAGNOSTICS
678                 printf("loop found in grid!\n");
679 #endif
680                 for (y = 0; y < h; y++)
681                     for (x = 0; x < w; x++)
682                         if (dsf_canonify(dsf, y*w+x) != loopclass) {
683                             if (workspace[(y*2+1)*W+(x*2+1)] & bBLANK) {
684                                 workspace[(y*2+1)*W+(x*2+1)] = bBLANK;
685                             } else {
686                                 /*
687                                  * This square is not part of the
688                                  * loop, but is known non-blank. We
689                                  * have goofed.
690                                  */
691 #ifdef SOLVER_DIAGNOSTICS
692                                 printf("non-blank square (%d,%d) found outside"
693                                        " loop!\n", x, y);
694 #endif
695                                 ret = 0;
696                                 goto cleanup;
697                             }
698                         }
699                 /*
700                  * And we're done.
701                  */
702                 ret = 1;
703                 break;
704             }
705
706             /* Further deductions are considered 'tricky'. */
707             if (difficulty == DIFF_EASY) goto done_deductions;
708
709             /*
710              * Now go through the workspace again and mark any edge
711              * which would cause a shortcut loop (i.e. would
712              * connect together two squares in the same equivalence
713              * class, and that equivalence class does not contain
714              * _all_ the known-non-blank squares currently in the
715              * grid) as disconnected. Also, mark any _square state_
716              * which would cause a shortcut loop as disconnected.
717              */
718             for (y = 1; y < H-1; y++)
719                 for (x = 1; x < W-1; x++)
720                     if ((y ^ x) & 1) {
721                         /*
722                          * (x,y) are the workspace coordinates of
723                          * an edge field. Compute the normal-space
724                          * coordinates of the squares it connects.
725                          */
726                         int ax = (x-1)/2, ay = (y-1)/2, ac = ay*w+ax;
727                         int bx = x/2, by = y/2, bc = by*w+bx;
728
729                         /*
730                          * If the edge is currently unknown, and
731                          * sits between two squares in the same
732                          * equivalence class, and the size of that
733                          * class is less than nonblanks, then
734                          * connecting this edge would be a shortcut
735                          * loop and so we must not do so.
736                          */
737                         if (workspace[y*W+x] == 3) {
738                             int ae, be;
739
740                             ae = dsf_canonify(dsf, ac);
741                             be = dsf_canonify(dsf, bc);
742
743                             if (ae == be) {
744                                 /*
745                                  * We have a loop. Is it a shortcut?
746                                  */
747                                 if (dsfsize[ae] < nonblanks) {
748                                     /*
749                                      * Yes! Mark this edge disconnected.
750                                      */
751                                     workspace[y*W+x] = 2;
752                                     done_something = TRUE;
753 #ifdef SOLVER_DIAGNOSTICS
754                                     printf("edge (%d,%d)-(%d,%d) would create"
755                                            " a shortcut loop, hence must be"
756                                            " disconnected\n", x/2, y/2,
757                                            (x+1)/2, (y+1)/2);
758 #endif
759                                 }
760                             }
761                         }
762                     } else if ((y & x) & 1) {
763                         /*
764                          * (x,y) are the workspace coordinates of a
765                          * square field. Go through its possible
766                          * (non-blank) states and see if any gives
767                          * rise to a shortcut loop.
768                          * 
769                          * This is slightly fiddly, because we have
770                          * to check whether this square is already
771                          * part of the same equivalence class as
772                          * the things it's joining.
773                          */
774                         int ae = dsf_canonify(dsf, (y/2)*w+(x/2));
775
776                         for (b = 2; b < 0xD; b++)
777                             if (workspace[y*W+x] & (1<<b)) {
778                                 /*
779                                  * Find the equivalence classes of
780                                  * the two squares this one would
781                                  * connect if it were in this
782                                  * state.
783                                  */
784                                 int e = -1;
785
786                                 for (d = 1; d <= 8; d += d) if (b & d) {
787                                     int xx = x/2 + DX(d), yy = y/2 + DY(d);
788                                     int ee = dsf_canonify(dsf, yy*w+xx);
789
790                                     if (e == -1)
791                                         ee = e;
792                                     else if (e != ee)
793                                         e = -2;
794                                 }
795
796                                 if (e >= 0) {
797                                     /*
798                                      * This square state would form
799                                      * a loop on equivalence class
800                                      * e. Measure the size of that
801                                      * loop, and see if it's a
802                                      * shortcut.
803                                      */
804                                     int loopsize = dsfsize[e];
805                                     if (e != ae)
806                                         loopsize++;/* add the square itself */
807                                     if (loopsize < nonblanks) {
808                                         /*
809                                          * It is! Mark this square
810                                          * state invalid.
811                                          */
812                                         workspace[y*W+x] &= ~(1<<b);
813                                         done_something = TRUE;
814 #ifdef SOLVER_DIAGNOSTICS
815                                         printf("square (%d,%d) would create a "
816                                                "shortcut loop in state %d, "
817                                                "hence cannot be\n",
818                                                x/2, y/2, b);
819 #endif
820                                     }
821                                 }
822                             }
823                     }
824         }
825
826 done_deductions:
827
828         if (done_something)
829             continue;
830
831         /*
832          * If we reach here, there is nothing left we can do.
833          * Return 2 for ambiguous puzzle.
834          */
835         ret = 2;
836         break;
837     }
838
839 cleanup:
840
841     /*
842      * If ret = 1 then we've successfully achieved a solution. This
843      * means that we expect every square to be nailed down to
844      * exactly one possibility. If this is the case, or if the caller
845      * asked for a partial solution anyway, transcribe those
846      * possibilities into the result array.
847      */
848     if (ret == 1 || partial) {
849         for (y = 0; y < h; y++) {
850             for (x = 0; x < w; x++) {
851                 for (b = 0; b < 0xD; b++)
852                     if (workspace[(2*y+1)*W+(2*x+1)] == (1<<b)) {
853                         result[y*w+x] = b;
854                         break;
855                     }
856                if (ret == 1) assert(b < 0xD); /* we should have had a break by now */
857             }
858         }
859     }
860
861     sfree(dsfsize);
862     sfree(dsf);
863     sfree(workspace);
864     assert(ret >= 0);
865     return ret;
866 }
867
868 /* ----------------------------------------------------------------------
869  * Loop generator.
870  */
871
872 /*
873  * We use the loop generator code from loopy, hard-coding to a square
874  * grid of the appropriate size. Knowing the grid layout and the tile
875  * size we can shrink that to our small grid and then make our line
876  * layout from the face colour info.
877  *
878  * We provide a bias function to the loop generator which tries to
879  * bias in favour of loops with more scope for Pearl black clues. This
880  * seems to improve the success rate of the puzzle generator, in that
881  * such loops have a better chance of being soluble with all valid
882  * clues put in.
883  */
884
885 struct pearl_loopgen_bias_ctx {
886     /*
887      * Our bias function counts the number of 'black clue' corners
888      * (i.e. corners adjacent to two straights) in both the
889      * BLACK/nonBLACK and WHITE/nonWHITE boundaries. In order to do
890      * this, we must:
891      *
892      *  - track the edges that are part of each of those loops
893      *  - track the types of vertex in each loop (corner, straight,
894      *    none)
895      *  - track the current black-clue status of each vertex in each
896      *    loop.
897      *
898      * Each of these chunks of data is updated incrementally from the
899      * previous one, to avoid slowdown due to the bias function
900      * rescanning the whole grid every time it's called.
901      *
902      * So we need a lot of separate arrays, plus a tdq for each one,
903      * and we must repeat it all twice for the BLACK and WHITE
904      * boundaries.
905      */
906     struct pearl_loopgen_bias_ctx_boundary {
907         int colour;                    /* FACE_WHITE or FACE_BLACK */
908
909         char *edges;                   /* is each edge part of the loop? */
910         tdq *edges_todo;
911
912         char *vertextypes;             /* bits 0-3 == outgoing edge bitmap;
913                                         * bit 4 set iff corner clue.
914                                         * Hence, 0 means non-vertex;
915                                         * nonzero but bit 4 zero = straight. */
916         int *neighbour[2];          /* indices of neighbour vertices in loop */
917         tdq *vertextypes_todo;
918
919         char *blackclues;              /* is each vertex a black clue site? */
920         tdq *blackclues_todo;
921     } boundaries[2];                   /* boundaries[0]=WHITE, [1]=BLACK */
922
923     char *faces;          /* remember last-seen colour of each face */
924     tdq *faces_todo;
925
926     int score;
927
928     grid *g;
929 };
930 int pearl_loopgen_bias(void *vctx, char *board, int face)
931 {
932     struct pearl_loopgen_bias_ctx *ctx = (struct pearl_loopgen_bias_ctx *)vctx;
933     grid *g = ctx->g;
934     int oldface, newface;
935     int i, j, k;
936
937     tdq_add(ctx->faces_todo, face);
938     while ((j = tdq_remove(ctx->faces_todo)) >= 0) {
939         oldface = ctx->faces[j];
940         ctx->faces[j] = newface = board[j];
941         for (i = 0; i < 2; i++) {
942             struct pearl_loopgen_bias_ctx_boundary *b = &ctx->boundaries[i];
943             int c = b->colour;
944
945             /*
946              * If the face has changed either from or to colour c, we need
947              * to reprocess the edges for this boundary.
948              */
949             if (oldface == c || newface == c) {
950                 grid_face *f = &g->faces[face];
951                 for (k = 0; k < f->order; k++)
952                     tdq_add(b->edges_todo, f->edges[k] - g->edges);
953             }
954         }
955     }
956
957     for (i = 0; i < 2; i++) {
958         struct pearl_loopgen_bias_ctx_boundary *b = &ctx->boundaries[i];
959         int c = b->colour;
960
961         /*
962          * Go through the to-do list of edges. For each edge, decide
963          * anew whether it's part of this boundary or not. Any edge
964          * that changes state has to have both its endpoints put on
965          * the vertextypes_todo list.
966          */
967         while ((j = tdq_remove(b->edges_todo)) >= 0) {
968             grid_edge *e = &g->edges[j];
969             int fc1 = e->face1 ? board[e->face1 - g->faces] : FACE_BLACK;
970             int fc2 = e->face2 ? board[e->face2 - g->faces] : FACE_BLACK;
971             int oldedge = b->edges[j];
972             int newedge = (fc1==c) ^ (fc2==c);
973             if (oldedge != newedge) {
974                 b->edges[j] = newedge;
975                 tdq_add(b->vertextypes_todo, e->dot1 - g->dots);
976                 tdq_add(b->vertextypes_todo, e->dot2 - g->dots);
977             }
978         }
979
980         /*
981          * Go through the to-do list of vertices whose types need
982          * refreshing. For each one, decide whether it's a corner, a
983          * straight, or a vertex not in the loop, and in the former
984          * two cases also work out the indices of its neighbour
985          * vertices along the loop. Any vertex that changes state must
986          * be put back on the to-do list for deciding if it's a black
987          * clue site, and so must its two new neighbours _and_ its two
988          * old neighbours.
989          */
990         while ((j = tdq_remove(b->vertextypes_todo)) >= 0) {
991             grid_dot *d = &g->dots[j];
992             int neighbours[2], type = 0, n = 0;
993             
994             for (k = 0; k < d->order; k++) {
995                 grid_edge *e = d->edges[k];
996                 grid_dot *d2 = (e->dot1 == d ? e->dot2 : e->dot1);
997                 /* dir == 0,1,2,3 for an edge going L,U,R,D */
998                 int dir = (d->y == d2->y) + 2*(d->x+d->y > d2->x+d2->y);
999                 int ei = e - g->edges;
1000                 if (b->edges[ei]) {
1001                     type |= 1 << dir;
1002                     neighbours[n] = d2 - g->dots; 
1003                     n++;
1004                 }
1005             }
1006
1007             /*
1008              * Decide if it's a corner, and set the corner flag if so.
1009              */
1010             if (type != 0 && type != 0x5 && type != 0xA)
1011                 type |= 0x10;
1012
1013             if (type != b->vertextypes[j]) {
1014                 /*
1015                  * Recompute old neighbours, if any.
1016                  */
1017                 if (b->vertextypes[j]) {
1018                     tdq_add(b->blackclues_todo, b->neighbour[0][j]);
1019                     tdq_add(b->blackclues_todo, b->neighbour[1][j]);
1020                 }
1021                 /*
1022                  * Recompute this vertex.
1023                  */
1024                 tdq_add(b->blackclues_todo, j);
1025                 b->vertextypes[j] = type;
1026                 /*
1027                  * Recompute new neighbours, if any.
1028                  */
1029                 if (b->vertextypes[j]) {
1030                     b->neighbour[0][j] = neighbours[0];
1031                     b->neighbour[1][j] = neighbours[1];
1032                     tdq_add(b->blackclues_todo, b->neighbour[0][j]);
1033                     tdq_add(b->blackclues_todo, b->neighbour[1][j]);
1034                 }
1035             }
1036         }
1037
1038         /*
1039          * Go through the list of vertices which we must check to see
1040          * if they're black clue sites. Each one is a black clue site
1041          * iff it is a corner and its loop neighbours are non-corners.
1042          * Adjust the running total of black clues we've counted.
1043          */
1044         while ((j = tdq_remove(b->blackclues_todo)) >= 0) {
1045             ctx->score -= b->blackclues[j];
1046             b->blackclues[j] = ((b->vertextypes[j] & 0x10) &&
1047                                 !((b->vertextypes[b->neighbour[0][j]] |
1048                                    b->vertextypes[b->neighbour[1][j]])
1049                                   & 0x10));
1050             ctx->score += b->blackclues[j];
1051         }
1052     }
1053
1054     return ctx->score;
1055 }
1056
1057 void pearl_loopgen(int w, int h, char *lines, random_state *rs)
1058 {
1059     grid *g = grid_new(GRID_SQUARE, w-1, h-1, NULL);
1060     char *board = snewn(g->num_faces, char);
1061     int i, s = g->tilesize;
1062     struct pearl_loopgen_bias_ctx biasctx;
1063
1064     memset(lines, 0, w*h);
1065
1066     /*
1067      * Initialise the context for the bias function. Initially we fill
1068      * all the to-do lists, so that the first call will scan
1069      * everything; thereafter the lists stay empty so we make
1070      * incremental changes.
1071      */
1072     biasctx.g = g;
1073     biasctx.faces = snewn(g->num_faces, char);
1074     biasctx.faces_todo = tdq_new(g->num_faces);
1075     tdq_fill(biasctx.faces_todo);
1076     biasctx.score = 0;
1077     memset(biasctx.faces, FACE_GREY, g->num_faces);
1078     for (i = 0; i < 2; i++) {
1079         biasctx.boundaries[i].edges = snewn(g->num_edges, char);
1080         memset(biasctx.boundaries[i].edges, 0, g->num_edges);
1081         biasctx.boundaries[i].edges_todo = tdq_new(g->num_edges);
1082         tdq_fill(biasctx.boundaries[i].edges_todo);
1083         biasctx.boundaries[i].vertextypes = snewn(g->num_dots, char);
1084         memset(biasctx.boundaries[i].vertextypes, 0, g->num_dots);
1085         biasctx.boundaries[i].neighbour[0] = snewn(g->num_dots, int);
1086         biasctx.boundaries[i].neighbour[1] = snewn(g->num_dots, int);
1087         biasctx.boundaries[i].vertextypes_todo = tdq_new(g->num_dots);
1088         tdq_fill(biasctx.boundaries[i].vertextypes_todo);
1089         biasctx.boundaries[i].blackclues = snewn(g->num_dots, char);
1090         memset(biasctx.boundaries[i].blackclues, 0, g->num_dots);
1091         biasctx.boundaries[i].blackclues_todo = tdq_new(g->num_dots);
1092         tdq_fill(biasctx.boundaries[i].blackclues_todo);
1093     }
1094     biasctx.boundaries[0].colour = FACE_WHITE;
1095     biasctx.boundaries[1].colour = FACE_BLACK;
1096     generate_loop(g, board, rs, pearl_loopgen_bias, &biasctx);
1097     sfree(biasctx.faces);
1098     tdq_free(biasctx.faces_todo);
1099     for (i = 0; i < 2; i++) {
1100         sfree(biasctx.boundaries[i].edges);
1101         tdq_free(biasctx.boundaries[i].edges_todo);
1102         sfree(biasctx.boundaries[i].vertextypes);
1103         sfree(biasctx.boundaries[i].neighbour[0]);
1104         sfree(biasctx.boundaries[i].neighbour[1]);
1105         tdq_free(biasctx.boundaries[i].vertextypes_todo);
1106         sfree(biasctx.boundaries[i].blackclues);
1107         tdq_free(biasctx.boundaries[i].blackclues_todo);
1108     }
1109
1110     for (i = 0; i < g->num_edges; i++) {
1111         grid_edge *e = g->edges + i;
1112         enum face_colour c1 = FACE_COLOUR(e->face1);
1113         enum face_colour c2 = FACE_COLOUR(e->face2);
1114         assert(c1 != FACE_GREY);
1115         assert(c2 != FACE_GREY);
1116         if (c1 != c2) {
1117             /* This grid edge is on the loop: lay line along it */
1118             int x1 = e->dot1->x/s, y1 = e->dot1->y/s;
1119             int x2 = e->dot2->x/s, y2 = e->dot2->y/s;
1120
1121             /* (x1,y1) and (x2,y2) are now in our grid coords (0-w,0-h). */
1122             if (x1 == x2) {
1123                 if (y1 > y2) SWAP(y1,y2);
1124
1125                 assert(y1+1 == y2);
1126                 lines[y1*w+x1] |= D;
1127                 lines[y2*w+x1] |= U;
1128             } else if (y1 == y2) {
1129                 if (x1 > x2) SWAP(x1,x2);
1130
1131                 assert(x1+1 == x2);
1132                 lines[y1*w+x1] |= R;
1133                 lines[y1*w+x2] |= L;
1134             } else
1135                 assert(!"grid with diagonal coords?!");
1136         }
1137     }
1138
1139     grid_free(g);
1140     sfree(board);
1141
1142 #if defined LOOPGEN_DIAGNOSTICS && !defined GENERATION_DIAGNOSTICS
1143     printf("as returned:\n");
1144     for (y = 0; y < h; y++) {
1145         for (x = 0; x < w; x++) {
1146             int type = lines[y*w+x];
1147             char s[5], *p = s;
1148             if (type & L) *p++ = 'L';
1149             if (type & R) *p++ = 'R';
1150             if (type & U) *p++ = 'U';
1151             if (type & D) *p++ = 'D';
1152             *p = '\0';
1153             printf("%3s", s);
1154         }
1155         printf("\n");
1156     }
1157     printf("\n");
1158 #endif
1159 }
1160
1161 static int new_clues(const game_params *params, random_state *rs,
1162                      char *clues, char *grid)
1163 {
1164     int w = params->w, h = params->h, diff = params->difficulty;
1165     int ngen = 0, x, y, d, ret, i;
1166
1167
1168     /*
1169      * Difficulty exception: 5x5 Tricky is not generable (the
1170      * generator will spin forever trying) and so we fudge it to Easy.
1171      */
1172     if (w == 5 && h == 5 && diff > DIFF_EASY)
1173         diff = DIFF_EASY;
1174
1175     while (1) {
1176         ngen++;
1177         pearl_loopgen(w, h, grid, rs);
1178
1179 #ifdef GENERATION_DIAGNOSTICS
1180         printf("grid array:\n");
1181         for (y = 0; y < h; y++) {
1182             for (x = 0; x < w; x++) {
1183                 int type = grid[y*w+x];
1184                 char s[5], *p = s;
1185                 if (type & L) *p++ = 'L';
1186                 if (type & R) *p++ = 'R';
1187                 if (type & U) *p++ = 'U';
1188                 if (type & D) *p++ = 'D';
1189                 *p = '\0';
1190                 printf("%2s ", s);
1191             }
1192             printf("\n");
1193         }
1194         printf("\n");
1195 #endif
1196
1197         /*
1198          * Set up the maximal clue array.
1199          */
1200         for (y = 0; y < h; y++)
1201             for (x = 0; x < w; x++) {
1202                 int type = grid[y*w+x];
1203
1204                 clues[y*w+x] = NOCLUE;
1205
1206                 if ((bLR|bUD) & (1 << type)) {
1207                     /*
1208                      * This is a straight; see if it's a viable
1209                      * candidate for a straight clue. It qualifies if
1210                      * at least one of the squares it connects to is a
1211                      * corner.
1212                      */
1213                     for (d = 1; d <= 8; d += d) if (type & d) {
1214                         int xx = x + DX(d), yy = y + DY(d);
1215                         assert(xx >= 0 && xx < w && yy >= 0 && yy < h);
1216                         if ((bLU|bLD|bRU|bRD) & (1 << grid[yy*w+xx]))
1217                             break;
1218                     }
1219                     if (d <= 8)        /* we found one */
1220                         clues[y*w+x] = STRAIGHT;
1221                 } else if ((bLU|bLD|bRU|bRD) & (1 << type)) {
1222                     /*
1223                      * This is a corner; see if it's a viable candidate
1224                      * for a corner clue. It qualifies if all the
1225                      * squares it connects to are straights.
1226                      */
1227                     for (d = 1; d <= 8; d += d) if (type & d) {
1228                         int xx = x + DX(d), yy = y + DY(d);
1229                         assert(xx >= 0 && xx < w && yy >= 0 && yy < h);
1230                         if (!((bLR|bUD) & (1 << grid[yy*w+xx])))
1231                             break;
1232                     }
1233                     if (d > 8)         /* we didn't find a counterexample */
1234                         clues[y*w+x] = CORNER;
1235                 }
1236             }
1237
1238 #ifdef GENERATION_DIAGNOSTICS
1239         printf("clue array:\n");
1240         for (y = 0; y < h; y++) {
1241             for (x = 0; x < w; x++) {
1242                 printf("%c", " *O"[(unsigned char)clues[y*w+x]]);
1243             }
1244             printf("\n");
1245         }
1246         printf("\n");
1247 #endif
1248
1249         if (!params->nosolve) {
1250             int *cluespace, *straights, *corners;
1251             int nstraights, ncorners, nstraightpos, ncornerpos;
1252
1253             /*
1254              * See if we can solve the puzzle just like this.
1255              */
1256             ret = pearl_solve(w, h, clues, grid, diff, FALSE);
1257             assert(ret > 0);           /* shouldn't be inconsistent! */
1258             if (ret != 1)
1259                 continue;                      /* go round and try again */
1260
1261             /*
1262              * Check this puzzle isn't too easy.
1263              */
1264             if (diff > DIFF_EASY) {
1265                 ret = pearl_solve(w, h, clues, grid, diff-1, FALSE);
1266                 assert(ret > 0);
1267                 if (ret == 1)
1268                     continue; /* too easy: try again */
1269             }
1270
1271             /*
1272              * Now shuffle the grid points and gradually remove the
1273              * clues to find a minimal set which still leaves the
1274              * puzzle soluble.
1275              *
1276              * We preferentially attempt to remove whichever type of
1277              * clue is currently most numerous, to combat a general
1278              * tendency of plain random generation to bias in favour
1279              * of many white clues and few black.
1280              *
1281              * 'nstraights' and 'ncorners' count the number of clues
1282              * of each type currently remaining in the grid;
1283              * 'nstraightpos' and 'ncornerpos' count the clues of each
1284              * type we have left to try to remove. (Clues which we
1285              * have tried and failed to remove are counted by the
1286              * former but not the latter.)
1287              */
1288             cluespace = snewn(w*h, int);
1289             straights = cluespace;
1290             nstraightpos = 0;
1291             for (i = 0; i < w*h; i++)
1292                 if (clues[i] == STRAIGHT)
1293                     straights[nstraightpos++] = i;
1294             corners = straights + nstraightpos;
1295             ncornerpos = 0;
1296             for (i = 0; i < w*h; i++)
1297                 if (clues[i] == STRAIGHT)
1298                     corners[ncornerpos++] = i;
1299             nstraights = nstraightpos;
1300             ncorners = ncornerpos;
1301
1302             shuffle(straights, nstraightpos, sizeof(*straights), rs);
1303             shuffle(corners, ncornerpos, sizeof(*corners), rs);
1304             while (nstraightpos > 0 || ncornerpos > 0) {
1305                 int cluepos;
1306                 int clue;
1307
1308                 /*
1309                  * Decide which clue to try to remove next. If both
1310                  * types are available, we choose whichever kind is
1311                  * currently overrepresented; otherwise we take
1312                  * whatever we can get.
1313                  */
1314                 if (nstraightpos > 0 && ncornerpos > 0) {
1315                     if (nstraights >= ncorners)
1316                         cluepos = straights[--nstraightpos];
1317                     else
1318                         cluepos = straights[--ncornerpos];
1319                 } else {
1320                     if (nstraightpos > 0)
1321                         cluepos = straights[--nstraightpos];
1322                     else
1323                         cluepos = straights[--ncornerpos];
1324                 }
1325
1326                 y = cluepos / w;
1327                 x = cluepos % w;
1328
1329                 clue = clues[y*w+x];
1330                 clues[y*w+x] = 0;              /* try removing this clue */
1331
1332                 ret = pearl_solve(w, h, clues, grid, diff, FALSE);
1333                 assert(ret > 0);
1334                 if (ret != 1)
1335                     clues[y*w+x] = clue;   /* oops, put it back again */
1336             }
1337             sfree(cluespace);
1338         }
1339
1340 #ifdef FINISHED_PUZZLE
1341         printf("clue array:\n");
1342         for (y = 0; y < h; y++) {
1343             for (x = 0; x < w; x++) {
1344                 printf("%c", " *O"[(unsigned char)clues[y*w+x]]);
1345             }
1346             printf("\n");
1347         }
1348         printf("\n");
1349 #endif
1350
1351         break;                         /* got it */
1352     }
1353
1354     debug(("%d %dx%d loops before finished puzzle.\n", ngen, w, h));
1355
1356     return ngen;
1357 }
1358
1359 static char *new_game_desc(const game_params *params, random_state *rs,
1360                            char **aux, int interactive)
1361 {
1362     char *grid, *clues;
1363     char *desc;
1364     int w = params->w, h = params->h, i, j;
1365
1366     grid = snewn(w*h, char);
1367     clues = snewn(w*h, char);
1368
1369     new_clues(params, rs, clues, grid);
1370
1371     desc = snewn(w * h + 1, char);
1372     for (i = j = 0; i < w*h; i++) {
1373         if (clues[i] == NOCLUE && j > 0 &&
1374             desc[j-1] >= 'a' && desc[j-1] < 'z')
1375             desc[j-1]++;
1376         else if (clues[i] == NOCLUE)
1377             desc[j++] = 'a';
1378         else if (clues[i] == CORNER)
1379             desc[j++] = 'B';
1380         else if (clues[i] == STRAIGHT)
1381             desc[j++] = 'W';
1382     }
1383     desc[j] = '\0';
1384
1385     *aux = snewn(w*h+1, char);
1386     for (i = 0; i < w*h; i++)
1387         (*aux)[i] = (grid[i] < 10) ? (grid[i] + '0') : (grid[i] + 'A' - 10);
1388     (*aux)[w*h] = '\0';
1389
1390     sfree(grid);
1391     sfree(clues);
1392
1393     return desc;
1394 }
1395
1396 static char *validate_desc(const game_params *params, const char *desc)
1397 {
1398     int i, sizesofar;
1399     const int totalsize = params->w * params->h;
1400
1401     sizesofar = 0;
1402     for (i = 0; desc[i]; i++) {
1403         if (desc[i] >= 'a' && desc[i] <= 'z')
1404             sizesofar += desc[i] - 'a' + 1;
1405         else if (desc[i] == 'B' || desc[i] == 'W')
1406             sizesofar++;
1407         else
1408             return "unrecognised character in string";
1409     }
1410
1411     if (sizesofar > totalsize)
1412         return "string too long";
1413     else if (sizesofar < totalsize)
1414         return "string too short";
1415
1416     return NULL;
1417 }
1418
1419 static game_state *new_game(midend *me, const game_params *params,
1420                             const char *desc)
1421 {
1422     game_state *state = snew(game_state);
1423     int i, j, sz = params->w*params->h;
1424
1425     state->completed = state->used_solve = FALSE;
1426     state->shared = snew(struct shared_state);
1427
1428     state->shared->w = params->w;
1429     state->shared->h = params->h;
1430     state->shared->sz = sz;
1431     state->shared->refcnt = 1;
1432     state->shared->clues = snewn(sz, char);
1433     for (i = j = 0; desc[i]; i++) {
1434         assert(j < sz);
1435         if (desc[i] >= 'a' && desc[i] <= 'z') {
1436             int n = desc[i] - 'a' + 1;
1437             assert(j + n <= sz);
1438             while (n-- > 0)
1439                 state->shared->clues[j++] = NOCLUE;
1440         } else if (desc[i] == 'B') {
1441             state->shared->clues[j++] = CORNER;
1442         } else if (desc[i] == 'W') {
1443             state->shared->clues[j++] = STRAIGHT;
1444         }
1445     }
1446
1447     state->lines = snewn(sz, char);
1448     state->errors = snewn(sz, char);
1449     state->marks = snewn(sz, char);
1450     for (i = 0; i < sz; i++)
1451         state->lines[i] = state->errors[i] = state->marks[i] = BLANK;
1452
1453     return state;
1454 }
1455
1456 static game_state *dup_game(const game_state *state)
1457 {
1458     game_state *ret = snew(game_state);
1459     int sz = state->shared->sz, i;
1460
1461     ret->shared = state->shared;
1462     ret->completed = state->completed;
1463     ret->used_solve = state->used_solve;
1464     ++ret->shared->refcnt;
1465
1466     ret->lines = snewn(sz, char);
1467     ret->errors = snewn(sz, char);
1468     ret->marks = snewn(sz, char);
1469     for (i = 0; i < sz; i++) {
1470         ret->lines[i] = state->lines[i];
1471         ret->errors[i] = state->errors[i];
1472         ret->marks[i] = state->marks[i];
1473     }
1474
1475     return ret;
1476 }
1477
1478 static void free_game(game_state *state)
1479 {
1480     assert(state);
1481     if (--state->shared->refcnt == 0) {
1482         sfree(state->shared->clues);
1483         sfree(state->shared);
1484     }
1485     sfree(state->lines);
1486     sfree(state->errors);
1487     sfree(state->marks);
1488     sfree(state);
1489 }
1490
1491 static char nbits[16] = { 0, 1, 1, 2,
1492                           1, 2, 2, 3,
1493                           1, 2, 2, 3,
1494                           2, 3, 3, 4 };
1495 #define NBITS(l) ( ((l) < 0 || (l) > 15) ? 4 : nbits[l] )
1496
1497 #define ERROR_CLUE 16
1498
1499 static void dsf_update_completion(game_state *state, int *loopclass,
1500                                  int ax, int ay, char dir,
1501                                  int *dsf, int *dsfsize)
1502 {
1503     int w = state->shared->w /*, h = state->shared->h */;
1504     int ac = ay*w+ax, ae, bx, by, bc, be;
1505
1506     if (!(state->lines[ac] & dir)) return; /* no link */
1507     bx = ax + DX(dir); by = ay + DY(dir);
1508
1509     assert(INGRID(state, bx, by)); /* should not have a link off grid */
1510
1511     bc = by*w+bx;
1512 #if 0
1513     assert(state->lines[bc] & F(dir)); /* should have reciprocal link */
1514 #endif
1515     /* TODO put above assertion back in once we stop generating partially
1516      * soluble puzzles. */
1517     if (!(state->lines[bc] & F(dir))) return;
1518
1519     ae = dsf_canonify(dsf, ac);
1520     be = dsf_canonify(dsf, bc);
1521
1522     if (ae == be) { /* detected a loop! */
1523         if (*loopclass != -1) /* this is the second loop, doom. */
1524             return;
1525         *loopclass = ae;
1526     } else {
1527         int size = dsfsize[ae] + dsfsize[be];
1528         dsf_merge(dsf, ac, bc);
1529         ae = dsf_canonify(dsf, ac);
1530         dsfsize[ae] = size;
1531     }
1532     return;
1533 }
1534
1535 static void check_completion(game_state *state, int mark)
1536 {
1537     int w = state->shared->w, h = state->shared->h, x, y, i, d;
1538     int had_error = FALSE /*, is_complete = FALSE */, loopclass;
1539     int *dsf, *dsfsize;
1540
1541     if (mark) {
1542         for (i = 0; i < w*h; i++) {
1543             state->errors[i] = 0;
1544         }
1545     }
1546
1547 #define ERROR(x,y,e) do { had_error = TRUE; if (mark) state->errors[(y)*w+(x)] |= (e); } while(0)
1548
1549     /*
1550      * First of all: we should have one single closed loop, passing through all clues.
1551      */
1552     dsf = snewn(w*h, int);
1553     dsfsize = snewn(w*h, int);
1554     dsf_init(dsf, w*h);
1555     for (i = 0; i < w*h; i++) dsfsize[i] = 1;
1556     loopclass = -1;
1557
1558     for (x = 0; x < w; x++) {
1559         for (y = 0; y < h; y++) {
1560             dsf_update_completion(state, &loopclass, x, y, R, dsf, dsfsize);
1561             dsf_update_completion(state, &loopclass, x, y, D, dsf, dsfsize);
1562         }
1563     }
1564     if (loopclass != -1) {
1565         /* We have a loop. Check all squares with lines on. */
1566         for (x = 0; x < w; x++) {
1567             for (y = 0; y < h; y++) {
1568                 if (state->lines[y*w+x] == BLANK) {
1569                     if (state->shared->clues[y*w+x] != NOCLUE) {
1570                         /* the loop doesn't include this clue square! */
1571                         ERROR(x, y, ERROR_CLUE);
1572                     }
1573                 } else {
1574                     if (dsf_canonify(dsf, y*w+x) != loopclass) {
1575                         /* these lines are not on the loop: mark them as error. */
1576                         ERROR(x, y, state->lines[y*w+x]);
1577                     }
1578                 }
1579             }
1580         }
1581     }
1582
1583     /*
1584      * Second: check no clues are contradicted.
1585      */
1586
1587     for (x = 0; x < w; x++) {
1588         for (y = 0; y < h; y++) {
1589             int type = state->lines[y*w+x];
1590             /*
1591              * Check that no square has more than two line segments.
1592              */
1593             if (NBITS(type) > 2) {
1594                 ERROR(x,y,type);
1595             }
1596             /*
1597              * Check that no clues are contradicted. This code is similar to
1598              * the code that sets up the maximal clue array for any given
1599              * loop.
1600              */
1601             if (state->shared->clues[y*w+x] == CORNER) {
1602                 /* Supposed to be a corner: will find a contradiction if
1603                  * it actually contains a straight line, or if it touches any
1604                  * corners. */
1605                 if ((bLR|bUD) & (1 << type)) {
1606                     ERROR(x,y,ERROR_CLUE); /* actually straight */
1607                 }
1608                 for (d = 1; d <= 8; d += d) if (type & d) {
1609                     int xx = x + DX(d), yy = y + DY(d);
1610                     if (!INGRID(state, xx, yy)) {
1611                         ERROR(x,y,d); /* leads off grid */
1612                     } else {
1613                         if ((bLU|bLD|bRU|bRD) & (1 << state->lines[yy*w+xx])) {
1614                             ERROR(x,y,ERROR_CLUE); /* touches corner */
1615                         }
1616                     }
1617                 }
1618             } else if (state->shared->clues[y*w+x] == STRAIGHT) {
1619                 /* Supposed to be straight: will find a contradiction if
1620                  * it actually contains a corner, or if it only touches
1621                  * straight lines. */
1622                 if ((bLU|bLD|bRU|bRD) & (1 << type)) {
1623                     ERROR(x,y,ERROR_CLUE); /* actually a corner */
1624                 }
1625                 i = 0;
1626                 for (d = 1; d <= 8; d += d) if (type & d) {
1627                     int xx = x + DX(d), yy = y + DY(d);
1628                     if (!INGRID(state, xx, yy)) {
1629                         ERROR(x,y,d); /* leads off grid */
1630                     } else {
1631                         if ((bLR|bUD) & (1 << state->lines[yy*w+xx]))
1632                             i++; /* a straight */
1633                     }
1634                 }
1635                 if (i >= 2 && NBITS(type) >= 2) {
1636                     ERROR(x,y,ERROR_CLUE); /* everything touched is straight */
1637                 }
1638             }
1639         }
1640     }
1641     if (!had_error && loopclass != -1) {
1642         state->completed = TRUE;
1643         state->loop_length = dsfsize[loopclass];
1644     }
1645
1646     sfree(dsf);
1647     sfree(dsfsize);
1648
1649     return;
1650 }
1651
1652 /* completion check:
1653  *
1654  * - no clues must be contradicted (highlight clue itself in error if so)
1655  * - if there is a closed loop it must include every line segment laid
1656  *    - if there's a smaller closed loop then highlight whole loop as error
1657  * - no square must have more than 2 lines radiating from centre point
1658  *   (highlight all lines in that square as error if so)
1659  */
1660
1661 static char *solve_for_diff(game_state *state, char *old_lines, char *new_lines)
1662 {
1663     int w = state->shared->w, h = state->shared->h, i;
1664     char *move = snewn(w*h*40, char), *p = move;
1665
1666     *p++ = 'S';
1667     for (i = 0; i < w*h; i++) {
1668         if (old_lines[i] != new_lines[i]) {
1669             p += sprintf(p, ";R%d,%d,%d", new_lines[i], i%w, i/w);
1670         }
1671     }
1672     *p++ = '\0';
1673     move = sresize(move, p - move, char);
1674
1675     return move;
1676 }
1677
1678 static char *solve_game(const game_state *state, const game_state *currstate,
1679                         const char *aux, char **error)
1680 {
1681     game_state *solved = dup_game(state);
1682     int i, ret, sz = state->shared->sz;
1683     char *move;
1684
1685     if (aux) {
1686         for (i = 0; i < sz; i++) {
1687             if (aux[i] >= '0' && aux[i] <= '9')
1688                 solved->lines[i] = aux[i] - '0';
1689             else if (aux[i] >= 'A' && aux[i] <= 'F')
1690                 solved->lines[i] = aux[i] - 'A' + 10;
1691             else {
1692                 *error = "invalid char in aux";
1693                 move = NULL;
1694                 goto done;
1695             }
1696         }
1697         ret = 1;
1698     } else {
1699         /* Try to solve with present (half-solved) state first: if there's no
1700          * solution from there go back to original state. */
1701         ret = pearl_solve(currstate->shared->w, currstate->shared->h,
1702                           currstate->shared->clues, solved->lines,
1703                           DIFFCOUNT, FALSE);
1704         if (ret < 1)
1705             ret = pearl_solve(state->shared->w, state->shared->h,
1706                               state->shared->clues, solved->lines,
1707                               DIFFCOUNT, FALSE);
1708
1709     }
1710
1711     if (ret < 1) {
1712         *error = "Unable to find solution";
1713         move = NULL;
1714     } else {
1715         move = solve_for_diff(solved, currstate->lines, solved->lines);
1716     }
1717
1718 done:
1719     free_game(solved);
1720     return move;
1721 }
1722
1723 static int game_can_format_as_text_now(const game_params *params)
1724 {
1725     return TRUE;
1726 }
1727
1728 static char *game_text_format(const game_state *state)
1729 {
1730     int w = state->shared->w, h = state->shared->h, cw = 4, ch = 2;
1731     int gw = cw*(w-1) + 2, gh = ch*(h-1) + 1, len = gw * gh, r, c, j;
1732     char *board = snewn(len + 1, char);
1733
1734     assert(board);
1735     memset(board, ' ', len);
1736
1737     for (r = 0; r < h; ++r) {
1738         for (c = 0; c < w; ++c) {
1739             int i = r*w + c, cell = r*ch*gw + c*cw;
1740             board[cell] = "+BW"[(unsigned char)state->shared->clues[i]];
1741             if (c < w - 1 && (state->lines[i] & R || state->lines[i+1] & L))
1742                 memset(board + cell + 1, '-', cw - 1);
1743             if (r < h - 1 && (state->lines[i] & D || state->lines[i+w] & U))
1744                 for (j = 1; j < ch; ++j) board[cell + j*gw] = '|';
1745             if (c < w - 1 && (state->marks[i] & R || state->marks[i+1] & L))
1746                 board[cell + cw/2] = 'x';
1747             if (r < h - 1 && (state->marks[i] & D || state->marks[i+w] & U))
1748                 board[cell + (ch/2 * gw)] = 'x';
1749         }
1750
1751         for (j = 0; j < (r == h - 1 ? 1 : ch); ++j)
1752             board[r*ch*gw + (gw - 1) + j*gw] = '\n';
1753     }
1754
1755     board[len] = '\0';
1756     return board;
1757 }
1758
1759 struct game_ui {
1760     int *dragcoords;       /* list of (y*w+x) coords in drag so far */
1761     int ndragcoords;       /* number of entries in dragcoords.
1762                             * 0 = click but no drag yet. -1 = no drag at all */
1763     int clickx, clicky;    /* pixel position of initial click */
1764
1765     int curx, cury;        /* grid position of keyboard cursor */
1766     int cursor_active;     /* TRUE iff cursor is shown */
1767 };
1768
1769 static game_ui *new_ui(const game_state *state)
1770 {
1771     game_ui *ui = snew(game_ui);
1772     int sz = state->shared->sz;
1773
1774     ui->ndragcoords = -1;
1775     ui->dragcoords = snewn(sz, int);
1776     ui->cursor_active = FALSE;
1777     ui->curx = ui->cury = 0;
1778
1779     return ui;
1780 }
1781
1782 static void free_ui(game_ui *ui)
1783 {
1784     sfree(ui->dragcoords);
1785     sfree(ui);
1786 }
1787
1788 static char *encode_ui(const game_ui *ui)
1789 {
1790     return NULL;
1791 }
1792
1793 static void decode_ui(game_ui *ui, const char *encoding)
1794 {
1795 }
1796
1797 static void game_changed_state(game_ui *ui, const game_state *oldstate,
1798                                const game_state *newstate)
1799 {
1800 }
1801
1802 #define PREFERRED_TILE_SIZE 31
1803 #define HALFSZ (ds->halfsz)
1804 #define TILE_SIZE (ds->halfsz*2 + 1)
1805
1806 #define BORDER ((get_gui_style() == GUI_LOOPY) ? (TILE_SIZE/8) : (TILE_SIZE/2))
1807
1808 #define BORDER_WIDTH (max(TILE_SIZE / 32, 1))
1809
1810 #define COORD(x) ( (x) * TILE_SIZE + BORDER )
1811 #define CENTERED_COORD(x) ( COORD(x) + TILE_SIZE/2 )
1812 #define FROMCOORD(x) ( ((x) < BORDER) ? -1 : ( ((x) - BORDER) / TILE_SIZE) )
1813
1814 #define DS_ESHIFT 4     /* R/U/L/D shift, for error flags */
1815 #define DS_DSHIFT 8     /* R/U/L/D shift, for drag-in-progress flags */
1816 #define DS_MSHIFT 12    /* shift for no-line mark */
1817
1818 #define DS_ERROR_CLUE (1 << 20)
1819 #define DS_FLASH (1 << 21)
1820 #define DS_CURSOR (1 << 22)
1821
1822 enum { GUI_MASYU, GUI_LOOPY };
1823
1824 static int get_gui_style(void)
1825 {
1826     static int gui_style = -1;
1827
1828     if (gui_style == -1) {
1829         char *env = getenv("PEARL_GUI_LOOPY");
1830         if (env && (env[0] == 'y' || env[0] == 'Y'))
1831             gui_style = GUI_LOOPY;
1832         else
1833             gui_style = GUI_MASYU;
1834     }
1835     return gui_style;
1836 }
1837
1838 struct game_drawstate {
1839     int halfsz;
1840     int started;
1841
1842     int w, h, sz;
1843     unsigned int *lflags;       /* size w*h */
1844
1845     char *draglines;            /* size w*h; lines flipped by current drag */
1846 };
1847
1848 static void update_ui_drag(const game_state *state, game_ui *ui,
1849                            int gx, int gy)
1850 {
1851     int /* sz = state->shared->sz, */ w = state->shared->w;
1852     int i, ox, oy, pos;
1853     int lastpos;
1854
1855     if (!INGRID(state, gx, gy))
1856         return;                        /* square is outside grid */
1857
1858     if (ui->ndragcoords < 0)
1859         return;                        /* drag not in progress anyway */
1860
1861     pos = gy * w + gx;
1862
1863     lastpos = ui->dragcoords[ui->ndragcoords > 0 ? ui->ndragcoords-1 : 0];
1864     if (pos == lastpos)
1865         return;             /* same square as last visited one */
1866
1867     /* Drag confirmed, if it wasn't already. */
1868     if (ui->ndragcoords == 0)
1869         ui->ndragcoords = 1;
1870
1871     /*
1872      * Dragging the mouse into a square that's already been visited by
1873      * the drag path so far has the effect of truncating the path back
1874      * to that square, so a player can back out part of an uncommitted
1875      * drag without having to let go of the mouse.
1876      */
1877     for (i = 0; i < ui->ndragcoords; i++)
1878         if (pos == ui->dragcoords[i]) {
1879             ui->ndragcoords = i+1;
1880             return;
1881         }
1882
1883     /*
1884      * Otherwise, dragging the mouse into a square that's a rook-move
1885      * away from the last one on the path extends the path.
1886      */
1887     oy = ui->dragcoords[ui->ndragcoords-1] / w;
1888     ox = ui->dragcoords[ui->ndragcoords-1] % w;
1889     if (ox == gx || oy == gy) {
1890         int dx = (gx < ox ? -1 : gx > ox ? +1 : 0);
1891         int dy = (gy < oy ? -1 : gy > oy ? +1 : 0);
1892         int dir = (dy>0 ? D : dy<0 ? U : dx>0 ? R : L);
1893         while (ox != gx || oy != gy) {
1894             /*
1895              * If the drag attempts to cross a 'no line here' mark,
1896              * stop there. We physically don't allow the user to drag
1897              * over those marks.
1898              */
1899             if (state->marks[oy*w+ox] & dir)
1900                 break;
1901             ox += dx;
1902             oy += dy;
1903             ui->dragcoords[ui->ndragcoords++] = oy * w + ox;
1904         }
1905     }
1906
1907     /*
1908      * Failing that, we do nothing at all: if the user has dragged
1909      * diagonally across the board, they'll just have to return the
1910      * mouse to the last known position and do whatever they meant to
1911      * do again, more slowly and clearly.
1912      */
1913 }
1914
1915 /*
1916  * Routine shared between interpret_move and game_redraw to work out
1917  * the intended effect of a drag path on the grid.
1918  *
1919  * Call it in a loop, like this:
1920  *
1921  *     int clearing = TRUE;
1922  *     for (i = 0; i < ui->ndragcoords - 1; i++) {
1923  *         int sx, sy, dx, dy, dir, oldstate, newstate;
1924  *         interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy,
1925  *                           &dir, &oldstate, &newstate);
1926  *
1927  *         [do whatever is needed to handle the fact that the drag
1928  *         wants the edge from sx,sy to dx,dy (heading in direction
1929  *         'dir' at the sx,sy end) to be changed from state oldstate
1930  *         to state newstate, each of which equals either 0 or dir]
1931  *     }
1932  */
1933 static void interpret_ui_drag(const game_state *state, const game_ui *ui,
1934                               int *clearing, int i, int *sx, int *sy,
1935                               int *dx, int *dy, int *dir,
1936                               int *oldstate, int *newstate)
1937 {
1938     int w = state->shared->w;
1939     int sp = ui->dragcoords[i], dp = ui->dragcoords[i+1];
1940     *sy = sp/w;
1941     *sx = sp%w;
1942     *dy = dp/w;
1943     *dx = dp%w;
1944     *dir = (*dy>*sy ? D : *dy<*sy ? U : *dx>*sx ? R : L);
1945     *oldstate = state->lines[sp] & *dir;
1946     if (*oldstate) {
1947         /*
1948          * The edge we've dragged over was previously
1949          * present. Set it to absent, unless we've already
1950          * stopped doing that.
1951          */
1952         *newstate = *clearing ? 0 : *dir;
1953     } else {
1954         /*
1955          * The edge we've dragged over was previously
1956          * absent. Set it to present, and cancel the
1957          * 'clearing' flag so that all subsequent edges in
1958          * the drag are set rather than cleared.
1959          */
1960         *newstate = *dir;
1961         *clearing = FALSE;
1962     }
1963 }
1964
1965 static char *mark_in_direction(const game_state *state, int x, int y, int dir,
1966                                int primary, char *buf)
1967 {
1968     int w = state->shared->w /*, h = state->shared->h, sz = state->shared->sz */;
1969     int x2 = x + DX(dir);
1970     int y2 = y + DY(dir);
1971     int dir2 = F(dir);
1972
1973     char ch = primary ? 'F' : 'M', *other;
1974
1975     if (!INGRID(state, x, y) || !INGRID(state, x2, y2)) return "";
1976
1977     /* disallow laying a mark over a line, or vice versa. */
1978     other = primary ? state->marks : state->lines;
1979     if (other[y*w+x] & dir || other[y2*w+x2] & dir2) return "";
1980     
1981     sprintf(buf, "%c%d,%d,%d;%c%d,%d,%d", ch, dir, x, y, ch, dir2, x2, y2);
1982     return dupstr(buf);
1983 }
1984
1985 #define KEY_DIRECTION(btn) (\
1986     (btn) == CURSOR_DOWN ? D : (btn) == CURSOR_UP ? U :\
1987     (btn) == CURSOR_LEFT ? L : R)
1988
1989 static char *interpret_move(const game_state *state, game_ui *ui,
1990                             const game_drawstate *ds,
1991                             int x, int y, int button)
1992 {
1993     int w = state->shared->w, h = state->shared->h /*, sz = state->shared->sz */;
1994     int gx = FROMCOORD(x), gy = FROMCOORD(y), i;
1995     int release = FALSE;
1996     char tmpbuf[80];
1997
1998     int shift = button & MOD_SHFT, control = button & MOD_CTRL;
1999     button &= ~MOD_MASK;
2000
2001     if (IS_MOUSE_DOWN(button)) {
2002         ui->cursor_active = FALSE;
2003
2004         if (!INGRID(state, gx, gy)) {
2005             ui->ndragcoords = -1;
2006             return NULL;
2007         }
2008
2009         ui->clickx = x; ui->clicky = y;
2010         ui->dragcoords[0] = gy * w + gx;
2011         ui->ndragcoords = 0;           /* will be 1 once drag is confirmed */
2012
2013         return "";
2014     }
2015
2016     if (button == LEFT_DRAG && ui->ndragcoords >= 0) {
2017         update_ui_drag(state, ui, gx, gy);
2018         return "";
2019     }
2020
2021     if (IS_MOUSE_RELEASE(button)) release = TRUE;
2022
2023     if (IS_CURSOR_MOVE(button)) {
2024         if (!ui->cursor_active) {
2025             ui->cursor_active = TRUE;
2026         } else if (control | shift) {
2027             char *move;
2028             if (ui->ndragcoords > 0) return NULL;
2029             ui->ndragcoords = -1;
2030             move = mark_in_direction(state, ui->curx, ui->cury,
2031                                      KEY_DIRECTION(button), control, tmpbuf);
2032             if (control && !shift && *move)
2033                 move_cursor(button, &ui->curx, &ui->cury, w, h, FALSE);
2034             return move;
2035         } else {
2036             move_cursor(button, &ui->curx, &ui->cury, w, h, FALSE);
2037             if (ui->ndragcoords >= 0)
2038                 update_ui_drag(state, ui, ui->curx, ui->cury);
2039         }
2040         return "";
2041     }
2042
2043     if (IS_CURSOR_SELECT(button)) {
2044         if (!ui->cursor_active) {
2045             ui->cursor_active = TRUE;
2046             return "";
2047         } else if (button == CURSOR_SELECT) {
2048             if (ui->ndragcoords == -1) {
2049                 ui->ndragcoords = 0;
2050                 ui->dragcoords[0] = ui->cury * w + ui->curx;
2051                 ui->clickx = CENTERED_COORD(ui->curx);
2052                 ui->clicky = CENTERED_COORD(ui->cury);
2053                 return "";
2054             } else release = TRUE;
2055         } else if (button == CURSOR_SELECT2 && ui->ndragcoords >= 0) {
2056             ui->ndragcoords = -1;
2057             return "";
2058         }
2059     }
2060
2061     if (button == 27 || button == '\b') {
2062         ui->ndragcoords = -1;
2063         return "";
2064     }
2065
2066     if (release) {
2067         if (ui->ndragcoords > 0) {
2068             /* End of a drag: process the cached line data. */
2069             int buflen = 0, bufsize = 256, tmplen;
2070             char *buf = NULL;
2071             const char *sep = "";
2072             int clearing = TRUE;
2073
2074             for (i = 0; i < ui->ndragcoords - 1; i++) {
2075                 int sx, sy, dx, dy, dir, oldstate, newstate;
2076                 interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy,
2077                                   &dir, &oldstate, &newstate);
2078
2079                 if (oldstate != newstate) {
2080                     if (!buf) buf = snewn(bufsize, char);
2081                     tmplen = sprintf(tmpbuf, "%sF%d,%d,%d;F%d,%d,%d", sep,
2082                                      dir, sx, sy, F(dir), dx, dy);
2083                     if (buflen + tmplen >= bufsize) {
2084                         bufsize = (buflen + tmplen) * 5 / 4 + 256;
2085                         buf = sresize(buf, bufsize, char);
2086                     }
2087                     strcpy(buf + buflen, tmpbuf);
2088                     buflen += tmplen;
2089                     sep = ";";
2090                 }
2091             }
2092
2093             ui->ndragcoords = -1;
2094
2095             return buf ? buf : "";
2096         } else if (ui->ndragcoords == 0) {
2097             /* Click (or tiny drag). Work out which edge we were
2098              * closest to. */
2099             int cx, cy;
2100
2101             ui->ndragcoords = -1;
2102
2103             /*
2104              * We process clicks based on the mouse-down location,
2105              * because that's more natural for a user to carefully
2106              * control than the mouse-up.
2107              */
2108             x = ui->clickx;
2109             y = ui->clicky;
2110
2111             gx = FROMCOORD(x);
2112             gy = FROMCOORD(y);
2113             cx = CENTERED_COORD(gx);
2114             cy = CENTERED_COORD(gy);
2115
2116             if (!INGRID(state, gx, gy)) return "";
2117
2118             if (max(abs(x-cx),abs(y-cy)) < TILE_SIZE/4) {
2119                 /* TODO closer to centre of grid: process as a cell click not an edge click. */
2120
2121                 return "";
2122             } else {
2123                 int direction;
2124                 if (abs(x-cx) < abs(y-cy)) {
2125                     /* Closest to top/bottom edge. */
2126                     direction = (y < cy) ? U : D;
2127                 } else {
2128                     /* Closest to left/right edge. */
2129                     direction = (x < cx) ? L : R;
2130                 }
2131                 return mark_in_direction(state, gx, gy, direction,
2132                                          (button == LEFT_RELEASE), tmpbuf);
2133             }
2134         }
2135     }
2136
2137     if (button == 'H' || button == 'h')
2138         return dupstr("H");
2139
2140     return NULL;
2141 }
2142
2143 static game_state *execute_move(const game_state *state, const char *move)
2144 {
2145     int w = state->shared->w, h = state->shared->h;
2146     char c;
2147     int x, y, l, n;
2148     game_state *ret = dup_game(state);
2149
2150     debug(("move: %s\n", move));
2151
2152     while (*move) {
2153         c = *move;
2154         if (c == 'S') {
2155             ret->used_solve = TRUE;
2156             move++;
2157         } else if (c == 'L' || c == 'N' || c == 'R' || c == 'F' || c == 'M') {
2158             /* 'line' or 'noline' or 'replace' or 'flip' or 'mark' */
2159             move++;
2160             if (sscanf(move, "%d,%d,%d%n", &l, &x, &y, &n) != 3)
2161                 goto badmove;
2162             if (!INGRID(state, x, y)) goto badmove;
2163             if (l < 0 || l > 15) goto badmove;
2164
2165             if (c == 'L')
2166                 ret->lines[y*w + x] |= (char)l;
2167             else if (c == 'N')
2168                 ret->lines[y*w + x] &= ~((char)l);
2169             else if (c == 'R') {
2170                 ret->lines[y*w + x] = (char)l;
2171                 ret->marks[y*w + x] &= ~((char)l); /* erase marks too */
2172             } else if (c == 'F')
2173                 ret->lines[y*w + x] ^= (char)l;
2174             else if (c == 'M')
2175                 ret->marks[y*w + x] ^= (char)l;
2176
2177             /*
2178              * If we ended up trying to lay a line _over_ a mark,
2179              * that's a failed move: interpret_move() should have
2180              * ensured we never received a move string like that in
2181              * the first place.
2182              */
2183             if ((ret->lines[y*w + x] & (char)l) &&
2184                 (ret->marks[y*w + x] & (char)l))
2185                 goto badmove;
2186
2187             move += n;
2188         } else if (strcmp(move, "H") == 0) {
2189             pearl_solve(ret->shared->w, ret->shared->h,
2190                         ret->shared->clues, ret->lines, DIFFCOUNT, TRUE);
2191             for (n = 0; n < w*h; n++)
2192                 ret->marks[n] &= ~ret->lines[n]; /* erase marks too */
2193             move++;
2194         } else {
2195             goto badmove;
2196         }
2197         if (*move == ';')
2198             move++;
2199         else if (*move)
2200             goto badmove;
2201     }
2202
2203     check_completion(ret, TRUE);
2204
2205     return ret;
2206
2207 badmove:
2208     free_game(ret);
2209     return NULL;
2210 }
2211
2212 /* ----------------------------------------------------------------------
2213  * Drawing routines.
2214  */
2215
2216 #define FLASH_TIME 0.5F
2217
2218 static void game_compute_size(const game_params *params, int tilesize,
2219                               int *x, int *y)
2220 {
2221     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2222     struct { int halfsz; } ads, *ds = &ads;
2223     ads.halfsz = (tilesize-1)/2;
2224
2225     *x = (params->w) * TILE_SIZE + 2 * BORDER;
2226     *y = (params->h) * TILE_SIZE + 2 * BORDER;
2227 }
2228
2229 static void game_set_size(drawing *dr, game_drawstate *ds,
2230                           const game_params *params, int tilesize)
2231 {
2232     ds->halfsz = (tilesize-1)/2;
2233 }
2234
2235 static float *game_colours(frontend *fe, int *ncolours)
2236 {
2237     float *ret = snewn(3 * NCOLOURS, float);
2238     int i;
2239
2240     game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT);
2241
2242     for (i = 0; i < 3; i++) {
2243         ret[COL_BLACK * 3 + i] = 0.0F;
2244         ret[COL_WHITE * 3 + i] = 1.0F;
2245         ret[COL_GRID * 3 + i] = 0.4F;
2246     }
2247
2248     ret[COL_ERROR * 3 + 0] = 1.0F;
2249     ret[COL_ERROR * 3 + 1] = 0.0F;
2250     ret[COL_ERROR * 3 + 2] = 0.0F;
2251
2252     ret[COL_DRAGON * 3 + 0] = 0.0F;
2253     ret[COL_DRAGON * 3 + 1] = 0.0F;
2254     ret[COL_DRAGON * 3 + 2] = 1.0F;
2255
2256     ret[COL_DRAGOFF * 3 + 0] = 0.8F;
2257     ret[COL_DRAGOFF * 3 + 1] = 0.8F;
2258     ret[COL_DRAGOFF * 3 + 2] = 1.0F;
2259
2260     ret[COL_FLASH * 3 + 0] = 1.0F;
2261     ret[COL_FLASH * 3 + 1] = 1.0F;
2262     ret[COL_FLASH * 3 + 2] = 1.0F;
2263
2264     *ncolours = NCOLOURS;
2265
2266     return ret;
2267 }
2268
2269 static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
2270 {
2271     struct game_drawstate *ds = snew(struct game_drawstate);
2272     int i;
2273
2274     ds->halfsz = 0;
2275     ds->started = FALSE;
2276
2277     ds->w = state->shared->w;
2278     ds->h = state->shared->h;
2279     ds->sz = state->shared->sz;
2280     ds->lflags = snewn(ds->sz, unsigned int);
2281     for (i = 0; i < ds->sz; i++)
2282         ds->lflags[i] = 0;
2283
2284     ds->draglines = snewn(ds->sz, char);
2285
2286     return ds;
2287 }
2288
2289 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
2290 {
2291     sfree(ds->draglines);
2292     sfree(ds->lflags);
2293     sfree(ds);
2294 }
2295
2296 static void draw_lines_specific(drawing *dr, game_drawstate *ds,
2297                                 int x, int y, unsigned int lflags,
2298                                 unsigned int shift, int c)
2299 {
2300     int ox = COORD(x), oy = COORD(y);
2301     int t2 = HALFSZ, t16 = HALFSZ/4;
2302     int cx = ox + t2, cy = oy + t2;
2303     int d;
2304
2305     /* Draw each of the four directions, where laid (or error, or drag, etc.) */
2306     for (d = 1; d < 16; d *= 2) {
2307         int xoff = t2 * DX(d), yoff = t2 * DY(d);
2308         int xnudge = abs(t16 * DX(C(d))), ynudge = abs(t16 * DY(C(d)));
2309
2310         if ((lflags >> shift) & d) {
2311             int lx = cx + ((xoff < 0) ? xoff : 0) - xnudge;
2312             int ly = cy + ((yoff < 0) ? yoff : 0) - ynudge;
2313
2314             if (c == COL_DRAGOFF && !(lflags & d))
2315                 continue;
2316             if (c == COL_DRAGON && (lflags & d))
2317                 continue;
2318
2319             draw_rect(dr, lx, ly,
2320                       abs(xoff)+2*xnudge+1,
2321                       abs(yoff)+2*ynudge+1, c);
2322             /* end cap */
2323             draw_rect(dr, cx - t16, cy - t16, 2*t16+1, 2*t16+1, c);
2324         }
2325     }
2326 }
2327
2328 static void draw_square(drawing *dr, game_drawstate *ds, const game_ui *ui,
2329                         int x, int y, unsigned int lflags, char clue)
2330 {
2331     int ox = COORD(x), oy = COORD(y);
2332     int t2 = HALFSZ, t16 = HALFSZ/4;
2333     int cx = ox + t2, cy = oy + t2;
2334     int d;
2335
2336     assert(dr);
2337
2338     /* Clip to the grid square. */
2339     clip(dr, ox, oy, TILE_SIZE, TILE_SIZE);
2340
2341     /* Clear the square. */
2342     draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE,
2343               (lflags & DS_CURSOR) ?
2344               COL_CURSOR_BACKGROUND : COL_BACKGROUND);
2345               
2346
2347     if (get_gui_style() == GUI_LOOPY) {
2348         /* Draw small dot, underneath any lines. */
2349         draw_circle(dr, cx, cy, t16, COL_GRID, COL_GRID);
2350     } else {
2351         /* Draw outline of grid square */
2352         draw_line(dr, ox, oy, COORD(x+1), oy, COL_GRID);
2353         draw_line(dr, ox, oy, ox, COORD(y+1), COL_GRID);
2354     }
2355
2356     /* Draw grid: either thin gridlines, or no-line marks.
2357      * We draw these first because the thick laid lines should be on top. */
2358     for (d = 1; d < 16; d *= 2) {
2359         int xoff = t2 * DX(d), yoff = t2 * DY(d);
2360
2361         if ((x == 0 && d == L) ||
2362             (y == 0 && d == U) ||
2363             (x == ds->w-1 && d == R) ||
2364             (y == ds->h-1 && d == D))
2365             continue; /* no gridlines out to the border. */
2366
2367         if ((lflags >> DS_MSHIFT) & d) {
2368             /* either a no-line mark ... */
2369             int mx = cx + xoff, my = cy + yoff, msz = t16;
2370
2371             draw_line(dr, mx-msz, my-msz, mx+msz, my+msz, COL_BLACK);
2372             draw_line(dr, mx-msz, my+msz, mx+msz, my-msz, COL_BLACK);
2373         } else {
2374             if (get_gui_style() == GUI_LOOPY) {
2375                 /* draw grid lines connecting centre of cells */
2376                 draw_line(dr, cx, cy, cx+xoff, cy+yoff, COL_GRID);
2377             }
2378         }
2379     }
2380
2381     /* Draw each of the four directions, where laid (or error, or drag, etc.)
2382      * Order is important here, specifically for the eventual colours of the
2383      * exposed end caps. */
2384     draw_lines_specific(dr, ds, x, y, lflags, 0,
2385                         (lflags & DS_FLASH ? COL_FLASH : COL_BLACK));
2386     draw_lines_specific(dr, ds, x, y, lflags, DS_ESHIFT, COL_ERROR);
2387     draw_lines_specific(dr, ds, x, y, lflags, DS_DSHIFT, COL_DRAGOFF);
2388     draw_lines_specific(dr, ds, x, y, lflags, DS_DSHIFT, COL_DRAGON);
2389
2390     /* Draw a clue, if present */
2391     if (clue != NOCLUE) {
2392         int c = (lflags & DS_FLASH) ? COL_FLASH :
2393                 (clue == STRAIGHT) ? COL_WHITE : COL_BLACK;
2394
2395         if (lflags & DS_ERROR_CLUE) /* draw a bigger 'error' clue circle. */
2396             draw_circle(dr, cx, cy, TILE_SIZE*3/8, COL_ERROR, COL_ERROR);
2397
2398         draw_circle(dr, cx, cy, TILE_SIZE/4, c, COL_BLACK);
2399     }
2400
2401     unclip(dr);
2402     draw_update(dr, ox, oy, TILE_SIZE, TILE_SIZE);
2403 }
2404
2405 static void game_redraw(drawing *dr, game_drawstate *ds,
2406                         const game_state *oldstate, const game_state *state,
2407                         int dir, const game_ui *ui,
2408                         float animtime, float flashtime)
2409 {
2410     int w = state->shared->w, h = state->shared->h, sz = state->shared->sz;
2411     int x, y, force = 0, flashing = 0;
2412
2413     if (!ds->started) {
2414         /*
2415          * The initial contents of the window are not guaranteed and
2416          * can vary with front ends. To be on the safe side, all games
2417          * should start by drawing a big background-colour rectangle
2418          * covering the whole window.
2419          */
2420         draw_rect(dr, 0, 0, w*TILE_SIZE + 2*BORDER, h*TILE_SIZE + 2*BORDER,
2421                   COL_BACKGROUND);
2422
2423         if (get_gui_style() == GUI_MASYU) {
2424             /*
2425              * Smaller black rectangle which is the main grid.
2426              */
2427             draw_rect(dr, BORDER - BORDER_WIDTH, BORDER - BORDER_WIDTH,
2428                       w*TILE_SIZE + 2*BORDER_WIDTH + 1,
2429                       h*TILE_SIZE + 2*BORDER_WIDTH + 1,
2430                       COL_GRID);
2431         }
2432
2433         draw_update(dr, 0, 0, w*TILE_SIZE + 2*BORDER, h*TILE_SIZE + 2*BORDER);
2434
2435         ds->started = TRUE;
2436         force = 1;
2437     }
2438
2439     if (flashtime > 0 &&
2440         (flashtime <= FLASH_TIME/3 ||
2441          flashtime >= FLASH_TIME*2/3))
2442         flashing = DS_FLASH;
2443
2444     memset(ds->draglines, 0, sz);
2445     if (ui->ndragcoords > 0) {
2446         int i, clearing = TRUE;
2447         for (i = 0; i < ui->ndragcoords - 1; i++) {
2448             int sx, sy, dx, dy, dir, oldstate, newstate;
2449             interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy,
2450                               &dir, &oldstate, &newstate);
2451             ds->draglines[sy*w+sx] ^= (oldstate ^ newstate);
2452             ds->draglines[dy*w+dx] ^= (F(oldstate) ^ F(newstate));
2453         }
2454     }   
2455
2456     for (x = 0; x < w; x++) {
2457         for (y = 0; y < h; y++) {
2458             unsigned int f = (unsigned int)state->lines[y*w+x];
2459             unsigned int eline = (unsigned int)(state->errors[y*w+x] & (R|U|L|D));
2460
2461             f |= eline << DS_ESHIFT;
2462             f |= ((unsigned int)ds->draglines[y*w+x]) << DS_DSHIFT;
2463             f |= ((unsigned int)state->marks[y*w+x]) << DS_MSHIFT;
2464
2465             if (state->errors[y*w+x] & ERROR_CLUE)
2466                 f |= DS_ERROR_CLUE;
2467
2468             f |= flashing;
2469
2470             if (ui->cursor_active && x == ui->curx && y == ui->cury)
2471                 f |= DS_CURSOR;
2472
2473             if (f != ds->lflags[y*w+x] || force) {
2474                 ds->lflags[y*w+x] = f;
2475                 draw_square(dr, ds, ui, x, y, f, state->shared->clues[y*w+x]);
2476             }
2477         }
2478     }
2479 }
2480
2481 static float game_anim_length(const game_state *oldstate,
2482                               const game_state *newstate, int dir, game_ui *ui)
2483 {
2484     return 0.0F;
2485 }
2486
2487 static float game_flash_length(const game_state *oldstate,
2488                                const game_state *newstate, int dir, game_ui *ui)
2489 {
2490     if (!oldstate->completed && newstate->completed &&
2491         !oldstate->used_solve && !newstate->used_solve)
2492         return FLASH_TIME;
2493     else
2494         return 0.0F;
2495 }
2496
2497 static int game_status(const game_state *state)
2498 {
2499     return state->completed ? +1 : 0;
2500 }
2501
2502 static int game_timing_state(const game_state *state, game_ui *ui)
2503 {
2504     return TRUE;
2505 }
2506
2507 static void game_print_size(const game_params *params, float *x, float *y)
2508 {
2509     int pw, ph;
2510
2511     /*
2512      * I'll use 6mm squares by default.
2513      */
2514     game_compute_size(params, 600, &pw, &ph);
2515     *x = pw / 100.0F;
2516     *y = ph / 100.0F;
2517 }
2518
2519 static void game_print(drawing *dr, const game_state *state, int tilesize)
2520 {
2521     int w = state->shared->w, h = state->shared->h, x, y;
2522     int black = print_mono_colour(dr, 0);
2523     int white = print_mono_colour(dr, 1);
2524
2525     /* No GUI_LOOPY here: only use the familiar masyu style. */
2526
2527     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2528     game_drawstate *ds = game_new_drawstate(dr, state);
2529     game_set_size(dr, ds, NULL, tilesize);
2530
2531     /* Draw grid outlines (black). */
2532     for (x = 0; x <= w; x++)
2533         draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), black);
2534     for (y = 0; y <= h; y++)
2535         draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), black);
2536
2537     for (x = 0; x < w; x++) {
2538         for (y = 0; y < h; y++) {
2539             int cx = COORD(x) + HALFSZ, cy = COORD(y) + HALFSZ;
2540             int clue = state->shared->clues[y*w+x];
2541
2542             draw_lines_specific(dr, ds, x, y, state->lines[y*w+x], 0, black);
2543
2544             if (clue != NOCLUE) {
2545                 int c = (clue == CORNER) ? black : white;
2546                 draw_circle(dr, cx, cy, TILE_SIZE/4, c, black);
2547             }
2548         }
2549     }
2550
2551     game_free_drawstate(dr, ds);
2552 }
2553
2554 #ifdef COMBINED
2555 #define thegame pearl
2556 #endif
2557
2558 const struct game thegame = {
2559     "Pearl", "games.pearl", "pearl",
2560     default_params,
2561     game_fetch_preset,
2562     decode_params,
2563     encode_params,
2564     free_params,
2565     dup_params,
2566     TRUE, game_configure, custom_params,
2567     validate_params,
2568     new_game_desc,
2569     validate_desc,
2570     new_game,
2571     dup_game,
2572     free_game,
2573     TRUE, solve_game,
2574     TRUE, game_can_format_as_text_now, game_text_format,
2575     new_ui,
2576     free_ui,
2577     encode_ui,
2578     decode_ui,
2579     game_changed_state,
2580     interpret_move,
2581     execute_move,
2582     PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
2583     game_colours,
2584     game_new_drawstate,
2585     game_free_drawstate,
2586     game_redraw,
2587     game_anim_length,
2588     game_flash_length,
2589     game_status,
2590     TRUE, FALSE, game_print_size, game_print,
2591     FALSE,                             /* wants_statusbar */
2592     FALSE, game_timing_state,
2593     0,                                 /* flags */
2594 };
2595
2596 #ifdef STANDALONE_SOLVER
2597
2598 #include <time.h>
2599 #include <stdarg.h>
2600
2601 const char *quis = NULL;
2602
2603 static void usage(FILE *out) {
2604     fprintf(out, "usage: %s <params>\n", quis);
2605 }
2606
2607 static void pnum(int n, int ntot, const char *desc)
2608 {
2609     printf("%2.1f%% (%d) %s", (double)n*100.0 / (double)ntot, n, desc);
2610 }
2611
2612 static void start_soak(game_params *p, random_state *rs, int nsecs)
2613 {
2614     time_t tt_start, tt_now, tt_last;
2615     int n = 0, nsolved = 0, nimpossible = 0, ret;
2616     char *grid, *clues;
2617
2618     tt_start = tt_last = time(NULL);
2619
2620     /* Currently this generates puzzles of any difficulty (trying to solve it
2621      * on the maximum difficulty level and not checking it's not too easy). */
2622     printf("Soak-testing a %dx%d grid (any difficulty)", p->w, p->h);
2623     if (nsecs > 0) printf(" for %d seconds", nsecs);
2624     printf(".\n");
2625
2626     p->nosolve = TRUE;
2627
2628     grid = snewn(p->w*p->h, char);
2629     clues = snewn(p->w*p->h, char);
2630
2631     while (1) {
2632         n += new_clues(p, rs, clues, grid); /* should be 1, with nosolve */
2633
2634         ret = pearl_solve(p->w, p->h, clues, grid, DIFF_TRICKY, FALSE);
2635         if (ret <= 0) nimpossible++;
2636         if (ret == 1) nsolved++;
2637
2638         tt_now = time(NULL);
2639         if (tt_now > tt_last) {
2640             tt_last = tt_now;
2641
2642             printf("%d total, %3.1f/s, ",
2643                    n, (double)n / ((double)tt_now - tt_start));
2644             pnum(nsolved, n, "solved"); printf(", ");
2645             printf("%3.1f/s", (double)nsolved / ((double)tt_now - tt_start));
2646             if (nimpossible > 0)
2647                 pnum(nimpossible, n, "impossible");
2648             printf("\n");
2649         }
2650         if (nsecs > 0 && (tt_now - tt_start) > nsecs) {
2651             printf("\n");
2652             break;
2653         }
2654     }
2655
2656     sfree(grid);
2657     sfree(clues);
2658 }
2659
2660 int main(int argc, const char *argv[])
2661 {
2662     game_params *p = NULL;
2663     random_state *rs = NULL;
2664     time_t seed = time(NULL);
2665     char *id = NULL, *err;
2666
2667     setvbuf(stdout, NULL, _IONBF, 0);
2668
2669     quis = argv[0];
2670
2671     while (--argc > 0) {
2672         char *p = (char*)(*++argv);
2673         if (!strcmp(p, "-e") || !strcmp(p, "--seed")) {
2674             seed = atoi(*++argv);
2675             argc--;
2676         } else if (*p == '-') {
2677             fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
2678             usage(stderr);
2679             exit(1);
2680         } else {
2681             id = p;
2682         }
2683     }
2684
2685     rs = random_new((void*)&seed, sizeof(time_t));
2686     p = default_params();
2687
2688     if (id) {
2689         if (strchr(id, ':')) {
2690             fprintf(stderr, "soak takes params only.\n");
2691             goto done;
2692         }
2693
2694         decode_params(p, id);
2695         err = validate_params(p, 1);
2696         if (err) {
2697             fprintf(stderr, "%s: %s", argv[0], err);
2698             goto done;
2699         }
2700
2701         start_soak(p, rs, 0); /* run forever */
2702     } else {
2703         int i;
2704
2705         for (i = 5; i <= 12; i++) {
2706             p->w = p->h = i;
2707             start_soak(p, rs, 5);
2708         }
2709     }
2710
2711 done:
2712     free_params(p);
2713     random_free(rs);
2714
2715     return 0;
2716 }
2717
2718 #endif
2719
2720 /* vim: set shiftwidth=4 tabstop=8: */