Introduce configurable symmetry type in generated puzzles, and drop
[sgt/puzzles] / solo.c
CommitLineData
1d8e8ad8 1/*
2 * solo.c: the number-placing puzzle most popularly known as `Sudoku'.
3 *
4 * TODO:
5 *
1d8e8ad8 6 * - can we do anything about nasty centring of text in GTK? It
7 * seems to be taking ascenders/descenders into account when
8 * centring. Ick.
9 *
10 * - implement stronger modes of reasoning in nsolve, thus
11 * enabling harder puzzles
ef57b17d 12 * + and having done that, supply configurable difficulty
13 * levels
1d8e8ad8 14 *
ef57b17d 15 * - it might still be nice to do some prioritisation on the
16 * removal of numbers from the grid
17 * + one possibility is to try to minimise the maximum number
18 * of filled squares in any block, which in particular ought
19 * to enforce never leaving a completely filled block in the
20 * puzzle as presented.
21 * + be careful of being too clever here, though, until after
22 * I've tried implementing difficulty levels. It's not
23 * impossible that those might impose much more important
24 * constraints on this process.
1d8e8ad8 25 *
26 * - alternative interface modes
27 * + sudoku.com's Windows program has a palette of possible
28 * entries; you select a palette entry first and then click
29 * on the square you want it to go in, thus enabling
30 * mouse-only play. Useful for PDAs! I don't think it's
31 * actually incompatible with the current highlight-then-type
32 * approach: you _either_ highlight a palette entry and then
33 * click, _or_ you highlight a square and then type. At most
34 * one thing is ever highlighted at a time, so there's no way
35 * to confuse the two.
36 * + `pencil marks' might be useful for more subtle forms of
37 * deduction, once we implement creation of puzzles that
38 * require it.
39 */
40
41/*
42 * Solo puzzles need to be square overall (since each row and each
43 * column must contain one of every digit), but they need not be
44 * subdivided the same way internally. I am going to adopt a
45 * convention whereby I _always_ refer to `r' as the number of rows
46 * of _big_ divisions, and `c' as the number of columns of _big_
47 * divisions. Thus, a 2c by 3r puzzle looks something like this:
48 *
49 * 4 5 1 | 2 6 3
50 * 6 3 2 | 5 4 1
51 * ------+------ (Of course, you can't subdivide it the other way
52 * 1 4 5 | 6 3 2 or you'll get clashes; observe that the 4 in the
53 * 3 2 6 | 4 1 5 top left would conflict with the 4 in the second
54 * ------+------ box down on the left-hand side.)
55 * 5 1 4 | 3 2 6
56 * 2 6 3 | 1 5 4
57 *
58 * The need for a strong naming convention should now be clear:
59 * each small box is two rows of digits by three columns, while the
60 * overall puzzle has three rows of small boxes by two columns. So
61 * I will (hopefully) consistently use `r' to denote the number of
62 * rows _of small boxes_ (here 3), which is also the number of
63 * columns of digits in each small box; and `c' vice versa (here
64 * 2).
65 *
66 * I'm also going to choose arbitrarily to list c first wherever
67 * possible: the above is a 2x3 puzzle, not a 3x2 one.
68 */
69
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <assert.h>
74#include <ctype.h>
75#include <math.h>
76
77#include "puzzles.h"
78
79/*
80 * To save space, I store digits internally as unsigned char. This
81 * imposes a hard limit of 255 on the order of the puzzle. Since
82 * even a 5x5 takes unacceptably long to generate, I don't see this
83 * as a serious limitation unless something _really_ impressive
84 * happens in computing technology; but here's a typedef anyway for
85 * general good practice.
86 */
87typedef unsigned char digit;
88#define ORDER_MAX 255
89
90#define TILE_SIZE 32
91#define BORDER 18
92
93#define FLASH_TIME 0.4F
94
ef57b17d 95enum { SYMM_NONE, SYMM_ROT2, SYMM_ROT4, SYMM_REF4 };
96
1d8e8ad8 97enum {
98 COL_BACKGROUND,
ef57b17d 99 COL_GRID,
100 COL_CLUE,
101 COL_USER,
102 COL_HIGHLIGHT,
103 NCOLOURS
1d8e8ad8 104};
105
106struct game_params {
ef57b17d 107 int c, r, symm;
1d8e8ad8 108};
109
110struct game_state {
111 int c, r;
112 digit *grid;
113 unsigned char *immutable; /* marks which digits are clues */
114 int completed;
115};
116
117static game_params *default_params(void)
118{
119 game_params *ret = snew(game_params);
120
121 ret->c = ret->r = 3;
ef57b17d 122 ret->symm = SYMM_ROT2; /* a plausible default */
1d8e8ad8 123
124 return ret;
125}
126
127static int game_fetch_preset(int i, char **name, game_params **params)
128{
129 game_params *ret;
130 int c, r;
131 char buf[80];
132
133 switch (i) {
134 case 0: c = 2, r = 2; break;
135 case 1: c = 2, r = 3; break;
136 case 2: c = 3, r = 3; break;
137 case 3: c = 3, r = 4; break;
138 case 4: c = 4, r = 4; break;
139 default: return FALSE;
140 }
141
142 sprintf(buf, "%dx%d", c, r);
143 *name = dupstr(buf);
144 *params = ret = snew(game_params);
145 ret->c = c;
146 ret->r = r;
ef57b17d 147 ret->symm = SYMM_ROT2;
1d8e8ad8 148 /* FIXME: difficulty presets? */
149 return TRUE;
150}
151
152static void free_params(game_params *params)
153{
154 sfree(params);
155}
156
157static game_params *dup_params(game_params *params)
158{
159 game_params *ret = snew(game_params);
160 *ret = *params; /* structure copy */
161 return ret;
162}
163
164static game_params *decode_params(char const *string)
165{
166 game_params *ret = default_params();
167
168 ret->c = ret->r = atoi(string);
ef57b17d 169 ret->symm = SYMM_ROT2;
1d8e8ad8 170 while (*string && isdigit((unsigned char)*string)) string++;
171 if (*string == 'x') {
172 string++;
173 ret->r = atoi(string);
174 while (*string && isdigit((unsigned char)*string)) string++;
175 }
ef57b17d 176 if (*string == 'r' || *string == 'm' || *string == 'a') {
177 int sn, sc;
178 sc = *string++;
179 sn = atoi(string);
180 while (*string && isdigit((unsigned char)*string)) string++;
181 if (sc == 'm' && sn == 4)
182 ret->symm = SYMM_REF4;
183 if (sc == 'r' && sn == 4)
184 ret->symm = SYMM_ROT4;
185 if (sc == 'r' && sn == 2)
186 ret->symm = SYMM_ROT2;
187 if (sc == 'a')
188 ret->symm = SYMM_NONE;
189 }
1d8e8ad8 190 /* FIXME: difficulty levels */
191
192 return ret;
193}
194
195static char *encode_params(game_params *params)
196{
197 char str[80];
198
ef57b17d 199 /*
200 * Symmetry is a game generation preference and hence is left
201 * out of the encoding. Users can add it back in as they see
202 * fit.
203 */
1d8e8ad8 204 sprintf(str, "%dx%d", params->c, params->r);
205 return dupstr(str);
206}
207
208static config_item *game_configure(game_params *params)
209{
210 config_item *ret;
211 char buf[80];
212
213 ret = snewn(5, config_item);
214
215 ret[0].name = "Columns of sub-blocks";
216 ret[0].type = C_STRING;
217 sprintf(buf, "%d", params->c);
218 ret[0].sval = dupstr(buf);
219 ret[0].ival = 0;
220
221 ret[1].name = "Rows of sub-blocks";
222 ret[1].type = C_STRING;
223 sprintf(buf, "%d", params->r);
224 ret[1].sval = dupstr(buf);
225 ret[1].ival = 0;
226
ef57b17d 227 ret[2].name = "Symmetry";
228 ret[2].type = C_CHOICES;
229 ret[2].sval = ":None:2-way rotation:4-way rotation:4-way mirror";
230 ret[2].ival = params->symm;
231
1d8e8ad8 232 /*
233 * FIXME: difficulty level.
234 */
235
ef57b17d 236 ret[3].name = NULL;
237 ret[3].type = C_END;
238 ret[3].sval = NULL;
239 ret[3].ival = 0;
1d8e8ad8 240
241 return ret;
242}
243
244static game_params *custom_params(config_item *cfg)
245{
246 game_params *ret = snew(game_params);
247
c1f743c8 248 ret->c = atoi(cfg[0].sval);
249 ret->r = atoi(cfg[1].sval);
ef57b17d 250 ret->symm = cfg[2].ival;
1d8e8ad8 251
252 return ret;
253}
254
255static char *validate_params(game_params *params)
256{
257 if (params->c < 2 || params->r < 2)
258 return "Both dimensions must be at least 2";
259 if (params->c > ORDER_MAX || params->r > ORDER_MAX)
260 return "Dimensions greater than "STR(ORDER_MAX)" are not supported";
261 return NULL;
262}
263
264/* ----------------------------------------------------------------------
265 * Full recursive Solo solver.
266 *
267 * The algorithm for this solver is shamelessly copied from a
268 * Python solver written by Andrew Wilkinson (which is GPLed, but
269 * I've reused only ideas and no code). It mostly just does the
270 * obvious recursive thing: pick an empty square, put one of the
271 * possible digits in it, recurse until all squares are filled,
272 * backtrack and change some choices if necessary.
273 *
274 * The clever bit is that every time it chooses which square to
275 * fill in next, it does so by counting the number of _possible_
276 * numbers that can go in each square, and it prioritises so that
277 * it picks a square with the _lowest_ number of possibilities. The
278 * idea is that filling in lots of the obvious bits (particularly
279 * any squares with only one possibility) will cut down on the list
280 * of possibilities for other squares and hence reduce the enormous
281 * search space as much as possible as early as possible.
282 *
283 * In practice the algorithm appeared to work very well; run on
284 * sample problems from the Times it completed in well under a
285 * second on my G5 even when written in Python, and given an empty
286 * grid (so that in principle it would enumerate _all_ solved
287 * grids!) it found the first valid solution just as quickly. So
288 * with a bit more randomisation I see no reason not to use this as
289 * my grid generator.
290 */
291
292/*
293 * Internal data structure used in solver to keep track of
294 * progress.
295 */
296struct rsolve_coord { int x, y, r; };
297struct rsolve_usage {
298 int c, r, cr; /* cr == c*r */
299 /* grid is a copy of the input grid, modified as we go along */
300 digit *grid;
301 /* row[y*cr+n-1] TRUE if digit n has been placed in row y */
302 unsigned char *row;
303 /* col[x*cr+n-1] TRUE if digit n has been placed in row x */
304 unsigned char *col;
305 /* blk[(y*c+x)*cr+n-1] TRUE if digit n has been placed in block (x,y) */
306 unsigned char *blk;
307 /* This lists all the empty spaces remaining in the grid. */
308 struct rsolve_coord *spaces;
309 int nspaces;
310 /* If we need randomisation in the solve, this is our random state. */
311 random_state *rs;
312 /* Number of solutions so far found, and maximum number we care about. */
313 int solns, maxsolns;
314};
315
316/*
317 * The real recursive step in the solving function.
318 */
319static void rsolve_real(struct rsolve_usage *usage, digit *grid)
320{
321 int c = usage->c, r = usage->r, cr = usage->cr;
322 int i, j, n, sx, sy, bestm, bestr;
323 int *digits;
324
325 /*
326 * Firstly, check for completion! If there are no spaces left
327 * in the grid, we have a solution.
328 */
329 if (usage->nspaces == 0) {
330 if (!usage->solns) {
331 /*
332 * This is our first solution, so fill in the output grid.
333 */
334 memcpy(grid, usage->grid, cr * cr);
335 }
336 usage->solns++;
337 return;
338 }
339
340 /*
341 * Otherwise, there must be at least one space. Find the most
342 * constrained space, using the `r' field as a tie-breaker.
343 */
344 bestm = cr+1; /* so that any space will beat it */
345 bestr = 0;
346 i = sx = sy = -1;
347 for (j = 0; j < usage->nspaces; j++) {
348 int x = usage->spaces[j].x, y = usage->spaces[j].y;
349 int m;
350
351 /*
352 * Find the number of digits that could go in this space.
353 */
354 m = 0;
355 for (n = 0; n < cr; n++)
356 if (!usage->row[y*cr+n] && !usage->col[x*cr+n] &&
357 !usage->blk[((y/c)*c+(x/r))*cr+n])
358 m++;
359
360 if (m < bestm || (m == bestm && usage->spaces[j].r < bestr)) {
361 bestm = m;
362 bestr = usage->spaces[j].r;
363 sx = x;
364 sy = y;
365 i = j;
366 }
367 }
368
369 /*
370 * Swap that square into the final place in the spaces array,
371 * so that decrementing nspaces will remove it from the list.
372 */
373 if (i != usage->nspaces-1) {
374 struct rsolve_coord t;
375 t = usage->spaces[usage->nspaces-1];
376 usage->spaces[usage->nspaces-1] = usage->spaces[i];
377 usage->spaces[i] = t;
378 }
379
380 /*
381 * Now we've decided which square to start our recursion at,
382 * simply go through all possible values, shuffling them
383 * randomly first if necessary.
384 */
385 digits = snewn(bestm, int);
386 j = 0;
387 for (n = 0; n < cr; n++)
388 if (!usage->row[sy*cr+n] && !usage->col[sx*cr+n] &&
389 !usage->blk[((sy/c)*c+(sx/r))*cr+n]) {
390 digits[j++] = n+1;
391 }
392
393 if (usage->rs) {
394 /* shuffle */
395 for (i = j; i > 1; i--) {
396 int p = random_upto(usage->rs, i);
397 if (p != i-1) {
398 int t = digits[p];
399 digits[p] = digits[i-1];
400 digits[i-1] = t;
401 }
402 }
403 }
404
405 /* And finally, go through the digit list and actually recurse. */
406 for (i = 0; i < j; i++) {
407 n = digits[i];
408
409 /* Update the usage structure to reflect the placing of this digit. */
410 usage->row[sy*cr+n-1] = usage->col[sx*cr+n-1] =
411 usage->blk[((sy/c)*c+(sx/r))*cr+n-1] = TRUE;
412 usage->grid[sy*cr+sx] = n;
413 usage->nspaces--;
414
415 /* Call the solver recursively. */
416 rsolve_real(usage, grid);
417
418 /*
419 * If we have seen as many solutions as we need, terminate
420 * all processing immediately.
421 */
422 if (usage->solns >= usage->maxsolns)
423 break;
424
425 /* Revert the usage structure. */
426 usage->row[sy*cr+n-1] = usage->col[sx*cr+n-1] =
427 usage->blk[((sy/c)*c+(sx/r))*cr+n-1] = FALSE;
428 usage->grid[sy*cr+sx] = 0;
429 usage->nspaces++;
430 }
431
432 sfree(digits);
433}
434
435/*
436 * Entry point to solver. You give it dimensions and a starting
437 * grid, which is simply an array of N^4 digits. In that array, 0
438 * means an empty square, and 1..N mean a clue square.
439 *
440 * Return value is the number of solutions found; searching will
441 * stop after the provided `max'. (Thus, you can pass max==1 to
442 * indicate that you only care about finding _one_ solution, or
443 * max==2 to indicate that you want to know the difference between
444 * a unique and non-unique solution.) The input parameter `grid' is
445 * also filled in with the _first_ (or only) solution found by the
446 * solver.
447 */
448static int rsolve(int c, int r, digit *grid, random_state *rs, int max)
449{
450 struct rsolve_usage *usage;
451 int x, y, cr = c*r;
452 int ret;
453
454 /*
455 * Create an rsolve_usage structure.
456 */
457 usage = snew(struct rsolve_usage);
458
459 usage->c = c;
460 usage->r = r;
461 usage->cr = cr;
462
463 usage->grid = snewn(cr * cr, digit);
464 memcpy(usage->grid, grid, cr * cr);
465
466 usage->row = snewn(cr * cr, unsigned char);
467 usage->col = snewn(cr * cr, unsigned char);
468 usage->blk = snewn(cr * cr, unsigned char);
469 memset(usage->row, FALSE, cr * cr);
470 memset(usage->col, FALSE, cr * cr);
471 memset(usage->blk, FALSE, cr * cr);
472
473 usage->spaces = snewn(cr * cr, struct rsolve_coord);
474 usage->nspaces = 0;
475
476 usage->solns = 0;
477 usage->maxsolns = max;
478
479 usage->rs = rs;
480
481 /*
482 * Now fill it in with data from the input grid.
483 */
484 for (y = 0; y < cr; y++) {
485 for (x = 0; x < cr; x++) {
486 int v = grid[y*cr+x];
487 if (v == 0) {
488 usage->spaces[usage->nspaces].x = x;
489 usage->spaces[usage->nspaces].y = y;
490 if (rs)
491 usage->spaces[usage->nspaces].r = random_bits(rs, 31);
492 else
493 usage->spaces[usage->nspaces].r = usage->nspaces;
494 usage->nspaces++;
495 } else {
496 usage->row[y*cr+v-1] = TRUE;
497 usage->col[x*cr+v-1] = TRUE;
498 usage->blk[((y/c)*c+(x/r))*cr+v-1] = TRUE;
499 }
500 }
501 }
502
503 /*
504 * Run the real recursive solving function.
505 */
506 rsolve_real(usage, grid);
507 ret = usage->solns;
508
509 /*
510 * Clean up the usage structure now we have our answer.
511 */
512 sfree(usage->spaces);
513 sfree(usage->blk);
514 sfree(usage->col);
515 sfree(usage->row);
516 sfree(usage->grid);
517 sfree(usage);
518
519 /*
520 * And return.
521 */
522 return ret;
523}
524
525/* ----------------------------------------------------------------------
526 * End of recursive solver code.
527 */
528
529/* ----------------------------------------------------------------------
530 * Less capable non-recursive solver. This one is used to check
531 * solubility of a grid as we gradually remove numbers from it: by
532 * verifying a grid using this solver we can ensure it isn't _too_
533 * hard (e.g. does not actually require guessing and backtracking).
534 *
535 * It supports a variety of specific modes of reasoning. By
536 * enabling or disabling subsets of these modes we can arrange a
537 * range of difficulty levels.
538 */
539
540/*
541 * Modes of reasoning currently supported:
542 *
543 * - Positional elimination: a number must go in a particular
544 * square because all the other empty squares in a given
545 * row/col/blk are ruled out.
546 *
547 * - Numeric elimination: a square must have a particular number
548 * in because all the other numbers that could go in it are
549 * ruled out.
550 *
551 * More advanced modes of reasoning I'd like to support in future:
552 *
553 * - Intersectional elimination: given two domains which overlap
554 * (hence one must be a block, and the other can be a row or
555 * col), if the possible locations for a particular number in
556 * one of the domains can be narrowed down to the overlap, then
557 * that number can be ruled out everywhere but the overlap in
558 * the other domain too.
559 *
560 * - Setwise numeric elimination: if there is a subset of the
561 * empty squares within a domain such that the union of the
562 * possible numbers in that subset has the same size as the
563 * subset itself, then those numbers can be ruled out everywhere
564 * else in the domain. (For example, if there are five empty
565 * squares and the possible numbers in each are 12, 23, 13, 134
566 * and 1345, then the first three empty squares form such a
567 * subset: the numbers 1, 2 and 3 _must_ be in those three
568 * squares in some permutation, and hence we can deduce none of
569 * them can be in the fourth or fifth squares.)
570 */
571
572struct nsolve_usage {
573 int c, r, cr;
574 /*
575 * We set up a cubic array, indexed by x, y and digit; each
576 * element of this array is TRUE or FALSE according to whether
577 * or not that digit _could_ in principle go in that position.
578 *
579 * The way to index this array is cube[(x*cr+y)*cr+n-1].
580 */
581 unsigned char *cube;
582 /*
583 * This is the grid in which we write down our final
584 * deductions.
585 */
586 digit *grid;
587 /*
588 * Now we keep track, at a slightly higher level, of what we
589 * have yet to work out, to prevent doing the same deduction
590 * many times.
591 */
592 /* row[y*cr+n-1] TRUE if digit n has been placed in row y */
593 unsigned char *row;
594 /* col[x*cr+n-1] TRUE if digit n has been placed in row x */
595 unsigned char *col;
596 /* blk[(y*c+x)*cr+n-1] TRUE if digit n has been placed in block (x,y) */
597 unsigned char *blk;
598};
599#define cube(x,y,n) (usage->cube[((x)*usage->cr+(y))*usage->cr+(n)-1])
600
601/*
602 * Function called when we are certain that a particular square has
603 * a particular number in it.
604 */
605static void nsolve_place(struct nsolve_usage *usage, int x, int y, int n)
606{
607 int c = usage->c, r = usage->r, cr = usage->cr;
608 int i, j, bx, by;
609
610 assert(cube(x,y,n));
611
612 /*
613 * Rule out all other numbers in this square.
614 */
615 for (i = 1; i <= cr; i++)
616 if (i != n)
617 cube(x,y,i) = FALSE;
618
619 /*
620 * Rule out this number in all other positions in the row.
621 */
622 for (i = 0; i < cr; i++)
623 if (i != y)
624 cube(x,i,n) = FALSE;
625
626 /*
627 * Rule out this number in all other positions in the column.
628 */
629 for (i = 0; i < cr; i++)
630 if (i != x)
631 cube(i,y,n) = FALSE;
632
633 /*
634 * Rule out this number in all other positions in the block.
635 */
636 bx = (x/r)*r;
637 by = (y/c)*c;
638 for (i = 0; i < r; i++)
639 for (j = 0; j < c; j++)
640 if (bx+i != x || by+j != y)
641 cube(bx+i,by+j,n) = FALSE;
642
643 /*
644 * Enter the number in the result grid.
645 */
646 usage->grid[y*cr+x] = n;
647
648 /*
649 * Cross out this number from the list of numbers left to place
650 * in its row, its column and its block.
651 */
652 usage->row[y*cr+n-1] = usage->col[x*cr+n-1] =
653 usage->blk[((y/c)*c+(x/r))*cr+n-1] = TRUE;
654}
655
656static int nsolve_blk_pos_elim(struct nsolve_usage *usage,
657 int x, int y, int n)
658{
659 int c = usage->c, r = usage->r;
660 int i, j, fx, fy, m;
661
662 x *= r;
663 y *= c;
664
665 /*
666 * Count the possible positions within this block where this
667 * number could appear.
668 */
669 m = 0;
670 fx = fy = -1;
671 for (i = 0; i < r; i++)
672 for (j = 0; j < c; j++)
673 if (cube(x+i,y+j,n)) {
674 fx = x+i;
675 fy = y+j;
676 m++;
677 }
678
679 if (m == 1) {
680 assert(fx >= 0 && fy >= 0);
681 nsolve_place(usage, fx, fy, n);
682 return TRUE;
683 }
684
685 return FALSE;
686}
687
688static int nsolve_row_pos_elim(struct nsolve_usage *usage,
689 int y, int n)
690{
691 int cr = usage->cr;
692 int x, fx, m;
693
694 /*
695 * Count the possible positions within this row where this
696 * number could appear.
697 */
698 m = 0;
699 fx = -1;
700 for (x = 0; x < cr; x++)
701 if (cube(x,y,n)) {
702 fx = x;
703 m++;
704 }
705
706 if (m == 1) {
707 assert(fx >= 0);
708 nsolve_place(usage, fx, y, n);
709 return TRUE;
710 }
711
712 return FALSE;
713}
714
715static int nsolve_col_pos_elim(struct nsolve_usage *usage,
716 int x, int n)
717{
718 int cr = usage->cr;
719 int y, fy, m;
720
721 /*
722 * Count the possible positions within this column where this
723 * number could appear.
724 */
725 m = 0;
726 fy = -1;
727 for (y = 0; y < cr; y++)
728 if (cube(x,y,n)) {
729 fy = y;
730 m++;
731 }
732
733 if (m == 1) {
734 assert(fy >= 0);
735 nsolve_place(usage, x, fy, n);
736 return TRUE;
737 }
738
739 return FALSE;
740}
741
742static int nsolve_num_elim(struct nsolve_usage *usage,
743 int x, int y)
744{
745 int cr = usage->cr;
746 int n, fn, m;
747
748 /*
749 * Count the possible numbers that could appear in this square.
750 */
751 m = 0;
752 fn = -1;
753 for (n = 1; n <= cr; n++)
754 if (cube(x,y,n)) {
755 fn = n;
756 m++;
757 }
758
759 if (m == 1) {
760 assert(fn > 0);
761 nsolve_place(usage, x, y, fn);
762 return TRUE;
763 }
764
765 return FALSE;
766}
767
768static int nsolve(int c, int r, digit *grid)
769{
770 struct nsolve_usage *usage;
771 int cr = c*r;
772 int x, y, n;
773
774 /*
775 * Set up a usage structure as a clean slate (everything
776 * possible).
777 */
778 usage = snew(struct nsolve_usage);
779 usage->c = c;
780 usage->r = r;
781 usage->cr = cr;
782 usage->cube = snewn(cr*cr*cr, unsigned char);
783 usage->grid = grid; /* write straight back to the input */
784 memset(usage->cube, TRUE, cr*cr*cr);
785
786 usage->row = snewn(cr * cr, unsigned char);
787 usage->col = snewn(cr * cr, unsigned char);
788 usage->blk = snewn(cr * cr, unsigned char);
789 memset(usage->row, FALSE, cr * cr);
790 memset(usage->col, FALSE, cr * cr);
791 memset(usage->blk, FALSE, cr * cr);
792
793 /*
794 * Place all the clue numbers we are given.
795 */
796 for (x = 0; x < cr; x++)
797 for (y = 0; y < cr; y++)
798 if (grid[y*cr+x])
799 nsolve_place(usage, x, y, grid[y*cr+x]);
800
801 /*
802 * Now loop over the grid repeatedly trying all permitted modes
803 * of reasoning. The loop terminates if we complete an
804 * iteration without making any progress; we then return
805 * failure or success depending on whether the grid is full or
806 * not.
807 */
808 while (1) {
809 /*
810 * Blockwise positional elimination.
811 */
812 for (x = 0; x < c; x++)
813 for (y = 0; y < r; y++)
814 for (n = 1; n <= cr; n++)
815 if (!usage->blk[((y/c)*c+(x/r))*cr+n-1] &&
816 nsolve_blk_pos_elim(usage, x, y, n))
817 continue;
818
819 /*
820 * Row-wise positional elimination.
821 */
822 for (y = 0; y < cr; y++)
823 for (n = 1; n <= cr; n++)
824 if (!usage->row[y*cr+n-1] &&
825 nsolve_row_pos_elim(usage, y, n))
826 continue;
827 /*
828 * Column-wise positional elimination.
829 */
830 for (x = 0; x < cr; x++)
831 for (n = 1; n <= cr; n++)
832 if (!usage->col[x*cr+n-1] &&
833 nsolve_col_pos_elim(usage, x, n))
834 continue;
835
836 /*
837 * Numeric elimination.
838 */
839 for (x = 0; x < cr; x++)
840 for (y = 0; y < cr; y++)
841 if (!usage->grid[y*cr+x] &&
842 nsolve_num_elim(usage, x, y))
843 continue;
844
845 /*
846 * If we reach here, we have made no deductions in this
847 * iteration, so the algorithm terminates.
848 */
849 break;
850 }
851
852 sfree(usage->cube);
853 sfree(usage->row);
854 sfree(usage->col);
855 sfree(usage->blk);
856 sfree(usage);
857
858 for (x = 0; x < cr; x++)
859 for (y = 0; y < cr; y++)
860 if (!grid[y*cr+x])
861 return FALSE;
862 return TRUE;
863}
864
865/* ----------------------------------------------------------------------
866 * End of non-recursive solver code.
867 */
868
869/*
870 * Check whether a grid contains a valid complete puzzle.
871 */
872static int check_valid(int c, int r, digit *grid)
873{
874 int cr = c*r;
875 unsigned char *used;
876 int x, y, n;
877
878 used = snewn(cr, unsigned char);
879
880 /*
881 * Check that each row contains precisely one of everything.
882 */
883 for (y = 0; y < cr; y++) {
884 memset(used, FALSE, cr);
885 for (x = 0; x < cr; x++)
886 if (grid[y*cr+x] > 0 && grid[y*cr+x] <= cr)
887 used[grid[y*cr+x]-1] = TRUE;
888 for (n = 0; n < cr; n++)
889 if (!used[n]) {
890 sfree(used);
891 return FALSE;
892 }
893 }
894
895 /*
896 * Check that each column contains precisely one of everything.
897 */
898 for (x = 0; x < cr; x++) {
899 memset(used, FALSE, cr);
900 for (y = 0; y < cr; y++)
901 if (grid[y*cr+x] > 0 && grid[y*cr+x] <= cr)
902 used[grid[y*cr+x]-1] = TRUE;
903 for (n = 0; n < cr; n++)
904 if (!used[n]) {
905 sfree(used);
906 return FALSE;
907 }
908 }
909
910 /*
911 * Check that each block contains precisely one of everything.
912 */
913 for (x = 0; x < cr; x += r) {
914 for (y = 0; y < cr; y += c) {
915 int xx, yy;
916 memset(used, FALSE, cr);
917 for (xx = x; xx < x+r; xx++)
918 for (yy = 0; yy < y+c; yy++)
919 if (grid[yy*cr+xx] > 0 && grid[yy*cr+xx] <= cr)
920 used[grid[yy*cr+xx]-1] = TRUE;
921 for (n = 0; n < cr; n++)
922 if (!used[n]) {
923 sfree(used);
924 return FALSE;
925 }
926 }
927 }
928
929 sfree(used);
930 return TRUE;
931}
932
ef57b17d 933static void symmetry_limit(game_params *params, int *xlim, int *ylim, int s)
934{
935 int c = params->c, r = params->r, cr = c*r;
936
937 switch (s) {
938 case SYMM_NONE:
939 *xlim = *ylim = cr;
940 break;
941 case SYMM_ROT2:
942 *xlim = (cr+1) / 2;
943 *ylim = cr;
944 break;
945 case SYMM_REF4:
946 case SYMM_ROT4:
947 *xlim = *ylim = (cr+1) / 2;
948 break;
949 }
950}
951
952static int symmetries(game_params *params, int x, int y, int *output, int s)
953{
954 int c = params->c, r = params->r, cr = c*r;
955 int i = 0;
956
957 *output++ = x;
958 *output++ = y;
959 i++;
960
961 switch (s) {
962 case SYMM_NONE:
963 break; /* just x,y is all we need */
964 case SYMM_REF4:
965 case SYMM_ROT4:
966 switch (s) {
967 case SYMM_REF4:
968 *output++ = cr - 1 - x;
969 *output++ = y;
970 i++;
971
972 *output++ = x;
973 *output++ = cr - 1 - y;
974 i++;
975 break;
976 case SYMM_ROT4:
977 *output++ = cr - 1 - y;
978 *output++ = x;
979 i++;
980
981 *output++ = y;
982 *output++ = cr - 1 - x;
983 i++;
984 break;
985 }
986 /* fall through */
987 case SYMM_ROT2:
988 *output++ = cr - 1 - x;
989 *output++ = cr - 1 - y;
990 i++;
991 break;
992 }
993
994 return i;
995}
996
1d8e8ad8 997static char *new_game_seed(game_params *params, random_state *rs)
998{
999 int c = params->c, r = params->r, cr = c*r;
1000 int area = cr*cr;
1001 digit *grid, *grid2;
1002 struct xy { int x, y; } *locs;
1003 int nlocs;
1004 int ret;
1005 char *seed;
ef57b17d 1006 int coords[16], ncoords;
1007 int xlim, ylim;
1d8e8ad8 1008
1009 /*
1010 * Start the recursive solver with an empty grid to generate a
1011 * random solved state.
1012 */
1013 grid = snewn(area, digit);
1014 memset(grid, 0, area);
1015 ret = rsolve(c, r, grid, rs, 1);
1016 assert(ret == 1);
1017 assert(check_valid(c, r, grid));
1018
1019#ifdef DEBUG
1020 memcpy(grid,
1021 "\x0\x1\x0\x0\x6\x0\x0\x0\x0"
1022 "\x5\x0\x0\x7\x0\x4\x0\x2\x0"
1023 "\x0\x0\x6\x1\x0\x0\x0\x0\x0"
1024 "\x8\x9\x7\x0\x0\x0\x0\x0\x0"
1025 "\x0\x0\x3\x0\x4\x0\x9\x0\x0"
1026 "\x0\x0\x0\x0\x0\x0\x8\x7\x6"
1027 "\x0\x0\x0\x0\x0\x9\x1\x0\x0"
1028 "\x0\x3\x0\x6\x0\x5\x0\x0\x7"
1029 "\x0\x0\x0\x0\x8\x0\x0\x5\x0"
1030 , area);
1031
1032 {
1033 int y, x;
1034 for (y = 0; y < cr; y++) {
1035 for (x = 0; x < cr; x++) {
1036 printf("%2.0d", grid[y*cr+x]);
1037 }
1038 printf("\n");
1039 }
1040 printf("\n");
1041 }
1042
1043 nsolve(c, r, grid);
1044
1045 {
1046 int y, x;
1047 for (y = 0; y < cr; y++) {
1048 for (x = 0; x < cr; x++) {
1049 printf("%2.0d", grid[y*cr+x]);
1050 }
1051 printf("\n");
1052 }
1053 printf("\n");
1054 }
1055#endif
1056
1057 /*
1058 * Now we have a solved grid, start removing things from it
1059 * while preserving solubility.
1060 */
ef57b17d 1061 locs = snewn(area, struct xy);
1d8e8ad8 1062 grid2 = snewn(area, digit);
ef57b17d 1063 symmetry_limit(params, &xlim, &ylim, params->symm);
1d8e8ad8 1064 while (1) {
ef57b17d 1065 int x, y, i, j;
1d8e8ad8 1066
1067 /*
ef57b17d 1068 * Iterate over the grid and enumerate all the filled
1069 * squares we could empty.
1d8e8ad8 1070 */
1071 nlocs = 0;
1072
ef57b17d 1073 for (x = 0; x < xlim; x++)
1074 for (y = 0; y < ylim; y++)
1d8e8ad8 1075 if (grid[y*cr+x]) {
1076 locs[nlocs].x = x;
1077 locs[nlocs].y = y;
1078 nlocs++;
1079 }
1080
1081 /*
1082 * Now shuffle that list.
1083 */
1084 for (i = nlocs; i > 1; i--) {
1085 int p = random_upto(rs, i);
1086 if (p != i-1) {
1087 struct xy t = locs[p];
1088 locs[p] = locs[i-1];
1089 locs[i-1] = t;
1090 }
1091 }
1092
1093 /*
1094 * Now loop over the shuffled list and, for each element,
1095 * see whether removing that element (and its reflections)
1096 * from the grid will still leave the grid soluble by
1097 * nsolve.
1098 */
1099 for (i = 0; i < nlocs; i++) {
1100 x = locs[i].x;
1101 y = locs[i].y;
1102
1103 memcpy(grid2, grid, area);
ef57b17d 1104 ncoords = symmetries(params, x, y, coords, params->symm);
1105 for (j = 0; j < ncoords; j++)
1106 grid2[coords[2*j+1]*cr+coords[2*j]] = 0;
1d8e8ad8 1107
1108 if (nsolve(c, r, grid2)) {
ef57b17d 1109 for (j = 0; j < ncoords; j++)
1110 grid[coords[2*j+1]*cr+coords[2*j]] = 0;
1d8e8ad8 1111 break;
1112 }
1113 }
1114
1115 if (i == nlocs) {
1116 /*
1117 * There was nothing we could remove without destroying
1118 * solvability.
1119 */
1120 break;
1121 }
1122 }
1123 sfree(grid2);
1124 sfree(locs);
1125
1126#ifdef DEBUG
1127 {
1128 int y, x;
1129 for (y = 0; y < cr; y++) {
1130 for (x = 0; x < cr; x++) {
1131 printf("%2.0d", grid[y*cr+x]);
1132 }
1133 printf("\n");
1134 }
1135 printf("\n");
1136 }
1137#endif
1138
1139 /*
1140 * Now we have the grid as it will be presented to the user.
1141 * Encode it in a game seed.
1142 */
1143 {
1144 char *p;
1145 int run, i;
1146
1147 seed = snewn(5 * area, char);
1148 p = seed;
1149 run = 0;
1150 for (i = 0; i <= area; i++) {
1151 int n = (i < area ? grid[i] : -1);
1152
1153 if (!n)
1154 run++;
1155 else {
1156 if (run) {
1157 while (run > 0) {
1158 int c = 'a' - 1 + run;
1159 if (run > 26)
1160 c = 'z';
1161 *p++ = c;
1162 run -= c - ('a' - 1);
1163 }
1164 } else {
1165 /*
1166 * If there's a number in the very top left or
1167 * bottom right, there's no point putting an
1168 * unnecessary _ before or after it.
1169 */
1170 if (p > seed && n > 0)
1171 *p++ = '_';
1172 }
1173 if (n > 0)
1174 p += sprintf(p, "%d", n);
1175 run = 0;
1176 }
1177 }
1178 assert(p - seed < 5 * area);
1179 *p++ = '\0';
1180 seed = sresize(seed, p - seed, char);
1181 }
1182
1183 sfree(grid);
1184
1185 return seed;
1186}
1187
1188static char *validate_seed(game_params *params, char *seed)
1189{
1190 int area = params->r * params->r * params->c * params->c;
1191 int squares = 0;
1192
1193 while (*seed) {
1194 int n = *seed++;
1195 if (n >= 'a' && n <= 'z') {
1196 squares += n - 'a' + 1;
1197 } else if (n == '_') {
1198 /* do nothing */;
1199 } else if (n > '0' && n <= '9') {
1200 squares++;
1201 while (*seed >= '0' && *seed <= '9')
1202 seed++;
1203 } else
1204 return "Invalid character in game specification";
1205 }
1206
1207 if (squares < area)
1208 return "Not enough data to fill grid";
1209
1210 if (squares > area)
1211 return "Too much data to fit in grid";
1212
1213 return NULL;
1214}
1215
1216static game_state *new_game(game_params *params, char *seed)
1217{
1218 game_state *state = snew(game_state);
1219 int c = params->c, r = params->r, cr = c*r, area = cr * cr;
1220 int i;
1221
1222 state->c = params->c;
1223 state->r = params->r;
1224
1225 state->grid = snewn(area, digit);
1226 state->immutable = snewn(area, unsigned char);
1227 memset(state->immutable, FALSE, area);
1228
1229 state->completed = FALSE;
1230
1231 i = 0;
1232 while (*seed) {
1233 int n = *seed++;
1234 if (n >= 'a' && n <= 'z') {
1235 int run = n - 'a' + 1;
1236 assert(i + run <= area);
1237 while (run-- > 0)
1238 state->grid[i++] = 0;
1239 } else if (n == '_') {
1240 /* do nothing */;
1241 } else if (n > '0' && n <= '9') {
1242 assert(i < area);
1243 state->immutable[i] = TRUE;
1244 state->grid[i++] = atoi(seed-1);
1245 while (*seed >= '0' && *seed <= '9')
1246 seed++;
1247 } else {
1248 assert(!"We can't get here");
1249 }
1250 }
1251 assert(i == area);
1252
1253 return state;
1254}
1255
1256static game_state *dup_game(game_state *state)
1257{
1258 game_state *ret = snew(game_state);
1259 int c = state->c, r = state->r, cr = c*r, area = cr * cr;
1260
1261 ret->c = state->c;
1262 ret->r = state->r;
1263
1264 ret->grid = snewn(area, digit);
1265 memcpy(ret->grid, state->grid, area);
1266
1267 ret->immutable = snewn(area, unsigned char);
1268 memcpy(ret->immutable, state->immutable, area);
1269
1270 ret->completed = state->completed;
1271
1272 return ret;
1273}
1274
1275static void free_game(game_state *state)
1276{
1277 sfree(state->immutable);
1278 sfree(state->grid);
1279 sfree(state);
1280}
1281
1282struct game_ui {
1283 /*
1284 * These are the coordinates of the currently highlighted
1285 * square on the grid, or -1,-1 if there isn't one. When there
1286 * is, pressing a valid number or letter key or Space will
1287 * enter that number or letter in the grid.
1288 */
1289 int hx, hy;
1290};
1291
1292static game_ui *new_ui(game_state *state)
1293{
1294 game_ui *ui = snew(game_ui);
1295
1296 ui->hx = ui->hy = -1;
1297
1298 return ui;
1299}
1300
1301static void free_ui(game_ui *ui)
1302{
1303 sfree(ui);
1304}
1305
1306static game_state *make_move(game_state *from, game_ui *ui, int x, int y,
1307 int button)
1308{
1309 int c = from->c, r = from->r, cr = c*r;
1310 int tx, ty;
1311 game_state *ret;
1312
1313 tx = (x - BORDER) / TILE_SIZE;
1314 ty = (y - BORDER) / TILE_SIZE;
1315
1316 if (tx >= 0 && tx < cr && ty >= 0 && ty < cr && button == LEFT_BUTTON) {
1317 if (tx == ui->hx && ty == ui->hy) {
1318 ui->hx = ui->hy = -1;
1319 } else {
1320 ui->hx = tx;
1321 ui->hy = ty;
1322 }
1323 return from; /* UI activity occurred */
1324 }
1325
1326 if (ui->hx != -1 && ui->hy != -1 &&
1327 ((button >= '1' && button <= '9' && button - '0' <= cr) ||
1328 (button >= 'a' && button <= 'z' && button - 'a' + 10 <= cr) ||
1329 (button >= 'A' && button <= 'Z' && button - 'A' + 10 <= cr) ||
1330 button == ' ')) {
1331 int n = button - '0';
1332 if (button >= 'A' && button <= 'Z')
1333 n = button - 'A' + 10;
1334 if (button >= 'a' && button <= 'z')
1335 n = button - 'a' + 10;
1336 if (button == ' ')
1337 n = 0;
1338
1339 if (from->immutable[ui->hy*cr+ui->hx])
1340 return NULL; /* can't overwrite this square */
1341
1342 ret = dup_game(from);
1343 ret->grid[ui->hy*cr+ui->hx] = n;
1344 ui->hx = ui->hy = -1;
1345
1346 /*
1347 * We've made a real change to the grid. Check to see
1348 * if the game has been completed.
1349 */
1350 if (!ret->completed && check_valid(c, r, ret->grid)) {
1351 ret->completed = TRUE;
1352 }
1353
1354 return ret; /* made a valid move */
1355 }
1356
1357 return NULL;
1358}
1359
1360/* ----------------------------------------------------------------------
1361 * Drawing routines.
1362 */
1363
1364struct game_drawstate {
1365 int started;
1366 int c, r, cr;
1367 digit *grid;
1368 unsigned char *hl;
1369};
1370
1371#define XSIZE(cr) ((cr) * TILE_SIZE + 2*BORDER + 1)
1372#define YSIZE(cr) ((cr) * TILE_SIZE + 2*BORDER + 1)
1373
1374static void game_size(game_params *params, int *x, int *y)
1375{
1376 int c = params->c, r = params->r, cr = c*r;
1377
1378 *x = XSIZE(cr);
1379 *y = YSIZE(cr);
1380}
1381
1382static float *game_colours(frontend *fe, game_state *state, int *ncolours)
1383{
1384 float *ret = snewn(3 * NCOLOURS, float);
1385
1386 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
1387
1388 ret[COL_GRID * 3 + 0] = 0.0F;
1389 ret[COL_GRID * 3 + 1] = 0.0F;
1390 ret[COL_GRID * 3 + 2] = 0.0F;
1391
1392 ret[COL_CLUE * 3 + 0] = 0.0F;
1393 ret[COL_CLUE * 3 + 1] = 0.0F;
1394 ret[COL_CLUE * 3 + 2] = 0.0F;
1395
1396 ret[COL_USER * 3 + 0] = 0.0F;
1397 ret[COL_USER * 3 + 1] = 0.6F * ret[COL_BACKGROUND * 3 + 1];
1398 ret[COL_USER * 3 + 2] = 0.0F;
1399
1400 ret[COL_HIGHLIGHT * 3 + 0] = 0.85F * ret[COL_BACKGROUND * 3 + 0];
1401 ret[COL_HIGHLIGHT * 3 + 1] = 0.85F * ret[COL_BACKGROUND * 3 + 1];
1402 ret[COL_HIGHLIGHT * 3 + 2] = 0.85F * ret[COL_BACKGROUND * 3 + 2];
1403
1404 *ncolours = NCOLOURS;
1405 return ret;
1406}
1407
1408static game_drawstate *game_new_drawstate(game_state *state)
1409{
1410 struct game_drawstate *ds = snew(struct game_drawstate);
1411 int c = state->c, r = state->r, cr = c*r;
1412
1413 ds->started = FALSE;
1414 ds->c = c;
1415 ds->r = r;
1416 ds->cr = cr;
1417 ds->grid = snewn(cr*cr, digit);
1418 memset(ds->grid, 0, cr*cr);
1419 ds->hl = snewn(cr*cr, unsigned char);
1420 memset(ds->hl, 0, cr*cr);
1421
1422 return ds;
1423}
1424
1425static void game_free_drawstate(game_drawstate *ds)
1426{
1427 sfree(ds->hl);
1428 sfree(ds->grid);
1429 sfree(ds);
1430}
1431
1432static void draw_number(frontend *fe, game_drawstate *ds, game_state *state,
1433 int x, int y, int hl)
1434{
1435 int c = state->c, r = state->r, cr = c*r;
1436 int tx, ty;
1437 int cx, cy, cw, ch;
1438 char str[2];
1439
1440 if (ds->grid[y*cr+x] == state->grid[y*cr+x] && ds->hl[y*cr+x] == hl)
1441 return; /* no change required */
1442
1443 tx = BORDER + x * TILE_SIZE + 2;
1444 ty = BORDER + y * TILE_SIZE + 2;
1445
1446 cx = tx;
1447 cy = ty;
1448 cw = TILE_SIZE-3;
1449 ch = TILE_SIZE-3;
1450
1451 if (x % r)
1452 cx--, cw++;
1453 if ((x+1) % r)
1454 cw++;
1455 if (y % c)
1456 cy--, ch++;
1457 if ((y+1) % c)
1458 ch++;
1459
1460 clip(fe, cx, cy, cw, ch);
1461
1462 /* background needs erasing? */
1463 if (ds->grid[y*cr+x] || ds->hl[y*cr+x] != hl)
1464 draw_rect(fe, cx, cy, cw, ch, hl ? COL_HIGHLIGHT : COL_BACKGROUND);
1465
1466 /* new number needs drawing? */
1467 if (state->grid[y*cr+x]) {
1468 str[1] = '\0';
1469 str[0] = state->grid[y*cr+x] + '0';
1470 if (str[0] > '9')
1471 str[0] += 'a' - ('9'+1);
1472 draw_text(fe, tx + TILE_SIZE/2, ty + TILE_SIZE/2,
1473 FONT_VARIABLE, TILE_SIZE/2, ALIGN_VCENTRE | ALIGN_HCENTRE,
1474 state->immutable[y*cr+x] ? COL_CLUE : COL_USER, str);
1475 }
1476
1477 unclip(fe);
1478
1479 draw_update(fe, cx, cy, cw, ch);
1480
1481 ds->grid[y*cr+x] = state->grid[y*cr+x];
1482 ds->hl[y*cr+x] = hl;
1483}
1484
1485static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
1486 game_state *state, int dir, game_ui *ui,
1487 float animtime, float flashtime)
1488{
1489 int c = state->c, r = state->r, cr = c*r;
1490 int x, y;
1491
1492 if (!ds->started) {
1493 /*
1494 * The initial contents of the window are not guaranteed
1495 * and can vary with front ends. To be on the safe side,
1496 * all games should start by drawing a big
1497 * background-colour rectangle covering the whole window.
1498 */
1499 draw_rect(fe, 0, 0, XSIZE(cr), YSIZE(cr), COL_BACKGROUND);
1500
1501 /*
1502 * Draw the grid.
1503 */
1504 for (x = 0; x <= cr; x++) {
1505 int thick = (x % r ? 0 : 1);
1506 draw_rect(fe, BORDER + x*TILE_SIZE - thick, BORDER-1,
1507 1+2*thick, cr*TILE_SIZE+3, COL_GRID);
1508 }
1509 for (y = 0; y <= cr; y++) {
1510 int thick = (y % c ? 0 : 1);
1511 draw_rect(fe, BORDER-1, BORDER + y*TILE_SIZE - thick,
1512 cr*TILE_SIZE+3, 1+2*thick, COL_GRID);
1513 }
1514 }
1515
1516 /*
1517 * Draw any numbers which need redrawing.
1518 */
1519 for (x = 0; x < cr; x++) {
1520 for (y = 0; y < cr; y++) {
1521 draw_number(fe, ds, state, x, y,
1522 (x == ui->hx && y == ui->hy) ||
1523 (flashtime > 0 &&
1524 (flashtime <= FLASH_TIME/3 ||
1525 flashtime >= FLASH_TIME*2/3)));
1526 }
1527 }
1528
1529 /*
1530 * Update the _entire_ grid if necessary.
1531 */
1532 if (!ds->started) {
1533 draw_update(fe, 0, 0, XSIZE(cr), YSIZE(cr));
1534 ds->started = TRUE;
1535 }
1536}
1537
1538static float game_anim_length(game_state *oldstate, game_state *newstate,
1539 int dir)
1540{
1541 return 0.0F;
1542}
1543
1544static float game_flash_length(game_state *oldstate, game_state *newstate,
1545 int dir)
1546{
1547 if (!oldstate->completed && newstate->completed)
1548 return FLASH_TIME;
1549 return 0.0F;
1550}
1551
1552static int game_wants_statusbar(void)
1553{
1554 return FALSE;
1555}
1556
1557#ifdef COMBINED
1558#define thegame solo
1559#endif
1560
1561const struct game thegame = {
1562 "Solo", "games.solo", TRUE,
1563 default_params,
1564 game_fetch_preset,
1565 decode_params,
1566 encode_params,
1567 free_params,
1568 dup_params,
1569 game_configure,
1570 custom_params,
1571 validate_params,
1572 new_game_seed,
1573 validate_seed,
1574 new_game,
1575 dup_game,
1576 free_game,
1577 new_ui,
1578 free_ui,
1579 make_move,
1580 game_size,
1581 game_colours,
1582 game_new_drawstate,
1583 game_free_drawstate,
1584 game_redraw,
1585 game_anim_length,
1586 game_flash_length,
1587 game_wants_statusbar,
1588};