chiark / gitweb /
037547e2260b06332312f0455aa2ae0c235704ba
[sgt-puzzles.git] / unfinished / group.c
1 /*
2  * group.c: a Latin-square puzzle, but played with groups' Cayley
3  * tables. That is, you are given a Cayley table of a group with
4  * most elements blank and a few clues, and you must fill it in
5  * so as to preserve the group axioms.
6  *
7  * This is a perfectly playable and fully working puzzle, but I'm
8  * leaving it for the moment in the 'unfinished' directory because
9  * it's just too esoteric (not to mention _hard_) for me to be
10  * comfortable presenting it to the general public as something they
11  * might (implicitly) actually want to play.
12  *
13  * TODO:
14  *
15  *  - more solver techniques?
16  *     * Inverses: once we know that gh = e, we can immediately
17  *       deduce hg = e as well; then for any gx=y we can deduce
18  *       hy=x, and for any xg=y we have yh=x.
19  *     * Hard-mode associativity: we currently deduce based on
20  *       definite numbers in the grid, but we could also winnow
21  *       based on _possible_ numbers.
22  *     * My overambitious original thoughts included wondering if we
23  *       could infer that there must be elements of certain orders
24  *       (e.g. a group of order divisible by 5 must contain an
25  *       element of order 5), but I think in fact this is probably
26  *       silly.
27  */
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <ctype.h>
34 #include <math.h>
35
36 #include "puzzles.h"
37 #include "latin.h"
38
39 /*
40  * Difficulty levels. I do some macro ickery here to ensure that my
41  * enum and the various forms of my name list always match up.
42  */
43 #define DIFFLIST(A) \
44     A(TRIVIAL,Trivial,NULL,t) \
45     A(NORMAL,Normal,solver_normal,n) \
46     A(HARD,Hard,NULL,h) \
47     A(EXTREME,Extreme,NULL,x) \
48     A(UNREASONABLE,Unreasonable,NULL,u)
49 #define ENUM(upper,title,func,lower) DIFF_ ## upper,
50 #define TITLE(upper,title,func,lower) #title,
51 #define ENCODE(upper,title,func,lower) #lower
52 #define CONFIG(upper,title,func,lower) ":" #title
53 enum { DIFFLIST(ENUM) DIFFCOUNT };
54 static char const *const group_diffnames[] = { DIFFLIST(TITLE) };
55 static char const group_diffchars[] = DIFFLIST(ENCODE);
56 #define DIFFCONFIG DIFFLIST(CONFIG)
57
58 enum {
59     COL_BACKGROUND,
60     COL_GRID,
61     COL_USER,
62     COL_HIGHLIGHT,
63     COL_ERROR,
64     COL_PENCIL,
65     NCOLOURS
66 };
67
68 /*
69  * In identity mode, we number the elements e,a,b,c,d,f,g,h,...
70  * Otherwise, they're a,b,c,d,e,f,g,h,... in the obvious way.
71  */
72 #define E_TO_FRONT(c,id) ( (id) && (c)<=5 ? (c) % 5 + 1 : (c) )
73 #define E_FROM_FRONT(c,id) ( (id) && (c)<=5 ? ((c) + 3) % 5 + 1 : (c) )
74
75 #define FROMCHAR(c,id) E_TO_FRONT((((c)-('A'-1)) & ~0x20), id)
76 #define ISCHAR(c) (((c)>='A'&&(c)<='Z') || ((c)>='a'&&(c)<='z'))
77 #define TOCHAR(c,id) (E_FROM_FRONT(c,id) + ('a'-1))
78
79 struct game_params {
80     int w, diff, id;
81 };
82
83 struct game_state {
84     game_params par;
85     digit *grid;
86     unsigned char *immutable;
87     int *pencil;                       /* bitmaps using bits 1<<1..1<<n */
88     int completed, cheated;
89     digit *sequence;                   /* sequence of group elements shown */
90 };
91
92 static game_params *default_params(void)
93 {
94     game_params *ret = snew(game_params);
95
96     ret->w = 6;
97     ret->diff = DIFF_NORMAL;
98     ret->id = TRUE;
99
100     return ret;
101 }
102
103 const static struct game_params group_presets[] = {
104     {  6, DIFF_NORMAL, TRUE },
105     {  6, DIFF_NORMAL, FALSE },
106     {  8, DIFF_NORMAL, TRUE },
107     {  8, DIFF_NORMAL, FALSE },
108     {  8, DIFF_HARD, TRUE },
109     {  8, DIFF_HARD, FALSE },
110     { 12, DIFF_NORMAL, TRUE },
111 };
112
113 static int game_fetch_preset(int i, char **name, game_params **params)
114 {
115     game_params *ret;
116     char buf[80];
117
118     if (i < 0 || i >= lenof(group_presets))
119         return FALSE;
120
121     ret = snew(game_params);
122     *ret = group_presets[i]; /* structure copy */
123
124     sprintf(buf, "%dx%d %s%s", ret->w, ret->w, group_diffnames[ret->diff],
125             ret->id ? "" : ", identity hidden");
126
127     *name = dupstr(buf);
128     *params = ret;
129     return TRUE;
130 }
131
132 static void free_params(game_params *params)
133 {
134     sfree(params);
135 }
136
137 static game_params *dup_params(game_params *params)
138 {
139     game_params *ret = snew(game_params);
140     *ret = *params;                    /* structure copy */
141     return ret;
142 }
143
144 static void decode_params(game_params *params, char const *string)
145 {
146     char const *p = string;
147
148     params->w = atoi(p);
149     while (*p && isdigit((unsigned char)*p)) p++;
150     params->diff = DIFF_NORMAL;
151     params->id = TRUE;
152
153     while (*p) {
154         if (*p == 'd') {
155             int i;
156             p++;
157             params->diff = DIFFCOUNT+1; /* ...which is invalid */
158             if (*p) {
159                 for (i = 0; i < DIFFCOUNT; i++) {
160                     if (*p == group_diffchars[i])
161                         params->diff = i;
162                 }
163                 p++;
164             }
165         } else if (*p == 'i') {
166             params->id = FALSE;
167             p++;
168         } else {
169             /* unrecognised character */
170             p++;
171         }
172     }
173 }
174
175 static char *encode_params(game_params *params, int full)
176 {
177     char ret[80];
178
179     sprintf(ret, "%d", params->w);
180     if (full)
181         sprintf(ret + strlen(ret), "d%c", group_diffchars[params->diff]);
182     if (!params->id)
183         sprintf(ret + strlen(ret), "i");
184
185     return dupstr(ret);
186 }
187
188 static config_item *game_configure(game_params *params)
189 {
190     config_item *ret;
191     char buf[80];
192
193     ret = snewn(4, config_item);
194
195     ret[0].name = "Grid size";
196     ret[0].type = C_STRING;
197     sprintf(buf, "%d", params->w);
198     ret[0].sval = dupstr(buf);
199     ret[0].ival = 0;
200
201     ret[1].name = "Difficulty";
202     ret[1].type = C_CHOICES;
203     ret[1].sval = DIFFCONFIG;
204     ret[1].ival = params->diff;
205
206     ret[2].name = "Show identity";
207     ret[2].type = C_BOOLEAN;
208     ret[2].sval = NULL;
209     ret[2].ival = params->id;
210
211     ret[3].name = NULL;
212     ret[3].type = C_END;
213     ret[3].sval = NULL;
214     ret[3].ival = 0;
215
216     return ret;
217 }
218
219 static game_params *custom_params(config_item *cfg)
220 {
221     game_params *ret = snew(game_params);
222
223     ret->w = atoi(cfg[0].sval);
224     ret->diff = cfg[1].ival;
225     ret->id = cfg[2].ival;
226
227     return ret;
228 }
229
230 static char *validate_params(game_params *params, int full)
231 {
232     if (params->w < 3 || params->w > 26)
233         return "Grid size must be between 3 and 26";
234     if (params->diff >= DIFFCOUNT)
235         return "Unknown difficulty rating";
236     if (!params->id && params->diff == DIFF_TRIVIAL) {
237         /*
238          * We can't have a Trivial-difficulty puzzle (i.e. latin
239          * square deductions only) without a clear identity, because
240          * identityless puzzles always have two rows and two columns
241          * entirely blank, and no latin-square deduction permits the
242          * distinguishing of two such rows.
243          */
244         return "Trivial puzzles must have an identity";
245     }
246     if (!params->id && params->w == 3) {
247         /*
248          * We can't have a 3x3 puzzle without an identity either,
249          * because 3x3 puzzles can't ever be harder than Trivial
250          * (there are no 3x3 latin squares which aren't also valid
251          * group tables, so enabling group-based deductions doesn't
252          * rule out any possible solutions) and - as above - Trivial
253          * puzzles can't not have an identity.
254          */
255         return "3x3 puzzles must have an identity";
256     }
257     return NULL;
258 }
259
260 /* ----------------------------------------------------------------------
261  * Solver.
262  */
263
264 static int solver_normal(struct latin_solver *solver, void *vctx)
265 {
266     int w = solver->o;
267 #ifdef STANDALONE_SOLVER
268     char **names = solver->names;
269 #endif
270     digit *grid = solver->grid;
271     int i, j, k;
272
273     /*
274      * Deduce using associativity: (ab)c = a(bc).
275      *
276      * So we pick any a,b,c we like; then if we know ab, bc, and
277      * (ab)c we can fill in a(bc).
278      */
279     for (i = 1; i < w; i++)
280         for (j = 1; j < w; j++)
281             for (k = 1; k < w; k++) {
282                 if (!grid[i*w+j] || !grid[j*w+k])
283                     continue;
284                 if (grid[(grid[i*w+j]-1)*w+k] &&
285                     !grid[i*w+(grid[j*w+k]-1)]) {
286                     int x = grid[j*w+k]-1, y = i;
287                     int n = grid[(grid[i*w+j]-1)*w+k];
288 #ifdef STANDALONE_SOLVER
289                     if (solver_show_working) {
290                         printf("%*sassociativity on %s,%s,%s: %s*%s = %s*%s\n",
291                                solver_recurse_depth*4, "",
292                                names[i], names[j], names[k],
293                                names[grid[i*w+j]-1], names[k],
294                                names[i], names[grid[j*w+k]-1]);
295                         printf("%*s  placing %s at (%d,%d)\n",
296                                solver_recurse_depth*4, "",
297                                names[n-1], x+1, y+1);
298                     }
299 #endif
300                     if (solver->cube[(x*w+y)*w+n-1]) {
301                         latin_solver_place(solver, x, y, n);
302                         return 1;
303                     } else {
304 #ifdef STANDALONE_SOLVER
305                         if (solver_show_working)
306                             printf("%*s  contradiction!\n",
307                                    solver_recurse_depth*4, "");
308                         return -1;
309 #endif
310                     }
311                 }
312                 if (!grid[(grid[i*w+j]-1)*w+k] &&
313                     grid[i*w+(grid[j*w+k]-1)]) {
314                     int x = k, y = grid[i*w+j]-1;
315                     int n = grid[i*w+(grid[j*w+k]-1)];
316 #ifdef STANDALONE_SOLVER
317                     if (solver_show_working) {
318                         printf("%*sassociativity on %s,%s,%s: %s*%s = %s*%s\n",
319                                solver_recurse_depth*4, "",
320                                names[i], names[j], names[k],
321                                names[grid[i*w+j]-1], names[k],
322                                names[i], names[grid[j*w+k]-1]);
323                         printf("%*s  placing %s at (%d,%d)\n",
324                                solver_recurse_depth*4, "",
325                                names[n-1], x+1, y+1);
326                     }
327 #endif
328                     if (solver->cube[(x*w+y)*w+n-1]) {
329                         latin_solver_place(solver, x, y, n);
330                         return 1;
331                     } else {
332 #ifdef STANDALONE_SOLVER
333                         if (solver_show_working)
334                             printf("%*s  contradiction!\n",
335                                    solver_recurse_depth*4, "");
336                         return -1;
337 #endif
338                     }
339                 }
340             }
341
342     return 0;
343 }
344
345 #define SOLVER(upper,title,func,lower) func,
346 static usersolver_t const group_solvers[] = { DIFFLIST(SOLVER) };
347
348 static int solver(game_params *params, digit *grid, int maxdiff)
349 {
350     int w = params->w;
351     int ret;
352     struct latin_solver solver;
353 #ifdef STANDALONE_SOLVER
354     char *p, text[100], *names[50];
355     int i;
356 #endif
357
358     latin_solver_alloc(&solver, grid, w);
359 #ifdef STANDALONE_SOLVER
360     for (i = 0, p = text; i < w; i++) {
361         names[i] = p;
362         *p++ = TOCHAR(i+1, params->id);
363         *p++ = '\0';
364     }
365     solver.names = names;
366 #endif
367
368     ret = latin_solver_main(&solver, maxdiff,
369                             DIFF_TRIVIAL, DIFF_HARD, DIFF_EXTREME,
370                             DIFF_EXTREME, DIFF_UNREASONABLE,
371                             group_solvers, NULL, NULL, NULL);
372
373     latin_solver_free(&solver);
374
375     return ret;
376 }
377
378 /* ----------------------------------------------------------------------
379  * Grid generation.
380  */
381
382 static char *encode_grid(char *desc, digit *grid, int area)
383 {
384     int run, i;
385     char *p = desc;
386
387     run = 0;
388     for (i = 0; i <= area; i++) {
389         int n = (i < area ? grid[i] : -1);
390
391         if (!n)
392             run++;
393         else {
394             if (run) {
395                 while (run > 0) {
396                     int c = 'a' - 1 + run;
397                     if (run > 26)
398                         c = 'z';
399                     *p++ = c;
400                     run -= c - ('a' - 1);
401                 }
402             } else {
403                 /*
404                  * If there's a number in the very top left or
405                  * bottom right, there's no point putting an
406                  * unnecessary _ before or after it.
407                  */
408                 if (p > desc && n > 0)
409                     *p++ = '_';
410             }
411             if (n > 0)
412                 p += sprintf(p, "%d", n);
413             run = 0;
414         }
415     }
416     return p;
417 }
418
419 /* ----- data generated by group.gap begins ----- */
420
421 struct group {
422     unsigned long autosize;
423     int order, ngens;
424     const char *gens;
425 };
426 struct groups {
427     int ngroups;
428     const struct group *groups;
429 };
430
431 static const struct group groupdata[] = {
432     /* order 2 */
433     {1L, 2, 1, "BA"},
434     /* order 3 */
435     {2L, 3, 1, "BCA"},
436     /* order 4 */
437     {2L, 4, 1, "BCDA"},
438     {6L, 4, 2, "BADC" "CDAB"},
439     /* order 5 */
440     {4L, 5, 1, "BCDEA"},
441     /* order 6 */
442     {6L, 6, 2, "CFEBAD" "BADCFE"},
443     {2L, 6, 1, "DCFEBA"},
444     /* order 7 */
445     {6L, 7, 1, "BCDEFGA"},
446     /* order 8 */
447     {4L, 8, 1, "BCEFDGHA"},
448     {8L, 8, 2, "BDEFGAHC" "EGBHDCFA"},
449     {8L, 8, 2, "EGBHDCFA" "BAEFCDHG"},
450     {24L, 8, 2, "BDEFGAHC" "CHDGBEAF"},
451     {168L, 8, 3, "BAEFCDHG" "CEAGBHDF" "DFGAHBCE"},
452     /* order 9 */
453     {6L, 9, 1, "BDECGHFIA"},
454     {48L, 9, 2, "BDEAGHCIF" "CEFGHAIBD"},
455     /* order 10 */
456     {20L, 10, 2, "CJEBGDIFAH" "BADCFEHGJI"},
457     {4L, 10, 1, "DCFEHGJIBA"},
458     /* order 11 */
459     {10L, 11, 1, "BCDEFGHIJKA"},
460     /* order 12 */
461     {12L, 12, 2, "GLDKJEHCBIAF" "BCEFAGIJDKLH"},
462     {4L, 12, 1, "EHIJKCBLDGFA"},
463     {24L, 12, 2, "BEFGAIJKCDLH" "FJBKHLEGDCIA"},
464     {12L, 12, 2, "GLDKJEHCBIAF" "BAEFCDIJGHLK"},
465     {12L, 12, 2, "FDIJGHLBKAEC" "GIDKFLHCJEAB"},
466     /* order 13 */
467     {12L, 13, 1, "BCDEFGHIJKLMA"},
468     /* order 14 */
469     {42L, 14, 2, "ELGNIBKDMFAHCJ" "BADCFEHGJILKNM"},
470     {6L, 14, 1, "FEHGJILKNMBADC"},
471     /* order 15 */
472     {8L, 15, 1, "EGHCJKFMNIOBLDA"},
473     /* order 16 */
474     {8L, 16, 1, "MKNPFOADBGLCIEHJ"},
475     {96L, 16, 2, "ILKCONFPEDJHGMAB" "BDFGHIAKLMNCOEPJ"},
476     {32L, 16, 2, "MIHPFDCONBLAKJGE" "BEFGHJKALMNOCDPI"},
477     {32L, 16, 2, "IFACOGLMDEJBNPKH" "BEFGHJKALMNOCDPI"},
478     {16L, 16, 2, "MOHPFKCINBLADJGE" "BDFGHIEKLMNJOAPC"},
479     {16L, 16, 2, "MIHPFDJONBLEKCGA" "BDFGHIEKLMNJOAPC"},
480     {32L, 16, 2, "MOHPFDCINBLEKJGA" "BAFGHCDELMNIJKPO"},
481     {16L, 16, 2, "MIHPFKJONBLADCGE" "GDPHNOEKFLBCIAMJ"},
482     {32L, 16, 2, "MIBPFDJOGHLEKCNA" "CLEIJGMPKAOHNFDB"},
483     {192L, 16, 3,
484      "MCHPFAIJNBLDEOGK" "BEFGHJKALMNOCDPI" "GKLBNOEDFPHJIAMC"},
485     {64L, 16, 3, "MCHPFAIJNBLDEOGK" "LOGFPKJIBNMEDCHA" "CMAIJHPFDEONBLKG"},
486     {192L, 16, 3,
487      "IPKCOGMLEDJBNFAH" "BEFGHJKALMNOCDPI" "CMEIJBPFKAOGHLDN"},
488     {48L, 16, 3, "IPDJONFLEKCBGMAH" "FJBLMEOCGHPKAIND" "DGIEKLHNJOAMPBCF"},
489     {20160L, 16, 4,
490      "EHJKAMNBOCDPFGIL" "BAFGHCDELMNIJKPO" "CFAIJBLMDEOGHPKN"
491      "DGIAKLBNCOEFPHJM"},
492     /* order 17 */
493     {16L, 17, 1, "EFGHIJKLMNOPQABCD"},
494     /* order 18 */
495     {54L, 18, 2, "MKIQOPNAGLRECDBJHF" "BAEFCDJKLGHIOPMNRQ"},
496     {6L, 18, 1, "ECJKGHFOPDMNLRIQBA"},
497     {12L, 18, 2, "ECJKGHBOPAMNFRDQLI" "KNOPQCFREIGHLJAMBD"},
498     {432L, 18, 3,
499      "IFNAKLQCDOPBGHREMJ" "NOQCFRIGHKLJAMPBDE" "BAEFCDJKLGHIOPMNRQ"},
500     {48L, 18, 2, "ECJKGHBOPAMNFRDQLI" "FDKLHIOPBMNAREQCJG"},
501     /* order 19 */
502     {18L, 19, 1, "EFGHIJKLMNOPQRSABCD"},
503     /* order 20 */
504     {40L, 20, 2, "GTDKREHOBILSFMPCJQAN" "EABICDFMGHJQKLNTOPRS"},
505     {8L, 20, 1, "EHIJLCMNPGQRSKBTDOFA"},
506     {20L, 20, 2, "DJSHQNCLTRGPEBKAIFOM" "EABICDFMGHJQKLNTOPRS"},
507     {40L, 20, 2, "GTDKREHOBILSFMPCJQAN" "ECBIAGFMDKJQHONTLSRP"},
508     {24L, 20, 2, "IGFMDKJQHONTLSREPCBA" "FDIJGHMNKLQROPTBSAEC"},
509     /* order 21 */
510     {42L, 21, 2, "ITLSBOUERDHAGKCJNFMQP" "EJHLMKOPNRSQAUTCDBFGI"},
511     {12L, 21, 1, "EGHCJKFMNIPQLSTOUBRDA"},
512     /* order 22 */
513     {110L, 22, 2, "ETGVIBKDMFOHQJSLUNAPCR" "BADCFEHGJILKNMPORQTSVU"},
514     {10L, 22, 1, "FEHGJILKNMPORQTSVUBADC"},
515     /* order 23 */
516     {22L, 23, 1, "EFGHIJKLMNOPQRSTUVWABCD"},
517     /* order 24 */
518     {24L, 24, 2, "QXEJWPUMKLRIVBFTSACGHNDO" "HRNOPSWCTUVBLDIJXFGAKQME"},
519     {8L, 24, 1, "MQBTUDRWFGHXJELINOPKSAVC"},
520     {24L, 24, 2, "IOQRBEUVFWGHKLAXMNPSCDTJ" "NJXOVGDKSMTFIPQELCURBWAH"},
521     {48L, 24, 2, "QUEJWVXFKLRIPGMNSACBOTDH" "HSNOPWLDTUVBRIAKXFGCQEMJ"},
522     {24L, 24, 2, "QXEJWPUMKLRIVBFTSACGHNDO" "TWHNXLRIOPUMSACQVBFDEJGK"},
523     {48L, 24, 2, "QUEJWVXFKLRIPGMNSACBOTDH" "BAFGHCDEMNOPIJKLTUVQRSXW"},
524     {48L, 24, 3,
525      "QXKJWVUMESRIPGFTLDCBONAH" "JUEQRPXFKLWCVBMNSAIGHTDO"
526      "HSNOPWLDTUVBRIAKXFGCQEMJ"},
527     {24L, 24, 3,
528      "QUKJWPXFESRIVBMNLDCGHTAO" "JXEQRVUMKLWCPGFTSAIBONDH"
529      "TRONXLWCHVUMSAIJPGFDEQBK"},
530     {16L, 24, 2, "MRGTULWIOPFXSDJQBVNEKCHA" "VKXHOQASNTPBCWDEUFGIJLMR"},
531     {16L, 24, 2, "MRGTULWIOPFXSDJQBVNEKCHA" "RMLWIGTUSDJQOPFXEKCBVNAH"},
532     {48L, 24, 2, "IULQRGXMSDCWOPNTEKJBVFAH" "GLMOPRSDTUBVWIEKFXHJQANC"},
533     {24L, 24, 2, "UJPXMRCSNHGTLWIKFVBEDQOA" "NRUFVLWIPXMOJEDQHGTCSABK"},
534     {24L, 24, 2, "MIBTUAQRFGHXCDEWNOPJKLVS" "OKXVFWSCGUTNDRQJBPMALIHE"},
535     {144L, 24, 3,
536      "QXKJWVUMESRIPGFTLDCBONAH" "JUEQRPXFKLWCVBMNSAIGHTDO"
537      "BAFGHCDEMNOPIJKLTUVQRSXW"},
538     {336L, 24, 3,
539      "QTKJWONXESRIHVUMLDCPGFAB" "JNEQRHTUKLWCOPXFSAIVBMDG"
540      "HENOPJKLTUVBQRSAXFGWCDMI"},
541     /* order 25 */
542     {20L, 25, 1, "EHILMNPQRSFTUVBJWXDOYGAKC"},
543     {480L, 25, 2, "EHILMNPQRSCTUVBFWXDJYGOKA" "BDEGHIKLMNAPQRSCTUVFWXJYO"},
544     /* order 26 */
545     {156L, 26, 2,
546      "EXGZIBKDMFOHQJSLUNWPYRATCV" "BADCFEHGJILKNMPORQTSVUXWZY"},
547     {12L, 26, 1, "FEHGJILKNMPORQTSVUXWZYBADC"},
548 };
549
550 static const struct groups groups[] = {
551     {0, NULL},                  /* trivial case: 0 */
552     {0, NULL},                  /* trivial case: 1 */
553     {1, groupdata + 0},         /* 2 */
554     {1, groupdata + 1},         /* 3 */
555     {2, groupdata + 2},         /* 4 */
556     {1, groupdata + 4},         /* 5 */
557     {2, groupdata + 5},         /* 6 */
558     {1, groupdata + 7},         /* 7 */
559     {5, groupdata + 8},         /* 8 */
560     {2, groupdata + 13},        /* 9 */
561     {2, groupdata + 15},        /* 10 */
562     {1, groupdata + 17},        /* 11 */
563     {5, groupdata + 18},        /* 12 */
564     {1, groupdata + 23},        /* 13 */
565     {2, groupdata + 24},        /* 14 */
566     {1, groupdata + 26},        /* 15 */
567     {14, groupdata + 27},       /* 16 */
568     {1, groupdata + 41},        /* 17 */
569     {5, groupdata + 42},        /* 18 */
570     {1, groupdata + 47},        /* 19 */
571     {5, groupdata + 48},        /* 20 */
572     {2, groupdata + 53},        /* 21 */
573     {2, groupdata + 55},        /* 22 */
574     {1, groupdata + 57},        /* 23 */
575     {15, groupdata + 58},       /* 24 */
576     {2, groupdata + 73},        /* 25 */
577     {2, groupdata + 75},        /* 26 */
578 };
579
580 /* ----- data generated by group.gap ends ----- */
581
582 static char *new_game_desc(game_params *params, random_state *rs,
583                            char **aux, int interactive)
584 {
585     int w = params->w, a = w*w;
586     digit *grid, *soln, *soln2;
587     int *indices;
588     int i, j, k, qh, qt;
589     int diff = params->diff;
590     const struct group *group;
591     char *desc, *p;
592
593     /*
594      * Difficulty exceptions: some combinations of size and
595      * difficulty cannot be satisfied, because all puzzles of at
596      * most that difficulty are actually even easier.
597      *
598      * Remember to re-test this whenever a change is made to the
599      * solver logic!
600      *
601      * I tested it using the following shell command:
602
603 for d in t n h x u; do
604   for id in '' i; do
605     for i in {3..9}; do
606       echo -n "./group --generate 1 ${i}d${d}${id}: "
607       perl -e 'alarm 30; exec @ARGV' \
608         ./group --generate 1 ${i}d${d}${id} >/dev/null && echo ok
609     done
610   done
611 done
612
613      * Of course, it's better to do that after taking the exceptions
614      * _out_, so as to detect exceptions that should be removed as
615      * well as those which should be added.
616      */
617     if (w < 5 && diff == DIFF_UNREASONABLE)
618         diff--;
619     if ((w < 5 || ((w == 6 || w == 8) && params->id)) && diff == DIFF_EXTREME)
620         diff--;
621     if ((w < 6 || (w == 6 && params->id)) && diff == DIFF_HARD)
622         diff--;
623     if ((w < 4 || (w == 4 && params->id)) && diff == DIFF_NORMAL)
624         diff--;
625
626     grid = snewn(a, digit);
627     soln = snewn(a, digit);
628     soln2 = snewn(a, digit);
629     indices = snewn(a, int);
630
631     while (1) {
632         /*
633          * Construct a valid group table, by picking a group from
634          * the above data table, decompressing it into a full
635          * representation by BFS, and then randomly permuting its
636          * non-identity elements.
637          *
638          * We build the canonical table in 'soln' (and use 'grid' as
639          * our BFS queue), then transfer the table into 'grid'
640          * having shuffled the rows.
641          */
642         assert(w >= 2);
643         assert(w < lenof(groups));
644         group = groups[w].groups + random_upto(rs, groups[w].ngroups);
645         assert(group->order == w);
646         memset(soln, 0, a);
647         for (i = 0; i < w; i++)
648             soln[i] = i+1;
649         qh = qt = 0;
650         grid[qt++] = 1;
651         while (qh < qt) {
652             digit *row, *newrow;
653
654             i = grid[qh++];
655             row = soln + (i-1)*w;
656
657             for (j = 0; j < group->ngens; j++) {
658                 int nri;
659                 const char *gen = group->gens + j*w;
660
661                 /*
662                  * Apply each group generator to row, constructing a
663                  * new row.
664                  */
665                 nri = gen[row[0]-1] - 'A' + 1;   /* which row is it? */
666                 newrow = soln + (nri-1)*w;
667                 if (!newrow[0]) {   /* not done yet */
668                     for (k = 0; k < w; k++)
669                         newrow[k] = gen[row[k]-1] - 'A' + 1;
670                     grid[qt++] = nri;
671                 }
672             }
673         }
674         /* That's got the canonical table. Now shuffle it. */
675         for (i = 0; i < w; i++)
676             soln2[i] = i;
677         if (params->id)                /* do we shuffle in the identity? */
678             shuffle(soln2+1, w-1, sizeof(*soln2), rs);
679         else
680             shuffle(soln2, w, sizeof(*soln2), rs);
681         for (i = 0; i < w; i++)
682             for (j = 0; j < w; j++)
683                 grid[(soln2[i])*w+(soln2[j])] = soln2[soln[i*w+j]-1]+1;
684
685         /*
686          * Remove entries one by one while the puzzle is still
687          * soluble at the appropriate difficulty level.
688          */
689         memcpy(soln, grid, a);
690         if (!params->id) {
691             /*
692              * Start by blanking the entire identity row and column,
693              * and also another row and column so that the player
694              * can't trivially determine which element is the
695              * identity.
696              */
697
698             j = 1 + random_upto(rs, w-1);  /* pick a second row/col to blank */
699             for (i = 0; i < w; i++) {
700                 grid[(soln2[0])*w+i] = grid[i*w+(soln2[0])] = 0;
701                 grid[(soln2[j])*w+i] = grid[i*w+(soln2[j])] = 0;
702             }
703
704             memcpy(soln2, grid, a);
705             if (solver(params, soln2, diff) > diff)
706                 continue;              /* go round again if that didn't work */
707         }
708
709         k = 0;
710         for (i = (params->id ? 1 : 0); i < w; i++)
711             for (j = (params->id ? 1 : 0); j < w; j++)
712                 if (grid[i*w+j])
713                     indices[k++] = i*w+j;
714         shuffle(indices, k, sizeof(*indices), rs);
715
716         for (i = 0; i < k; i++) {
717             memcpy(soln2, grid, a);
718             soln2[indices[i]] = 0;
719             if (solver(params, soln2, diff) <= diff)
720                 grid[indices[i]] = 0;
721         }
722
723         /*
724          * Make sure the puzzle isn't too easy.
725          */
726         if (diff > 0) {
727             memcpy(soln2, grid, a);
728             if (solver(params, soln2, diff-1) < diff)
729                 continue;              /* go round and try again */
730         }
731
732         /*
733          * Done.
734          */
735         break;
736     }
737
738     /*
739      * Encode the puzzle description.
740      */
741     desc = snewn(a*20, char);
742     p = encode_grid(desc, grid, a);
743     *p++ = '\0';
744     desc = sresize(desc, p - desc, char);
745
746     /*
747      * Encode the solution.
748      */
749     *aux = snewn(a+2, char);
750     (*aux)[0] = 'S';
751     for (i = 0; i < a; i++)
752         (*aux)[i+1] = TOCHAR(soln[i], params->id);
753     (*aux)[a+1] = '\0';
754
755     sfree(grid);
756     sfree(soln);
757     sfree(soln2);
758     sfree(indices);
759
760     return desc;
761 }
762
763 /* ----------------------------------------------------------------------
764  * Gameplay.
765  */
766
767 static char *validate_grid_desc(const char **pdesc, int range, int area)
768 {
769     const char *desc = *pdesc;
770     int squares = 0;
771     while (*desc && *desc != ',') {
772         int n = *desc++;
773         if (n >= 'a' && n <= 'z') {
774             squares += n - 'a' + 1;
775         } else if (n == '_') {
776             /* do nothing */;
777         } else if (n > '0' && n <= '9') {
778             int val = atoi(desc-1);
779             if (val < 1 || val > range)
780                 return "Out-of-range number in game description";
781             squares++;
782             while (*desc >= '0' && *desc <= '9')
783                 desc++;
784         } else
785             return "Invalid character in game description";
786     }
787
788     if (squares < area)
789         return "Not enough data to fill grid";
790
791     if (squares > area)
792         return "Too much data to fit in grid";
793     *pdesc = desc;
794     return NULL;
795 }
796
797 static char *validate_desc(game_params *params, char *desc)
798 {
799     int w = params->w, a = w*w;
800     const char *p = desc;
801
802     return validate_grid_desc(&p, w, a);
803 }
804
805 static char *spec_to_grid(char *desc, digit *grid, int area)
806 {
807     int i = 0;
808     while (*desc && *desc != ',') {
809         int n = *desc++;
810         if (n >= 'a' && n <= 'z') {
811             int run = n - 'a' + 1;
812             assert(i + run <= area);
813             while (run-- > 0)
814                 grid[i++] = 0;
815         } else if (n == '_') {
816             /* do nothing */;
817         } else if (n > '0' && n <= '9') {
818             assert(i < area);
819             grid[i++] = atoi(desc-1);
820             while (*desc >= '0' && *desc <= '9')
821                 desc++;
822         } else {
823             assert(!"We can't get here");
824         }
825     }
826     assert(i == area);
827     return desc;
828 }
829
830 static game_state *new_game(midend *me, game_params *params, char *desc)
831 {
832     int w = params->w, a = w*w;
833     game_state *state = snew(game_state);
834     int i;
835
836     state->par = *params;              /* structure copy */
837     state->grid = snewn(a, digit);
838     state->immutable = snewn(a, unsigned char);
839     state->pencil = snewn(a, int);
840     for (i = 0; i < a; i++) {
841         state->grid[i] = 0;
842         state->immutable[i] = 0;
843         state->pencil[i] = 0;
844     }
845     state->sequence = snewn(w, digit);
846     for (i = 0; i < w; i++) {
847         state->sequence[i] = i;
848     }
849
850     desc = spec_to_grid(desc, state->grid, a);
851     for (i = 0; i < a; i++)
852         if (state->grid[i] != 0)
853             state->immutable[i] = TRUE;
854
855     state->completed = state->cheated = FALSE;
856
857     return state;
858 }
859
860 static game_state *dup_game(game_state *state)
861 {
862     int w = state->par.w, a = w*w;
863     game_state *ret = snew(game_state);
864
865     ret->par = state->par;             /* structure copy */
866
867     ret->grid = snewn(a, digit);
868     ret->immutable = snewn(a, unsigned char);
869     ret->pencil = snewn(a, int);
870     ret->sequence = snewn(w, digit);
871     memcpy(ret->grid, state->grid, a*sizeof(digit));
872     memcpy(ret->immutable, state->immutable, a*sizeof(unsigned char));
873     memcpy(ret->pencil, state->pencil, a*sizeof(int));
874     memcpy(ret->sequence, state->sequence, w*sizeof(digit));
875
876     ret->completed = state->completed;
877     ret->cheated = state->cheated;
878
879     return ret;
880 }
881
882 static void free_game(game_state *state)
883 {
884     sfree(state->grid);
885     sfree(state->immutable);
886     sfree(state->pencil);
887     sfree(state->sequence);
888     sfree(state);
889 }
890
891 static char *solve_game(game_state *state, game_state *currstate,
892                         char *aux, char **error)
893 {
894     int w = state->par.w, a = w*w;
895     int i, ret;
896     digit *soln;
897     char *out;
898
899     if (aux)
900         return dupstr(aux);
901
902     soln = snewn(a, digit);
903     memcpy(soln, state->grid, a*sizeof(digit));
904
905     ret = solver(&state->par, soln, DIFFCOUNT-1);
906
907     if (ret == diff_impossible) {
908         *error = "No solution exists for this puzzle";
909         out = NULL;
910     } else if (ret == diff_ambiguous) {
911         *error = "Multiple solutions exist for this puzzle";
912         out = NULL;
913     } else {
914         out = snewn(a+2, char);
915         out[0] = 'S';
916         for (i = 0; i < a; i++)
917             out[i+1] = TOCHAR(soln[i], state->par.id);
918         out[a+1] = '\0';
919     }
920
921     sfree(soln);
922     return out;
923 }
924
925 static int game_can_format_as_text_now(game_params *params)
926 {
927     return TRUE;
928 }
929
930 static char *game_text_format(game_state *state)
931 {
932     int w = state->par.w;
933     int x, y;
934     char *ret, *p, ch;
935
936     ret = snewn(2*w*w+1, char);        /* leave room for terminating NUL */
937
938     p = ret;
939     for (y = 0; y < w; y++) {
940         for (x = 0; x < w; x++) {
941             digit d = state->grid[y*w+x];
942
943             if (d == 0) {
944                 ch = '.';
945             } else {
946                 ch = TOCHAR(d, state->par.id);
947             }
948
949             *p++ = ch;
950             if (x == w-1) {
951                 *p++ = '\n';
952             } else {
953                 *p++ = ' ';
954             }
955         }
956     }
957
958     assert(p - ret == 2*w*w);
959     *p = '\0';
960     return ret;
961 }
962
963 struct game_ui {
964     /*
965      * These are the coordinates of the currently highlighted
966      * square on the grid, if hshow = 1.
967      */
968     int hx, hy;
969     /*
970      * This indicates whether the current highlight is a
971      * pencil-mark one or a real one.
972      */
973     int hpencil;
974     /*
975      * This indicates whether or not we're showing the highlight
976      * (used to be hx = hy = -1); important so that when we're
977      * using the cursor keys it doesn't keep coming back at a
978      * fixed position. When hshow = 1, pressing a valid number
979      * or letter key or Space will enter that number or letter in the grid.
980      */
981     int hshow;
982     /*
983      * This indicates whether we're using the highlight as a cursor;
984      * it means that it doesn't vanish on a keypress, and that it is
985      * allowed on immutable squares.
986      */
987     int hcursor;
988     /*
989      * This indicates whether we're dragging a table header to
990      * reposition an entire row or column.
991      */
992     int drag;                          /* 0=none 1=row 2=col */
993     int dragnum;                       /* element being dragged */
994     int dragpos;                       /* its current position */
995 };
996
997 static game_ui *new_ui(game_state *state)
998 {
999     game_ui *ui = snew(game_ui);
1000
1001     ui->hx = ui->hy = 0;
1002     ui->hpencil = ui->hshow = ui->hcursor = 0;
1003     ui->drag = 0;
1004
1005     return ui;
1006 }
1007
1008 static void free_ui(game_ui *ui)
1009 {
1010     sfree(ui);
1011 }
1012
1013 static char *encode_ui(game_ui *ui)
1014 {
1015     return NULL;
1016 }
1017
1018 static void decode_ui(game_ui *ui, char *encoding)
1019 {
1020 }
1021
1022 static void game_changed_state(game_ui *ui, game_state *oldstate,
1023                                game_state *newstate)
1024 {
1025     int w = newstate->par.w;
1026     /*
1027      * We prevent pencil-mode highlighting of a filled square, unless
1028      * we're using the cursor keys. So if the user has just filled in
1029      * a square which we had a pencil-mode highlight in (by Undo, or
1030      * by Redo, or by Solve), then we cancel the highlight.
1031      */
1032     if (ui->hshow && ui->hpencil && !ui->hcursor &&
1033         newstate->grid[ui->hy * w + ui->hx] != 0) {
1034         ui->hshow = 0;
1035     }
1036 }
1037
1038 #define PREFERRED_TILESIZE 48
1039 #define TILESIZE (ds->tilesize)
1040 #define BORDER (TILESIZE / 2)
1041 #define LEGEND (TILESIZE)
1042 #define GRIDEXTRA max((TILESIZE / 32),1)
1043 #define COORD(x) ((x)*TILESIZE + BORDER + LEGEND)
1044 #define FROMCOORD(x) (((x)+(TILESIZE-BORDER-LEGEND)) / TILESIZE - 1)
1045
1046 #define FLASH_TIME 0.4F
1047
1048 #define DF_HIGHLIGHT 0x0400
1049 #define DF_HIGHLIGHT_PENCIL 0x0200
1050 #define DF_IMMUTABLE 0x0100
1051 #define DF_LEGEND 0x0080
1052 #define DF_DIGIT_MASK 0x001F
1053
1054 #define EF_DIGIT_SHIFT 5
1055 #define EF_DIGIT_MASK ((1 << EF_DIGIT_SHIFT) - 1)
1056 #define EF_LEFT_SHIFT 0
1057 #define EF_RIGHT_SHIFT (3*EF_DIGIT_SHIFT)
1058 #define EF_LEFT_MASK ((1UL << (3*EF_DIGIT_SHIFT)) - 1UL)
1059 #define EF_RIGHT_MASK (EF_LEFT_MASK << EF_RIGHT_SHIFT)
1060 #define EF_LATIN (1UL << (6*EF_DIGIT_SHIFT))
1061
1062 struct game_drawstate {
1063     game_params par;
1064     int w, tilesize;
1065     int started;
1066     long *tiles, *legend, *pencil, *errors;
1067     long *errtmp;
1068     digit *sequence;
1069 };
1070
1071 static int check_errors(game_state *state, long *errors)
1072 {
1073     int w = state->par.w, a = w*w;
1074     digit *grid = state->grid;
1075     int i, j, k, x, y, errs = FALSE;
1076
1077     /*
1078      * To verify that we have a valid group table, it suffices to
1079      * test latin-square-hood and associativity only. All the other
1080      * group axioms follow from those two.
1081      *
1082      * Proof:
1083      *
1084      * Associativity is given; closure is obvious from latin-
1085      * square-hood. We need to show that an identity exists and that
1086      * every element has an inverse.
1087      *
1088      * Identity: take any element a. There will be some element e
1089      * such that ea=a (in a latin square, every element occurs in
1090      * every row and column, so a must occur somewhere in the a
1091      * column, say on row e). For any other element b, there must
1092      * exist x such that ax=b (same argument from latin-square-hood
1093      * again), and then associativity gives us eb = e(ax) = (ea)x =
1094      * ax = b. Hence eb=b for all b, i.e. e is a left-identity. A
1095      * similar argument tells us that there must be some f which is
1096      * a right-identity, and then we show they are the same element
1097      * by observing that ef must simultaneously equal e and equal f.
1098      *
1099      * Inverses: given any a, by the latin-square argument again,
1100      * there must exist p and q such that pa=e and aq=e (i.e. left-
1101      * and right-inverses). We can show these are equal by
1102      * associativity: p = pe = p(aq) = (pa)q = eq = q. []
1103      */
1104
1105     if (errors)
1106         for (i = 0; i < a; i++)
1107             errors[i] = 0;
1108
1109     for (y = 0; y < w; y++) {
1110         unsigned long mask = 0, errmask = 0;
1111         for (x = 0; x < w; x++) {
1112             unsigned long bit = 1UL << grid[y*w+x];
1113             errmask |= (mask & bit);
1114             mask |= bit;
1115         }
1116
1117         if (mask != (1 << (w+1)) - (1 << 1)) {
1118             errs = TRUE;
1119             errmask &= ~1UL;
1120             if (errors) {
1121                 for (x = 0; x < w; x++)
1122                     if (errmask & (1UL << grid[y*w+x]))
1123                         errors[y*w+x] |= EF_LATIN;
1124             }
1125         }
1126     }
1127
1128     for (x = 0; x < w; x++) {
1129         unsigned long mask = 0, errmask = 0;
1130         for (y = 0; y < w; y++) {
1131             unsigned long bit = 1UL << grid[y*w+x];
1132             errmask |= (mask & bit);
1133             mask |= bit;
1134         }
1135
1136         if (mask != (1 << (w+1)) - (1 << 1)) {
1137             errs = TRUE;
1138             errmask &= ~1UL;
1139             if (errors) {
1140                 for (y = 0; y < w; y++)
1141                     if (errmask & (1UL << grid[y*w+x]))
1142                         errors[y*w+x] |= EF_LATIN;
1143             }
1144         }
1145     }
1146
1147     for (i = 1; i < w; i++)
1148         for (j = 1; j < w; j++)
1149             for (k = 1; k < w; k++)
1150                 if (grid[i*w+j] && grid[j*w+k] &&
1151                     grid[(grid[i*w+j]-1)*w+k] &&
1152                     grid[i*w+(grid[j*w+k]-1)] &&
1153                     grid[(grid[i*w+j]-1)*w+k] != grid[i*w+(grid[j*w+k]-1)]) {
1154                     if (errors) {
1155                         int a = i+1, b = j+1, c = k+1;
1156                         int ab = grid[i*w+j], bc = grid[j*w+k];
1157                         int left = (ab-1)*w+(c-1), right = (a-1)*w+(bc-1);
1158                         /*
1159                          * If the appropriate error slot is already
1160                          * used for one of the squares, we don't
1161                          * fill either of them.
1162                          */
1163                         if (!(errors[left] & EF_LEFT_MASK) &&
1164                             !(errors[right] & EF_RIGHT_MASK)) {
1165                             long err;
1166                             err = a;
1167                             err = (err << EF_DIGIT_SHIFT) | b;
1168                             err = (err << EF_DIGIT_SHIFT) | c;
1169                             errors[left] |= err << EF_LEFT_SHIFT;
1170                             errors[right] |= err << EF_RIGHT_SHIFT;
1171                         }
1172                     }
1173                     errs = TRUE;
1174                 }
1175
1176     return errs;
1177 }
1178
1179 static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
1180                             int x, int y, int button)
1181 {
1182     int w = state->par.w;
1183     int tx, ty;
1184     char buf[80];
1185
1186     button &= ~MOD_MASK;
1187
1188     tx = FROMCOORD(x);
1189     ty = FROMCOORD(y);
1190
1191     if (ui->drag) {
1192         if (IS_MOUSE_DRAG(button)) {
1193             int tcoord = (ui->drag == 1 ? ty : tx);
1194             if (tcoord >= 0 && tcoord < w) {
1195                 ui->dragpos = tcoord;
1196                 return "";
1197             }
1198         } else if (IS_MOUSE_RELEASE(button)) {
1199             ui->drag = 0;              /* end drag */
1200             if (state->sequence[ui->dragpos] == ui->dragnum)
1201                 return "";             /* drag was a no-op overall */
1202             sprintf(buf, "D%d,%d", ui->dragnum, ui->dragpos);
1203             return dupstr(buf);
1204         }
1205     } else if (IS_MOUSE_DOWN(button)) {
1206         if (tx >= 0 && tx < w && ty >= 0 && ty < w) {
1207             tx = state->sequence[tx];
1208             ty = state->sequence[ty];
1209             if (button == LEFT_BUTTON) {
1210                 if (tx == ui->hx && ty == ui->hy &&
1211                     ui->hshow && ui->hpencil == 0) {
1212                     ui->hshow = 0;
1213                 } else {
1214                     ui->hx = tx;
1215                     ui->hy = ty;
1216                     ui->hshow = !state->immutable[ty*w+tx];
1217                     ui->hpencil = 0;
1218                 }
1219                 ui->hcursor = 0;
1220                 return "";                     /* UI activity occurred */
1221             }
1222             if (button == RIGHT_BUTTON) {
1223                 /*
1224                  * Pencil-mode highlighting for non filled squares.
1225                  */
1226                 if (state->grid[ty*w+tx] == 0) {
1227                     if (tx == ui->hx && ty == ui->hy &&
1228                         ui->hshow && ui->hpencil) {
1229                         ui->hshow = 0;
1230                     } else {
1231                         ui->hpencil = 1;
1232                         ui->hx = tx;
1233                         ui->hy = ty;
1234                         ui->hshow = 1;
1235                     }
1236                 } else {
1237                     ui->hshow = 0;
1238                 }
1239                 ui->hcursor = 0;
1240                 return "";                     /* UI activity occurred */
1241             }
1242         } else if (tx >= 0 && tx < w && ty == -1) {
1243             ui->drag = 2;
1244             ui->dragnum = state->sequence[tx];
1245             ui->dragpos = tx;
1246             return "";
1247         } else if (ty >= 0 && ty < w && tx == -1) {
1248             ui->drag = 1;
1249             ui->dragnum = state->sequence[ty];
1250             ui->dragpos = ty;
1251             return "";
1252         }
1253     }
1254
1255     if (IS_CURSOR_MOVE(button)) {
1256         move_cursor(button, &ui->hx, &ui->hy, w, w, 0);
1257         ui->hshow = ui->hcursor = 1;
1258         return "";
1259     }
1260     if (ui->hshow &&
1261         (button == CURSOR_SELECT)) {
1262         ui->hpencil = 1 - ui->hpencil;
1263         ui->hcursor = 1;
1264         return "";
1265     }
1266
1267     if (ui->hshow &&
1268         ((ISCHAR(button) && FROMCHAR(button, state->par.id) <= w) ||
1269          button == CURSOR_SELECT2 || button == '\b')) {
1270         int n = FROMCHAR(button, state->par.id);
1271         if (button == CURSOR_SELECT2 || button == '\b')
1272             n = 0;
1273
1274         /*
1275          * Can't make pencil marks in a filled square. This can only
1276          * become highlighted if we're using cursor keys.
1277          */
1278         if (ui->hpencil && state->grid[ui->hy*w+ui->hx])
1279             return NULL;
1280
1281         /*
1282          * Can't do anything to an immutable square.
1283          */
1284         if (state->immutable[ui->hy*w+ui->hx])
1285             return NULL;
1286
1287         sprintf(buf, "%c%d,%d,%d",
1288                 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n);
1289
1290         if (!ui->hcursor) ui->hshow = 0;
1291
1292         return dupstr(buf);
1293     }
1294
1295     if (button == 'M' || button == 'm')
1296         return dupstr("M");
1297
1298     return NULL;
1299 }
1300
1301 static game_state *execute_move(game_state *from, char *move)
1302 {
1303     int w = from->par.w, a = w*w;
1304     game_state *ret;
1305     int x, y, i, j, n;
1306
1307     if (move[0] == 'S') {
1308         ret = dup_game(from);
1309         ret->completed = ret->cheated = TRUE;
1310
1311         for (i = 0; i < a; i++) {
1312             if (!ISCHAR(move[i+1]) || FROMCHAR(move[i+1], from->par.id) > w) {
1313                 free_game(ret);
1314                 return NULL;
1315             }
1316             ret->grid[i] = FROMCHAR(move[i+1], from->par.id);
1317             ret->pencil[i] = 0;
1318         }
1319
1320         if (move[a+1] != '\0') {
1321             free_game(ret);
1322             return NULL;
1323         }
1324
1325         return ret;
1326     } else if ((move[0] == 'P' || move[0] == 'R') &&
1327         sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 &&
1328         x >= 0 && x < w && y >= 0 && y < w && n >= 0 && n <= w) {
1329         if (from->immutable[y*w+x])
1330             return NULL;
1331
1332         ret = dup_game(from);
1333         if (move[0] == 'P' && n > 0) {
1334             ret->pencil[y*w+x] ^= 1 << n;
1335         } else {
1336             ret->grid[y*w+x] = n;
1337             ret->pencil[y*w+x] = 0;
1338
1339             if (!ret->completed && !check_errors(ret, NULL))
1340                 ret->completed = TRUE;
1341         }
1342         return ret;
1343     } else if (move[0] == 'M') {
1344         /*
1345          * Fill in absolutely all pencil marks everywhere. (I
1346          * wouldn't use this for actual play, but it's a handy
1347          * starting point when following through a set of
1348          * diagnostics output by the standalone solver.)
1349          */
1350         ret = dup_game(from);
1351         for (i = 0; i < a; i++) {
1352             if (!ret->grid[i])
1353                 ret->pencil[i] = (1 << (w+1)) - (1 << 1);
1354         }
1355         return ret;
1356     } else if (move[0] == 'D' &&
1357                sscanf(move+1, "%d,%d", &x, &y) == 2) {
1358         /*
1359          * Reorder the rows and columns so that digit x is in position
1360          * y.
1361          */
1362         ret = dup_game(from);
1363         for (i = j = 0; i < w; i++) {
1364             if (i == y) {
1365                 ret->sequence[i] = x;
1366             } else {
1367                 if (from->sequence[j] == x)
1368                     j++;
1369                 ret->sequence[i] = from->sequence[j++];
1370             }
1371         }
1372         return ret;
1373     } else
1374         return NULL;                   /* couldn't parse move string */
1375 }
1376
1377 /* ----------------------------------------------------------------------
1378  * Drawing routines.
1379  */
1380
1381 #define SIZE(w) ((w) * TILESIZE + 2*BORDER + LEGEND)
1382
1383 static void game_compute_size(game_params *params, int tilesize,
1384                               int *x, int *y)
1385 {
1386     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1387     struct { int tilesize; } ads, *ds = &ads;
1388     ads.tilesize = tilesize;
1389
1390     *x = *y = SIZE(params->w);
1391 }
1392
1393 static void game_set_size(drawing *dr, game_drawstate *ds,
1394                           game_params *params, int tilesize)
1395 {
1396     ds->tilesize = tilesize;
1397 }
1398
1399 static float *game_colours(frontend *fe, int *ncolours)
1400 {
1401     float *ret = snewn(3 * NCOLOURS, float);
1402
1403     frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
1404
1405     ret[COL_GRID * 3 + 0] = 0.0F;
1406     ret[COL_GRID * 3 + 1] = 0.0F;
1407     ret[COL_GRID * 3 + 2] = 0.0F;
1408
1409     ret[COL_USER * 3 + 0] = 0.0F;
1410     ret[COL_USER * 3 + 1] = 0.6F * ret[COL_BACKGROUND * 3 + 1];
1411     ret[COL_USER * 3 + 2] = 0.0F;
1412
1413     ret[COL_HIGHLIGHT * 3 + 0] = 0.78F * ret[COL_BACKGROUND * 3 + 0];
1414     ret[COL_HIGHLIGHT * 3 + 1] = 0.78F * ret[COL_BACKGROUND * 3 + 1];
1415     ret[COL_HIGHLIGHT * 3 + 2] = 0.78F * ret[COL_BACKGROUND * 3 + 2];
1416
1417     ret[COL_ERROR * 3 + 0] = 1.0F;
1418     ret[COL_ERROR * 3 + 1] = 0.0F;
1419     ret[COL_ERROR * 3 + 2] = 0.0F;
1420
1421     ret[COL_PENCIL * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0];
1422     ret[COL_PENCIL * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1];
1423     ret[COL_PENCIL * 3 + 2] = ret[COL_BACKGROUND * 3 + 2];
1424
1425     *ncolours = NCOLOURS;
1426     return ret;
1427 }
1428
1429 static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
1430 {
1431     int w = state->par.w, a = w*w;
1432     struct game_drawstate *ds = snew(struct game_drawstate);
1433     int i;
1434
1435     ds->w = w;
1436     ds->par = state->par;              /* structure copy */
1437     ds->tilesize = 0;
1438     ds->started = FALSE;
1439     ds->tiles = snewn(a, long);
1440     ds->legend = snewn(w, long);
1441     ds->pencil = snewn(a, long);
1442     ds->errors = snewn(a, long);
1443     ds->sequence = snewn(a, digit);
1444     for (i = 0; i < a; i++)
1445         ds->tiles[i] = ds->pencil[i] = -1;
1446     for (i = 0; i < w; i++)
1447         ds->legend[i] = -1;
1448     ds->errtmp = snewn(a, long);
1449
1450     return ds;
1451 }
1452
1453 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1454 {
1455     sfree(ds->tiles);
1456     sfree(ds->pencil);
1457     sfree(ds->errors);
1458     sfree(ds->errtmp);
1459     sfree(ds->sequence);
1460     sfree(ds);
1461 }
1462
1463 static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y, long tile,
1464                       long pencil, long error)
1465 {
1466     int w = ds->w /* , a = w*w */;
1467     int tx, ty, tw, th;
1468     int cx, cy, cw, ch;
1469     char str[64];
1470
1471     tx = BORDER + LEGEND + x * TILESIZE + 1;
1472     ty = BORDER + LEGEND + y * TILESIZE + 1;
1473
1474     cx = tx;
1475     cy = ty;
1476     cw = tw = TILESIZE-1;
1477     ch = th = TILESIZE-1;
1478
1479     if (tile & DF_LEGEND) {
1480         cx += TILESIZE/10;
1481         cy += TILESIZE/10;
1482         cw -= TILESIZE/5;
1483         ch -= TILESIZE/5;
1484         tile |= DF_IMMUTABLE;
1485     }
1486
1487     clip(dr, cx, cy, cw, ch);
1488
1489     /* background needs erasing */
1490     draw_rect(dr, cx, cy, cw, ch,
1491               (tile & DF_HIGHLIGHT) ? COL_HIGHLIGHT : COL_BACKGROUND);
1492
1493     /* pencil-mode highlight */
1494     if (tile & DF_HIGHLIGHT_PENCIL) {
1495         int coords[6];
1496         coords[0] = cx;
1497         coords[1] = cy;
1498         coords[2] = cx+cw/2;
1499         coords[3] = cy;
1500         coords[4] = cx;
1501         coords[5] = cy+ch/2;
1502         draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
1503     }
1504
1505     /* new number needs drawing? */
1506     if (tile & DF_DIGIT_MASK) {
1507         str[1] = '\0';
1508         str[0] = TOCHAR(tile & DF_DIGIT_MASK, ds->par.id);
1509         draw_text(dr, tx + TILESIZE/2, ty + TILESIZE/2,
1510                   FONT_VARIABLE, TILESIZE/2, ALIGN_VCENTRE | ALIGN_HCENTRE,
1511                   (error & EF_LATIN) ? COL_ERROR :
1512                   (tile & DF_IMMUTABLE) ? COL_GRID : COL_USER, str);
1513
1514         if (error & EF_LEFT_MASK) {
1515             int a = (error >> (EF_LEFT_SHIFT+2*EF_DIGIT_SHIFT))&EF_DIGIT_MASK;
1516             int b = (error >> (EF_LEFT_SHIFT+1*EF_DIGIT_SHIFT))&EF_DIGIT_MASK;
1517             int c = (error >> (EF_LEFT_SHIFT                 ))&EF_DIGIT_MASK;
1518             char buf[10];
1519             sprintf(buf, "(%c%c)%c", TOCHAR(a, ds->par.id),
1520                     TOCHAR(b, ds->par.id), TOCHAR(c, ds->par.id));
1521             draw_text(dr, tx + TILESIZE/2, ty + TILESIZE/6,
1522                       FONT_VARIABLE, TILESIZE/6, ALIGN_VCENTRE | ALIGN_HCENTRE,
1523                       COL_ERROR, buf);
1524         }
1525         if (error & EF_RIGHT_MASK) {
1526             int a = (error >> (EF_RIGHT_SHIFT+2*EF_DIGIT_SHIFT))&EF_DIGIT_MASK;
1527             int b = (error >> (EF_RIGHT_SHIFT+1*EF_DIGIT_SHIFT))&EF_DIGIT_MASK;
1528             int c = (error >> (EF_RIGHT_SHIFT                 ))&EF_DIGIT_MASK;
1529             char buf[10];
1530             sprintf(buf, "%c(%c%c)", TOCHAR(a, ds->par.id),
1531                     TOCHAR(b, ds->par.id), TOCHAR(c, ds->par.id));
1532             draw_text(dr, tx + TILESIZE/2, ty + TILESIZE - TILESIZE/6,
1533                       FONT_VARIABLE, TILESIZE/6, ALIGN_VCENTRE | ALIGN_HCENTRE,
1534                       COL_ERROR, buf);
1535         }
1536     } else {
1537         int i, j, npencil;
1538         int pl, pr, pt, pb;
1539         float bestsize;
1540         int pw, ph, minph, pbest, fontsize;
1541
1542         /* Count the pencil marks required. */
1543         for (i = 1, npencil = 0; i <= w; i++)
1544             if (pencil & (1 << i))
1545                 npencil++;
1546         if (npencil) {
1547
1548             minph = 2;
1549
1550             /*
1551              * Determine the bounding rectangle within which we're going
1552              * to put the pencil marks.
1553              */
1554             /* Start with the whole square */
1555             pl = tx + GRIDEXTRA;
1556             pr = pl + TILESIZE - GRIDEXTRA;
1557             pt = ty + GRIDEXTRA;
1558             pb = pt + TILESIZE - GRIDEXTRA;
1559
1560             /*
1561              * We arrange our pencil marks in a grid layout, with
1562              * the number of rows and columns adjusted to allow the
1563              * maximum font size.
1564              *
1565              * So now we work out what the grid size ought to be.
1566              */
1567             bestsize = 0.0;
1568             pbest = 0;
1569             /* Minimum */
1570             for (pw = 3; pw < max(npencil,4); pw++) {
1571                 float fw, fh, fs;
1572
1573                 ph = (npencil + pw - 1) / pw;
1574                 ph = max(ph, minph);
1575                 fw = (pr - pl) / (float)pw;
1576                 fh = (pb - pt) / (float)ph;
1577                 fs = min(fw, fh);
1578                 if (fs > bestsize) {
1579                     bestsize = fs;
1580                     pbest = pw;
1581                 }
1582             }
1583             assert(pbest > 0);
1584             pw = pbest;
1585             ph = (npencil + pw - 1) / pw;
1586             ph = max(ph, minph);
1587
1588             /*
1589              * Now we've got our grid dimensions, work out the pixel
1590              * size of a grid element, and round it to the nearest
1591              * pixel. (We don't want rounding errors to make the
1592              * grid look uneven at low pixel sizes.)
1593              */
1594             fontsize = min((pr - pl) / pw, (pb - pt) / ph);
1595
1596             /*
1597              * Centre the resulting figure in the square.
1598              */
1599             pl = tx + (TILESIZE - fontsize * pw) / 2;
1600             pt = ty + (TILESIZE - fontsize * ph) / 2;
1601
1602             /*
1603              * Now actually draw the pencil marks.
1604              */
1605             for (i = 1, j = 0; i <= w; i++)
1606                 if (pencil & (1 << i)) {
1607                     int dx = j % pw, dy = j / pw;
1608
1609                     str[1] = '\0';
1610                     str[0] = TOCHAR(i, ds->par.id);
1611                     draw_text(dr, pl + fontsize * (2*dx+1) / 2,
1612                               pt + fontsize * (2*dy+1) / 2,
1613                               FONT_VARIABLE, fontsize,
1614                               ALIGN_VCENTRE | ALIGN_HCENTRE, COL_PENCIL, str);
1615                     j++;
1616                 }
1617         }
1618     }
1619
1620     unclip(dr);
1621
1622     draw_update(dr, cx, cy, cw, ch);
1623 }
1624
1625 static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
1626                         game_state *state, int dir, game_ui *ui,
1627                         float animtime, float flashtime)
1628 {
1629     int w = state->par.w /*, a = w*w */;
1630     int x, y, i, j;
1631
1632     if (!ds->started) {
1633         /*
1634          * The initial contents of the window are not guaranteed and
1635          * can vary with front ends. To be on the safe side, all
1636          * games should start by drawing a big background-colour
1637          * rectangle covering the whole window.
1638          */
1639         draw_rect(dr, 0, 0, SIZE(w), SIZE(w), COL_BACKGROUND);
1640
1641         /*
1642          * Big containing rectangle.
1643          */
1644         draw_rect(dr, COORD(0) - GRIDEXTRA, COORD(0) - GRIDEXTRA,
1645                   w*TILESIZE+1+GRIDEXTRA*2, w*TILESIZE+1+GRIDEXTRA*2,
1646                   COL_GRID);
1647
1648         draw_update(dr, 0, 0, SIZE(w), SIZE(w));
1649
1650         ds->started = TRUE;
1651     }
1652
1653     check_errors(state, ds->errtmp);
1654
1655     /*
1656      * Construct a modified version of state->sequence which takes
1657      * into account an unfinished drag operation.
1658      */
1659     if (ui->drag) {
1660         x = ui->dragnum;
1661         y = ui->dragpos;
1662     } else {
1663         x = y = -1;
1664     }
1665     for (i = j = 0; i < w; i++) {
1666         if (i == y) {
1667             ds->sequence[i] = x;
1668         } else {
1669             if (state->sequence[j] == x)
1670                 j++;
1671             ds->sequence[i] = state->sequence[j++];
1672         }
1673     }
1674
1675     /*
1676      * Draw the table legend.
1677      */
1678     for (x = 0; x < w; x++) {
1679         int sx = ds->sequence[x];
1680         long tile = (sx+1) | DF_LEGEND;
1681         if (ds->legend[x] != tile) {
1682             ds->legend[x] = tile;
1683             draw_tile(dr, ds, -1, x, tile, 0, 0);
1684             draw_tile(dr, ds, x, -1, tile, 0, 0);
1685         }
1686     }
1687
1688     for (y = 0; y < w; y++) {
1689         int sy = ds->sequence[y];
1690         for (x = 0; x < w; x++) {
1691             long tile = 0L, pencil = 0L, error;
1692             int sx = ds->sequence[x];
1693
1694             if (state->grid[sy*w+sx])
1695                 tile = state->grid[sy*w+sx];
1696             else
1697                 pencil = (long)state->pencil[sy*w+sx];
1698
1699             if (state->immutable[sy*w+sx])
1700                 tile |= DF_IMMUTABLE;
1701
1702             if ((ui->drag == 1 && ui->dragnum == sy) ||
1703                 (ui->drag == 2 && ui->dragnum == sx))
1704                 tile |= DF_HIGHLIGHT;
1705             else if (ui->hshow && ui->hx == sx && ui->hy == sy)
1706                 tile |= (ui->hpencil ? DF_HIGHLIGHT_PENCIL : DF_HIGHLIGHT);
1707
1708             if (flashtime > 0 &&
1709                 (flashtime <= FLASH_TIME/3 ||
1710                  flashtime >= FLASH_TIME*2/3))
1711                 tile |= DF_HIGHLIGHT;  /* completion flash */
1712
1713             error = ds->errtmp[y*w+x];
1714
1715             if (ds->tiles[y*w+x] != tile ||
1716                 ds->pencil[y*w+x] != pencil ||
1717                 ds->errors[y*w+x] != error) {
1718                 ds->tiles[y*w+x] = tile;
1719                 ds->pencil[y*w+x] = pencil;
1720                 ds->errors[y*w+x] = error;
1721                 draw_tile(dr, ds, x, y, tile, pencil, error);
1722             }
1723         }
1724     }
1725 }
1726
1727 static float game_anim_length(game_state *oldstate, game_state *newstate,
1728                               int dir, game_ui *ui)
1729 {
1730     return 0.0F;
1731 }
1732
1733 static float game_flash_length(game_state *oldstate, game_state *newstate,
1734                                int dir, game_ui *ui)
1735 {
1736     if (!oldstate->completed && newstate->completed &&
1737         !oldstate->cheated && !newstate->cheated)
1738         return FLASH_TIME;
1739     return 0.0F;
1740 }
1741
1742 static int game_timing_state(game_state *state, game_ui *ui)
1743 {
1744     if (state->completed)
1745         return FALSE;
1746     return TRUE;
1747 }
1748
1749 static void game_print_size(game_params *params, float *x, float *y)
1750 {
1751     int pw, ph;
1752
1753     /*
1754      * We use 9mm squares by default, like Solo.
1755      */
1756     game_compute_size(params, 900, &pw, &ph);
1757     *x = pw / 100.0F;
1758     *y = ph / 100.0F;
1759 }
1760
1761 static void game_print(drawing *dr, game_state *state, int tilesize)
1762 {
1763     int w = state->par.w;
1764     int ink = print_mono_colour(dr, 0);
1765     int x, y;
1766
1767     /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1768     game_drawstate ads, *ds = &ads;
1769     game_set_size(dr, ds, NULL, tilesize);
1770
1771     /*
1772      * Border.
1773      */
1774     print_line_width(dr, 3 * TILESIZE / 40);
1775     draw_rect_outline(dr, BORDER + LEGEND, BORDER + LEGEND,
1776                       w*TILESIZE, w*TILESIZE, ink);
1777
1778     /*
1779      * Legend on table.
1780      */
1781     for (x = 0; x < w; x++) {
1782         char str[2];
1783         str[1] = '\0';
1784         str[0] = TOCHAR(x+1, state->par.id);
1785         draw_text(dr, BORDER+LEGEND + x*TILESIZE + TILESIZE/2,
1786                   BORDER + TILESIZE/2,
1787                   FONT_VARIABLE, TILESIZE/2,
1788                   ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str);
1789         draw_text(dr, BORDER + TILESIZE/2,
1790                   BORDER+LEGEND + x*TILESIZE + TILESIZE/2,
1791                   FONT_VARIABLE, TILESIZE/2,
1792                   ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str);
1793     }
1794
1795     /*
1796      * Main grid.
1797      */
1798     for (x = 1; x < w; x++) {
1799         print_line_width(dr, TILESIZE / 40);
1800         draw_line(dr, BORDER+LEGEND+x*TILESIZE, BORDER+LEGEND,
1801                   BORDER+LEGEND+x*TILESIZE, BORDER+LEGEND+w*TILESIZE, ink);
1802     }
1803     for (y = 1; y < w; y++) {
1804         print_line_width(dr, TILESIZE / 40);
1805         draw_line(dr, BORDER+LEGEND, BORDER+LEGEND+y*TILESIZE,
1806                   BORDER+LEGEND+w*TILESIZE, BORDER+LEGEND+y*TILESIZE, ink);
1807     }
1808
1809     /*
1810      * Numbers.
1811      */
1812     for (y = 0; y < w; y++)
1813         for (x = 0; x < w; x++)
1814             if (state->grid[y*w+x]) {
1815                 char str[2];
1816                 str[1] = '\0';
1817                 str[0] = TOCHAR(state->grid[y*w+x], state->par.id);
1818                 draw_text(dr, BORDER+LEGEND + x*TILESIZE + TILESIZE/2,
1819                           BORDER+LEGEND + y*TILESIZE + TILESIZE/2,
1820                           FONT_VARIABLE, TILESIZE/2,
1821                           ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str);
1822             }
1823 }
1824
1825 #ifdef COMBINED
1826 #define thegame group
1827 #endif
1828
1829 const struct game thegame = {
1830     "Group", NULL, NULL,
1831     default_params,
1832     game_fetch_preset,
1833     decode_params,
1834     encode_params,
1835     free_params,
1836     dup_params,
1837     TRUE, game_configure, custom_params,
1838     validate_params,
1839     new_game_desc,
1840     validate_desc,
1841     new_game,
1842     dup_game,
1843     free_game,
1844     TRUE, solve_game,
1845     TRUE, game_can_format_as_text_now, game_text_format,
1846     new_ui,
1847     free_ui,
1848     encode_ui,
1849     decode_ui,
1850     game_changed_state,
1851     interpret_move,
1852     execute_move,
1853     PREFERRED_TILESIZE, game_compute_size, game_set_size,
1854     game_colours,
1855     game_new_drawstate,
1856     game_free_drawstate,
1857     game_redraw,
1858     game_anim_length,
1859     game_flash_length,
1860     TRUE, FALSE, game_print_size, game_print,
1861     FALSE,                             /* wants_statusbar */
1862     FALSE, game_timing_state,
1863     REQUIRE_RBUTTON | REQUIRE_NUMPAD,  /* flags */
1864 };
1865
1866 #ifdef STANDALONE_SOLVER
1867
1868 #include <stdarg.h>
1869
1870 int main(int argc, char **argv)
1871 {
1872     game_params *p;
1873     game_state *s;
1874     char *id = NULL, *desc, *err;
1875     digit *grid;
1876     int grade = FALSE;
1877     int ret, diff, really_show_working = FALSE;
1878
1879     while (--argc > 0) {
1880         char *p = *++argv;
1881         if (!strcmp(p, "-v")) {
1882             really_show_working = TRUE;
1883         } else if (!strcmp(p, "-g")) {
1884             grade = TRUE;
1885         } else if (*p == '-') {
1886             fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
1887             return 1;
1888         } else {
1889             id = p;
1890         }
1891     }
1892
1893     if (!id) {
1894         fprintf(stderr, "usage: %s [-g | -v] <game_id>\n", argv[0]);
1895         return 1;
1896     }
1897
1898     desc = strchr(id, ':');
1899     if (!desc) {
1900         fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
1901         return 1;
1902     }
1903     *desc++ = '\0';
1904
1905     p = default_params();
1906     decode_params(p, id);
1907     err = validate_desc(p, desc);
1908     if (err) {
1909         fprintf(stderr, "%s: %s\n", argv[0], err);
1910         return 1;
1911     }
1912     s = new_game(NULL, p, desc);
1913
1914     grid = snewn(p->w * p->w, digit);
1915
1916     /*
1917      * When solving a Normal puzzle, we don't want to bother the
1918      * user with Hard-level deductions. For this reason, we grade
1919      * the puzzle internally before doing anything else.
1920      */
1921     ret = -1;                          /* placate optimiser */
1922     solver_show_working = FALSE;
1923     for (diff = 0; diff < DIFFCOUNT; diff++) {
1924         memcpy(grid, s->grid, p->w * p->w);
1925         ret = solver(&s->par, grid, diff);
1926         if (ret <= diff)
1927             break;
1928     }
1929
1930     if (diff == DIFFCOUNT) {
1931         if (grade)
1932             printf("Difficulty rating: ambiguous\n");
1933         else
1934             printf("Unable to find a unique solution\n");
1935     } else {
1936         if (grade) {
1937             if (ret == diff_impossible)
1938                 printf("Difficulty rating: impossible (no solution exists)\n");
1939             else
1940                 printf("Difficulty rating: %s\n", group_diffnames[ret]);
1941         } else {
1942             solver_show_working = really_show_working;
1943             memcpy(grid, s->grid, p->w * p->w);
1944             ret = solver(&s->par, grid, diff);
1945             if (ret != diff)
1946                 printf("Puzzle is inconsistent\n");
1947             else {
1948                 memcpy(s->grid, grid, p->w * p->w);
1949                 fputs(game_text_format(s), stdout);
1950             }
1951         }
1952     }
1953
1954     return 0;
1955 }
1956
1957 #endif
1958
1959 /* vim: set shiftwidth=4 tabstop=8: */