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