Imported Upstream version 8278
[sgt-puzzles/ydirson.git] / mines.c
blob431cc08f049133675765ce1633d0dcd9b09e193c
1 /*
2 * mines.c: Minesweeper clone with sophisticated grid generation.
3 *
4 * Still TODO:
6 * - think about configurably supporting question marks. Once,
7 * that is, we've thought about configurability in general!
8 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <assert.h>
14 #include <ctype.h>
15 #include <math.h>
17 #include "tree234.h"
18 #include "puzzles.h"
20 enum {
21 COL_BACKGROUND, COL_BACKGROUND2,
22 COL_1, COL_2, COL_3, COL_4, COL_5, COL_6, COL_7, COL_8,
23 COL_MINE, COL_BANG, COL_CROSS, COL_FLAG, COL_FLAGBASE, COL_QUERY,
24 COL_HIGHLIGHT, COL_LOWLIGHT,
25 COL_WRONGNUMBER,
26 NCOLOURS
29 #define PREFERRED_TILE_SIZE 20
30 #define TILE_SIZE (ds->tilesize)
31 #ifdef SMALL_SCREEN
32 #define BORDER 8
33 #else
34 #define BORDER (TILE_SIZE * 3 / 2)
35 #endif
36 #define HIGHLIGHT_WIDTH (TILE_SIZE / 10)
37 #define OUTER_HIGHLIGHT_WIDTH (BORDER / 10)
38 #define COORD(x) ( (x) * TILE_SIZE + BORDER )
39 #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 )
41 #define FLASH_FRAME 0.13F
43 struct game_params {
44 int w, h, n;
45 int unique;
48 struct mine_layout {
50 * This structure is shared between all the game_states for a
51 * given instance of the puzzle, so we reference-count it.
53 int refcount;
54 char *mines;
56 * If we haven't yet actually generated the mine layout, here's
57 * all the data we will need to do so.
59 int n, unique;
60 random_state *rs;
61 midend *me; /* to give back the new game desc */
64 struct game_state {
65 int w, h, n, dead, won;
66 int used_solve;
67 struct mine_layout *layout; /* real mine positions */
68 signed char *grid; /* player knowledge */
70 * Each item in the `grid' array is one of the following values:
72 * - 0 to 8 mean the square is open and has a surrounding mine
73 * count.
75 * - -1 means the square is marked as a mine.
77 * - -2 means the square is unknown.
79 * - -3 means the square is marked with a question mark
80 * (FIXME: do we even want to bother with this?).
82 * - 64 means the square has had a mine revealed when the game
83 * was lost.
85 * - 65 means the square had a mine revealed and this was the
86 * one the player hits.
88 * - 66 means the square has a crossed-out mine because the
89 * player had incorrectly marked it.
93 static game_params *default_params(void)
95 game_params *ret = snew(game_params);
97 ret->w = ret->h = 9;
98 ret->n = 10;
99 ret->unique = TRUE;
101 return ret;
104 static const struct game_params mines_presets[] = {
105 {9, 9, 10, TRUE},
106 {9, 9, 35, TRUE},
107 {16, 16, 40, TRUE},
108 {16, 16, 99, TRUE},
109 #ifndef SMALL_SCREEN
110 {30, 16, 99, TRUE},
111 {30, 16, 170, TRUE},
112 #endif
115 static int game_fetch_preset(int i, char **name, game_params **params)
117 game_params *ret;
118 char str[80];
120 if (i < 0 || i >= lenof(mines_presets))
121 return FALSE;
123 ret = snew(game_params);
124 *ret = mines_presets[i];
126 sprintf(str, "%dx%d, %d mines", ret->w, ret->h, ret->n);
128 *name = dupstr(str);
129 *params = ret;
130 return TRUE;
133 static void free_params(game_params *params)
135 sfree(params);
138 static game_params *dup_params(game_params *params)
140 game_params *ret = snew(game_params);
141 *ret = *params; /* structure copy */
142 return ret;
145 static void decode_params(game_params *params, char const *string)
147 char const *p = string;
149 params->w = atoi(p);
150 while (*p && isdigit((unsigned char)*p)) p++;
151 if (*p == 'x') {
152 p++;
153 params->h = atoi(p);
154 while (*p && isdigit((unsigned char)*p)) p++;
155 } else {
156 params->h = params->w;
158 if (*p == 'n') {
159 p++;
160 params->n = atoi(p);
161 while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++;
162 } else {
163 params->n = params->w * params->h / 10;
166 while (*p) {
167 if (*p == 'a') {
168 p++;
169 params->unique = FALSE;
170 } else
171 p++; /* skip any other gunk */
175 static char *encode_params(game_params *params, int full)
177 char ret[400];
178 int len;
180 len = sprintf(ret, "%dx%d", params->w, params->h);
182 * Mine count is a generation-time parameter, since it can be
183 * deduced from the mine bitmap!
185 if (full)
186 len += sprintf(ret+len, "n%d", params->n);
187 if (full && !params->unique)
188 ret[len++] = 'a';
189 assert(len < lenof(ret));
190 ret[len] = '\0';
192 return dupstr(ret);
195 static config_item *game_configure(game_params *params)
197 config_item *ret;
198 char buf[80];
200 ret = snewn(5, config_item);
202 ret[0].name = "Width";
203 ret[0].type = C_STRING;
204 sprintf(buf, "%d", params->w);
205 ret[0].sval = dupstr(buf);
206 ret[0].ival = 0;
208 ret[1].name = "Height";
209 ret[1].type = C_STRING;
210 sprintf(buf, "%d", params->h);
211 ret[1].sval = dupstr(buf);
212 ret[1].ival = 0;
214 ret[2].name = "Mines";
215 ret[2].type = C_STRING;
216 sprintf(buf, "%d", params->n);
217 ret[2].sval = dupstr(buf);
218 ret[2].ival = 0;
220 ret[3].name = "Ensure solubility";
221 ret[3].type = C_BOOLEAN;
222 ret[3].sval = NULL;
223 ret[3].ival = params->unique;
225 ret[4].name = NULL;
226 ret[4].type = C_END;
227 ret[4].sval = NULL;
228 ret[4].ival = 0;
230 return ret;
233 static game_params *custom_params(config_item *cfg)
235 game_params *ret = snew(game_params);
237 ret->w = atoi(cfg[0].sval);
238 ret->h = atoi(cfg[1].sval);
239 ret->n = atoi(cfg[2].sval);
240 if (strchr(cfg[2].sval, '%'))
241 ret->n = ret->n * (ret->w * ret->h) / 100;
242 ret->unique = cfg[3].ival;
244 return ret;
247 static char *validate_params(game_params *params, int full)
250 * Lower limit on grid size: each dimension must be at least 3.
251 * 1 is theoretically workable if rather boring, but 2 is a
252 * real problem: there is often _no_ way to generate a uniquely
253 * solvable 2xn Mines grid. You either run into two mines
254 * blocking the way and no idea what's behind them, or one mine
255 * and no way to know which of the two rows it's in. If the
256 * mine count is even you can create a soluble grid by packing
257 * all the mines at one end (so what when you hit a two-mine
258 * wall there are only as many covered squares left as there
259 * are mines); but if it's odd, you are doomed, because you
260 * _have_ to have a gap somewhere which you can't determine the
261 * position of.
263 if (full && params->unique && (params->w <= 2 || params->h <= 2))
264 return "Width and height must both be greater than two";
265 if (params->n > params->w * params->h - 9)
266 return "Too many mines for grid size";
269 * FIXME: Need more constraints here. Not sure what the
270 * sensible limits for Minesweeper actually are. The limits
271 * probably ought to change, however, depending on uniqueness.
274 return NULL;
277 /* ----------------------------------------------------------------------
278 * Minesweeper solver, used to ensure the generated grids are
279 * solvable without having to take risks.
283 * Count the bits in a word. Only needs to cope with 16 bits.
285 static int bitcount16(int inword)
287 unsigned int word = inword;
289 word = ((word & 0xAAAA) >> 1) + (word & 0x5555);
290 word = ((word & 0xCCCC) >> 2) + (word & 0x3333);
291 word = ((word & 0xF0F0) >> 4) + (word & 0x0F0F);
292 word = ((word & 0xFF00) >> 8) + (word & 0x00FF);
294 return (int)word;
298 * We use a tree234 to store a large number of small localised
299 * sets, each with a mine count. We also keep some of those sets
300 * linked together into a to-do list.
302 struct set {
303 short x, y, mask, mines;
304 int todo;
305 struct set *prev, *next;
308 static int setcmp(void *av, void *bv)
310 struct set *a = (struct set *)av;
311 struct set *b = (struct set *)bv;
313 if (a->y < b->y)
314 return -1;
315 else if (a->y > b->y)
316 return +1;
317 else if (a->x < b->x)
318 return -1;
319 else if (a->x > b->x)
320 return +1;
321 else if (a->mask < b->mask)
322 return -1;
323 else if (a->mask > b->mask)
324 return +1;
325 else
326 return 0;
329 struct setstore {
330 tree234 *sets;
331 struct set *todo_head, *todo_tail;
334 static struct setstore *ss_new(void)
336 struct setstore *ss = snew(struct setstore);
337 ss->sets = newtree234(setcmp);
338 ss->todo_head = ss->todo_tail = NULL;
339 return ss;
343 * Take two input sets, in the form (x,y,mask). Munge the first by
344 * taking either its intersection with the second or its difference
345 * with the second. Return the new mask part of the first set.
347 static int setmunge(int x1, int y1, int mask1, int x2, int y2, int mask2,
348 int diff)
351 * Adjust the second set so that it has the same x,y
352 * coordinates as the first.
354 if (abs(x2-x1) >= 3 || abs(y2-y1) >= 3) {
355 mask2 = 0;
356 } else {
357 while (x2 > x1) {
358 mask2 &= ~(4|32|256);
359 mask2 <<= 1;
360 x2--;
362 while (x2 < x1) {
363 mask2 &= ~(1|8|64);
364 mask2 >>= 1;
365 x2++;
367 while (y2 > y1) {
368 mask2 &= ~(64|128|256);
369 mask2 <<= 3;
370 y2--;
372 while (y2 < y1) {
373 mask2 &= ~(1|2|4);
374 mask2 >>= 3;
375 y2++;
380 * Invert the second set if `diff' is set (we're after A &~ B
381 * rather than A & B).
383 if (diff)
384 mask2 ^= 511;
387 * Now all that's left is a logical AND.
389 return mask1 & mask2;
392 static void ss_add_todo(struct setstore *ss, struct set *s)
394 if (s->todo)
395 return; /* already on it */
397 #ifdef SOLVER_DIAGNOSTICS
398 printf("adding set on todo list: %d,%d %03x %d\n",
399 s->x, s->y, s->mask, s->mines);
400 #endif
402 s->prev = ss->todo_tail;
403 if (s->prev)
404 s->prev->next = s;
405 else
406 ss->todo_head = s;
407 ss->todo_tail = s;
408 s->next = NULL;
409 s->todo = TRUE;
412 static void ss_add(struct setstore *ss, int x, int y, int mask, int mines)
414 struct set *s;
416 assert(mask != 0);
419 * Normalise so that x and y are genuinely the bounding
420 * rectangle.
422 while (!(mask & (1|8|64)))
423 mask >>= 1, x++;
424 while (!(mask & (1|2|4)))
425 mask >>= 3, y++;
428 * Create a set structure and add it to the tree.
430 s = snew(struct set);
431 s->x = x;
432 s->y = y;
433 s->mask = mask;
434 s->mines = mines;
435 s->todo = FALSE;
436 if (add234(ss->sets, s) != s) {
438 * This set already existed! Free it and return.
440 sfree(s);
441 return;
445 * We've added a new set to the tree, so put it on the todo
446 * list.
448 ss_add_todo(ss, s);
451 static void ss_remove(struct setstore *ss, struct set *s)
453 struct set *next = s->next, *prev = s->prev;
455 #ifdef SOLVER_DIAGNOSTICS
456 printf("removing set %d,%d %03x\n", s->x, s->y, s->mask);
457 #endif
459 * Remove s from the todo list.
461 if (prev)
462 prev->next = next;
463 else if (s == ss->todo_head)
464 ss->todo_head = next;
466 if (next)
467 next->prev = prev;
468 else if (s == ss->todo_tail)
469 ss->todo_tail = prev;
471 s->todo = FALSE;
474 * Remove s from the tree.
476 del234(ss->sets, s);
479 * Destroy the actual set structure.
481 sfree(s);
485 * Return a dynamically allocated list of all the sets which
486 * overlap a provided input set.
488 static struct set **ss_overlap(struct setstore *ss, int x, int y, int mask)
490 struct set **ret = NULL;
491 int nret = 0, retsize = 0;
492 int xx, yy;
494 for (xx = x-3; xx < x+3; xx++)
495 for (yy = y-3; yy < y+3; yy++) {
496 struct set stmp, *s;
497 int pos;
500 * Find the first set with these top left coordinates.
502 stmp.x = xx;
503 stmp.y = yy;
504 stmp.mask = 0;
506 if (findrelpos234(ss->sets, &stmp, NULL, REL234_GE, &pos)) {
507 while ((s = index234(ss->sets, pos)) != NULL &&
508 s->x == xx && s->y == yy) {
510 * This set potentially overlaps the input one.
511 * Compute the intersection to see if they
512 * really overlap, and add it to the list if
513 * so.
515 if (setmunge(x, y, mask, s->x, s->y, s->mask, FALSE)) {
517 * There's an overlap.
519 if (nret >= retsize) {
520 retsize = nret + 32;
521 ret = sresize(ret, retsize, struct set *);
523 ret[nret++] = s;
526 pos++;
531 ret = sresize(ret, nret+1, struct set *);
532 ret[nret] = NULL;
534 return ret;
538 * Get an element from the head of the set todo list.
540 static struct set *ss_todo(struct setstore *ss)
542 if (ss->todo_head) {
543 struct set *ret = ss->todo_head;
544 ss->todo_head = ret->next;
545 if (ss->todo_head)
546 ss->todo_head->prev = NULL;
547 else
548 ss->todo_tail = NULL;
549 ret->next = ret->prev = NULL;
550 ret->todo = FALSE;
551 return ret;
552 } else {
553 return NULL;
557 struct squaretodo {
558 int *next;
559 int head, tail;
562 static void std_add(struct squaretodo *std, int i)
564 if (std->tail >= 0)
565 std->next[std->tail] = i;
566 else
567 std->head = i;
568 std->tail = i;
569 std->next[i] = -1;
572 typedef int (*open_cb)(void *, int, int);
574 static void known_squares(int w, int h, struct squaretodo *std,
575 signed char *grid,
576 open_cb open, void *openctx,
577 int x, int y, int mask, int mine)
579 int xx, yy, bit;
581 bit = 1;
583 for (yy = 0; yy < 3; yy++)
584 for (xx = 0; xx < 3; xx++) {
585 if (mask & bit) {
586 int i = (y + yy) * w + (x + xx);
589 * It's possible that this square is _already_
590 * known, in which case we don't try to add it to
591 * the list twice.
593 if (grid[i] == -2) {
595 if (mine) {
596 grid[i] = -1; /* and don't open it! */
597 } else {
598 grid[i] = open(openctx, x + xx, y + yy);
599 assert(grid[i] != -1); /* *bang* */
601 std_add(std, i);
605 bit <<= 1;
610 * This is data returned from the `perturb' function. It details
611 * which squares have become mines and which have become clear. The
612 * solver is (of course) expected to honourably not use that
613 * knowledge directly, but to efficently adjust its internal data
614 * structures and proceed based on only the information it
615 * legitimately has.
617 struct perturbation {
618 int x, y;
619 int delta; /* +1 == become a mine; -1 == cleared */
621 struct perturbations {
622 int n;
623 struct perturbation *changes;
627 * Main solver entry point. You give it a grid of existing
628 * knowledge (-1 for a square known to be a mine, 0-8 for empty
629 * squares with a given number of neighbours, -2 for completely
630 * unknown), plus a function which you can call to open new squares
631 * once you're confident of them. It fills in as much more of the
632 * grid as it can.
634 * Return value is:
636 * - -1 means deduction stalled and nothing could be done
637 * - 0 means deduction succeeded fully
638 * - >0 means deduction succeeded but some number of perturbation
639 * steps were required; the exact return value is the number of
640 * perturb calls.
643 typedef struct perturbations *(*perturb_cb) (void *, signed char *, int, int, int);
645 static int minesolve(int w, int h, int n, signed char *grid,
646 open_cb open,
647 perturb_cb perturb,
648 void *ctx, random_state *rs)
650 struct setstore *ss = ss_new();
651 struct set **list;
652 struct squaretodo astd, *std = &astd;
653 int x, y, i, j;
654 int nperturbs = 0;
657 * Set up a linked list of squares with known contents, so that
658 * we can process them one by one.
660 std->next = snewn(w*h, int);
661 std->head = std->tail = -1;
664 * Initialise that list with all known squares in the input
665 * grid.
667 for (y = 0; y < h; y++) {
668 for (x = 0; x < w; x++) {
669 i = y*w+x;
670 if (grid[i] != -2)
671 std_add(std, i);
676 * Main deductive loop.
678 while (1) {
679 int done_something = FALSE;
680 struct set *s;
683 * If there are any known squares on the todo list, process
684 * them and construct a set for each.
686 while (std->head != -1) {
687 i = std->head;
688 #ifdef SOLVER_DIAGNOSTICS
689 printf("known square at %d,%d [%d]\n", i%w, i/w, grid[i]);
690 #endif
691 std->head = std->next[i];
692 if (std->head == -1)
693 std->tail = -1;
695 x = i % w;
696 y = i / w;
698 if (grid[i] >= 0) {
699 int dx, dy, mines, bit, val;
700 #ifdef SOLVER_DIAGNOSTICS
701 printf("creating set around this square\n");
702 #endif
704 * Empty square. Construct the set of non-known squares
705 * around this one, and determine its mine count.
707 mines = grid[i];
708 bit = 1;
709 val = 0;
710 for (dy = -1; dy <= +1; dy++) {
711 for (dx = -1; dx <= +1; dx++) {
712 #ifdef SOLVER_DIAGNOSTICS
713 printf("grid %d,%d = %d\n", x+dx, y+dy, grid[i+dy*w+dx]);
714 #endif
715 if (x+dx < 0 || x+dx >= w || y+dy < 0 || y+dy >= h)
716 /* ignore this one */;
717 else if (grid[i+dy*w+dx] == -1)
718 mines--;
719 else if (grid[i+dy*w+dx] == -2)
720 val |= bit;
721 bit <<= 1;
724 if (val)
725 ss_add(ss, x-1, y-1, val, mines);
729 * Now, whether the square is empty or full, we must
730 * find any set which contains it and replace it with
731 * one which does not.
734 #ifdef SOLVER_DIAGNOSTICS
735 printf("finding sets containing known square %d,%d\n", x, y);
736 #endif
737 list = ss_overlap(ss, x, y, 1);
739 for (j = 0; list[j]; j++) {
740 int newmask, newmines;
742 s = list[j];
745 * Compute the mask for this set minus the
746 * newly known square.
748 newmask = setmunge(s->x, s->y, s->mask, x, y, 1, TRUE);
751 * Compute the new mine count.
753 newmines = s->mines - (grid[i] == -1);
756 * Insert the new set into the collection,
757 * unless it's been whittled right down to
758 * nothing.
760 if (newmask)
761 ss_add(ss, s->x, s->y, newmask, newmines);
764 * Destroy the old one; it is actually obsolete.
766 ss_remove(ss, s);
769 sfree(list);
773 * Marking a fresh square as known certainly counts as
774 * doing something.
776 done_something = TRUE;
780 * Now pick a set off the to-do list and attempt deductions
781 * based on it.
783 if ((s = ss_todo(ss)) != NULL) {
785 #ifdef SOLVER_DIAGNOSTICS
786 printf("set to do: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines);
787 #endif
789 * Firstly, see if this set has a mine count of zero or
790 * of its own cardinality.
792 if (s->mines == 0 || s->mines == bitcount16(s->mask)) {
794 * If so, we can immediately mark all the squares
795 * in the set as known.
797 #ifdef SOLVER_DIAGNOSTICS
798 printf("easy\n");
799 #endif
800 known_squares(w, h, std, grid, open, ctx,
801 s->x, s->y, s->mask, (s->mines != 0));
804 * Having done that, we need do nothing further
805 * with this set; marking all the squares in it as
806 * known will eventually eliminate it, and will
807 * also permit further deductions about anything
808 * that overlaps it.
810 continue;
814 * Failing that, we now search through all the sets
815 * which overlap this one.
817 list = ss_overlap(ss, s->x, s->y, s->mask);
819 for (j = 0; list[j]; j++) {
820 struct set *s2 = list[j];
821 int swing, s2wing, swc, s2wc;
824 * Find the non-overlapping parts s2-s and s-s2,
825 * and their cardinalities.
827 * I'm going to refer to these parts as `wings'
828 * surrounding the central part common to both
829 * sets. The `s wing' is s-s2; the `s2 wing' is
830 * s2-s.
832 swing = setmunge(s->x, s->y, s->mask, s2->x, s2->y, s2->mask,
833 TRUE);
834 s2wing = setmunge(s2->x, s2->y, s2->mask, s->x, s->y, s->mask,
835 TRUE);
836 swc = bitcount16(swing);
837 s2wc = bitcount16(s2wing);
840 * If one set has more mines than the other, and
841 * the number of extra mines is equal to the
842 * cardinality of that set's wing, then we can mark
843 * every square in the wing as a known mine, and
844 * every square in the other wing as known clear.
846 if (swc == s->mines - s2->mines ||
847 s2wc == s2->mines - s->mines) {
848 known_squares(w, h, std, grid, open, ctx,
849 s->x, s->y, swing,
850 (swc == s->mines - s2->mines));
851 known_squares(w, h, std, grid, open, ctx,
852 s2->x, s2->y, s2wing,
853 (s2wc == s2->mines - s->mines));
854 continue;
858 * Failing that, see if one set is a subset of the
859 * other. If so, we can divide up the mine count of
860 * the larger set between the smaller set and its
861 * complement, even if neither smaller set ends up
862 * being immediately clearable.
864 if (swc == 0 && s2wc != 0) {
865 /* s is a subset of s2. */
866 assert(s2->mines > s->mines);
867 ss_add(ss, s2->x, s2->y, s2wing, s2->mines - s->mines);
868 } else if (s2wc == 0 && swc != 0) {
869 /* s2 is a subset of s. */
870 assert(s->mines > s2->mines);
871 ss_add(ss, s->x, s->y, swing, s->mines - s2->mines);
875 sfree(list);
878 * In this situation we have definitely done
879 * _something_, even if it's only reducing the size of
880 * our to-do list.
882 done_something = TRUE;
883 } else if (n >= 0) {
885 * We have nothing left on our todo list, which means
886 * all localised deductions have failed. Our next step
887 * is to resort to global deduction based on the total
888 * mine count. This is computationally expensive
889 * compared to any of the above deductions, which is
890 * why we only ever do it when all else fails, so that
891 * hopefully it won't have to happen too often.
893 * If you pass n<0 into this solver, that informs it
894 * that you do not know the total mine count, so it
895 * won't even attempt these deductions.
898 int minesleft, squaresleft;
899 int nsets, setused[10], cursor;
902 * Start by scanning the current grid state to work out
903 * how many unknown squares we still have, and how many
904 * mines are to be placed in them.
906 squaresleft = 0;
907 minesleft = n;
908 for (i = 0; i < w*h; i++) {
909 if (grid[i] == -1)
910 minesleft--;
911 else if (grid[i] == -2)
912 squaresleft++;
915 #ifdef SOLVER_DIAGNOSTICS
916 printf("global deduction time: squaresleft=%d minesleft=%d\n",
917 squaresleft, minesleft);
918 for (y = 0; y < h; y++) {
919 for (x = 0; x < w; x++) {
920 int v = grid[y*w+x];
921 if (v == -1)
922 putchar('*');
923 else if (v == -2)
924 putchar('?');
925 else if (v == 0)
926 putchar('-');
927 else
928 putchar('0' + v);
930 putchar('\n');
932 #endif
935 * If there _are_ no unknown squares, we have actually
936 * finished.
938 if (squaresleft == 0) {
939 assert(minesleft == 0);
940 break;
944 * First really simple case: if there are no more mines
945 * left, or if there are exactly as many mines left as
946 * squares to play them in, then it's all easy.
948 if (minesleft == 0 || minesleft == squaresleft) {
949 for (i = 0; i < w*h; i++)
950 if (grid[i] == -2)
951 known_squares(w, h, std, grid, open, ctx,
952 i % w, i / w, 1, minesleft != 0);
953 continue; /* now go back to main deductive loop */
957 * Failing that, we have to do some _real_ work.
958 * Ideally what we do here is to try every single
959 * combination of the currently available sets, in an
960 * attempt to find a disjoint union (i.e. a set of
961 * squares with a known mine count between them) such
962 * that the remaining unknown squares _not_ contained
963 * in that union either contain no mines or are all
964 * mines.
966 * Actually enumerating all 2^n possibilities will get
967 * a bit slow for large n, so I artificially cap this
968 * recursion at n=10 to avoid too much pain.
970 nsets = count234(ss->sets);
971 if (nsets <= lenof(setused)) {
973 * Doing this with actual recursive function calls
974 * would get fiddly because a load of local
975 * variables from this function would have to be
976 * passed down through the recursion. So instead
977 * I'm going to use a virtual recursion within this
978 * function. The way this works is:
980 * - we have an array `setused', such that
981 * setused[n] is 0 or 1 depending on whether set
982 * n is currently in the union we are
983 * considering.
985 * - we have a value `cursor' which indicates how
986 * much of `setused' we have so far filled in.
987 * It's conceptually the recursion depth.
989 * We begin by setting `cursor' to zero. Then:
991 * - if cursor can advance, we advance it by one.
992 * We set the value in `setused' that it went
993 * past to 1 if that set is disjoint from
994 * anything else currently in `setused', or to 0
995 * otherwise.
997 * - If cursor cannot advance because it has
998 * reached the end of the setused list, then we
999 * have a maximal disjoint union. Check to see
1000 * whether its mine count has any useful
1001 * properties. If so, mark all the squares not
1002 * in the union as known and terminate.
1004 * - If cursor has reached the end of setused and
1005 * the algorithm _hasn't_ terminated, back
1006 * cursor up to the nearest 1, turn it into a 0
1007 * and advance cursor just past it.
1009 * - If we attempt to back up to the nearest 1 and
1010 * there isn't one at all, then we have gone
1011 * through all disjoint unions of sets in the
1012 * list and none of them has been helpful, so we
1013 * give up.
1015 struct set *sets[lenof(setused)];
1016 for (i = 0; i < nsets; i++)
1017 sets[i] = index234(ss->sets, i);
1019 cursor = 0;
1020 while (1) {
1022 if (cursor < nsets) {
1023 int ok = TRUE;
1025 /* See if any existing set overlaps this one. */
1026 for (i = 0; i < cursor; i++)
1027 if (setused[i] &&
1028 setmunge(sets[cursor]->x,
1029 sets[cursor]->y,
1030 sets[cursor]->mask,
1031 sets[i]->x, sets[i]->y, sets[i]->mask,
1032 FALSE)) {
1033 ok = FALSE;
1034 break;
1037 if (ok) {
1039 * We're adding this set to our union,
1040 * so adjust minesleft and squaresleft
1041 * appropriately.
1043 minesleft -= sets[cursor]->mines;
1044 squaresleft -= bitcount16(sets[cursor]->mask);
1047 setused[cursor++] = ok;
1048 } else {
1049 #ifdef SOLVER_DIAGNOSTICS
1050 printf("trying a set combination with %d %d\n",
1051 squaresleft, minesleft);
1052 #endif /* SOLVER_DIAGNOSTICS */
1055 * We've reached the end. See if we've got
1056 * anything interesting.
1058 if (squaresleft > 0 &&
1059 (minesleft == 0 || minesleft == squaresleft)) {
1061 * We have! There is at least one
1062 * square not contained within the set
1063 * union we've just found, and we can
1064 * deduce that either all such squares
1065 * are mines or all are not (depending
1066 * on whether minesleft==0). So now all
1067 * we have to do is actually go through
1068 * the grid, find those squares, and
1069 * mark them.
1071 for (i = 0; i < w*h; i++)
1072 if (grid[i] == -2) {
1073 int outside = TRUE;
1074 y = i / w;
1075 x = i % w;
1076 for (j = 0; j < nsets; j++)
1077 if (setused[j] &&
1078 setmunge(sets[j]->x, sets[j]->y,
1079 sets[j]->mask, x, y, 1,
1080 FALSE)) {
1081 outside = FALSE;
1082 break;
1084 if (outside)
1085 known_squares(w, h, std, grid,
1086 open, ctx,
1087 x, y, 1, minesleft != 0);
1090 done_something = TRUE;
1091 break; /* return to main deductive loop */
1095 * If we reach here, then this union hasn't
1096 * done us any good, so move on to the
1097 * next. Backtrack cursor to the nearest 1,
1098 * change it to a 0 and continue.
1100 while (--cursor >= 0 && !setused[cursor]);
1101 if (cursor >= 0) {
1102 assert(setused[cursor]);
1105 * We're removing this set from our
1106 * union, so re-increment minesleft and
1107 * squaresleft.
1109 minesleft += sets[cursor]->mines;
1110 squaresleft += bitcount16(sets[cursor]->mask);
1112 setused[cursor++] = 0;
1113 } else {
1115 * We've backtracked all the way to the
1116 * start without finding a single 1,
1117 * which means that our virtual
1118 * recursion is complete and nothing
1119 * helped.
1121 break;
1130 if (done_something)
1131 continue;
1133 #ifdef SOLVER_DIAGNOSTICS
1135 * Dump the current known state of the grid.
1137 printf("solver ran out of steam, ret=%d, grid:\n", nperturbs);
1138 for (y = 0; y < h; y++) {
1139 for (x = 0; x < w; x++) {
1140 int v = grid[y*w+x];
1141 if (v == -1)
1142 putchar('*');
1143 else if (v == -2)
1144 putchar('?');
1145 else if (v == 0)
1146 putchar('-');
1147 else
1148 putchar('0' + v);
1150 putchar('\n');
1154 struct set *s;
1156 for (i = 0; (s = index234(ss->sets, i)) != NULL; i++)
1157 printf("remaining set: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines);
1159 #endif
1162 * Now we really are at our wits' end as far as solving
1163 * this grid goes. Our only remaining option is to call
1164 * a perturb function and ask it to modify the grid to
1165 * make it easier.
1167 if (perturb) {
1168 struct perturbations *ret;
1169 struct set *s;
1171 nperturbs++;
1174 * Choose a set at random from the current selection,
1175 * and ask the perturb function to either fill or empty
1176 * it.
1178 * If we have no sets at all, we must give up.
1180 if (count234(ss->sets) == 0) {
1181 #ifdef SOLVER_DIAGNOSTICS
1182 printf("perturbing on entire unknown set\n");
1183 #endif
1184 ret = perturb(ctx, grid, 0, 0, 0);
1185 } else {
1186 s = index234(ss->sets, random_upto(rs, count234(ss->sets)));
1187 #ifdef SOLVER_DIAGNOSTICS
1188 printf("perturbing on set %d,%d %03x\n", s->x, s->y, s->mask);
1189 #endif
1190 ret = perturb(ctx, grid, s->x, s->y, s->mask);
1193 if (ret) {
1194 assert(ret->n > 0); /* otherwise should have been NULL */
1197 * A number of squares have been fiddled with, and
1198 * the returned structure tells us which. Adjust
1199 * the mine count in any set which overlaps one of
1200 * those squares, and put them back on the to-do
1201 * list. Also, if the square itself is marked as a
1202 * known non-mine, put it back on the squares-to-do
1203 * list.
1205 for (i = 0; i < ret->n; i++) {
1206 #ifdef SOLVER_DIAGNOSTICS
1207 printf("perturbation %s mine at %d,%d\n",
1208 ret->changes[i].delta > 0 ? "added" : "removed",
1209 ret->changes[i].x, ret->changes[i].y);
1210 #endif
1212 if (ret->changes[i].delta < 0 &&
1213 grid[ret->changes[i].y*w+ret->changes[i].x] != -2) {
1214 std_add(std, ret->changes[i].y*w+ret->changes[i].x);
1217 list = ss_overlap(ss,
1218 ret->changes[i].x, ret->changes[i].y, 1);
1220 for (j = 0; list[j]; j++) {
1221 list[j]->mines += ret->changes[i].delta;
1222 ss_add_todo(ss, list[j]);
1225 sfree(list);
1229 * Now free the returned data.
1231 sfree(ret->changes);
1232 sfree(ret);
1234 #ifdef SOLVER_DIAGNOSTICS
1236 * Dump the current known state of the grid.
1238 printf("state after perturbation:\n");
1239 for (y = 0; y < h; y++) {
1240 for (x = 0; x < w; x++) {
1241 int v = grid[y*w+x];
1242 if (v == -1)
1243 putchar('*');
1244 else if (v == -2)
1245 putchar('?');
1246 else if (v == 0)
1247 putchar('-');
1248 else
1249 putchar('0' + v);
1251 putchar('\n');
1255 struct set *s;
1257 for (i = 0; (s = index234(ss->sets, i)) != NULL; i++)
1258 printf("remaining set: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines);
1260 #endif
1263 * And now we can go back round the deductive loop.
1265 continue;
1270 * If we get here, even that didn't work (either we didn't
1271 * have a perturb function or it returned failure), so we
1272 * give up entirely.
1274 break;
1278 * See if we've got any unknown squares left.
1280 for (y = 0; y < h; y++)
1281 for (x = 0; x < w; x++)
1282 if (grid[y*w+x] == -2) {
1283 nperturbs = -1; /* failed to complete */
1284 break;
1288 * Free the set list and square-todo list.
1291 struct set *s;
1292 while ((s = delpos234(ss->sets, 0)) != NULL)
1293 sfree(s);
1294 freetree234(ss->sets);
1295 sfree(ss);
1296 sfree(std->next);
1299 return nperturbs;
1302 /* ----------------------------------------------------------------------
1303 * Grid generator which uses the above solver.
1306 struct minectx {
1307 char *grid;
1308 int w, h;
1309 int sx, sy;
1310 int allow_big_perturbs;
1311 random_state *rs;
1314 static int mineopen(void *vctx, int x, int y)
1316 struct minectx *ctx = (struct minectx *)vctx;
1317 int i, j, n;
1319 assert(x >= 0 && x < ctx->w && y >= 0 && y < ctx->h);
1320 if (ctx->grid[y * ctx->w + x])
1321 return -1; /* *bang* */
1323 n = 0;
1324 for (i = -1; i <= +1; i++) {
1325 if (x + i < 0 || x + i >= ctx->w)
1326 continue;
1327 for (j = -1; j <= +1; j++) {
1328 if (y + j < 0 || y + j >= ctx->h)
1329 continue;
1330 if (i == 0 && j == 0)
1331 continue;
1332 if (ctx->grid[(y+j) * ctx->w + (x+i)])
1333 n++;
1337 return n;
1340 /* Structure used internally to mineperturb(). */
1341 struct square {
1342 int x, y, type, random;
1344 static int squarecmp(const void *av, const void *bv)
1346 const struct square *a = (const struct square *)av;
1347 const struct square *b = (const struct square *)bv;
1348 if (a->type < b->type)
1349 return -1;
1350 else if (a->type > b->type)
1351 return +1;
1352 else if (a->random < b->random)
1353 return -1;
1354 else if (a->random > b->random)
1355 return +1;
1356 else if (a->y < b->y)
1357 return -1;
1358 else if (a->y > b->y)
1359 return +1;
1360 else if (a->x < b->x)
1361 return -1;
1362 else if (a->x > b->x)
1363 return +1;
1364 return 0;
1368 * Normally this function is passed an (x,y,mask) set description.
1369 * On occasions, though, there is no _localised_ set being used,
1370 * and the set being perturbed is supposed to be the entirety of
1371 * the unreachable area. This is signified by the special case
1372 * mask==0: in this case, anything labelled -2 in the grid is part
1373 * of the set.
1375 * Allowing perturbation in this special case appears to make it
1376 * guaranteeably possible to generate a workable grid for any mine
1377 * density, but they tend to be a bit boring, with mines packed
1378 * densely into far corners of the grid and the remainder being
1379 * less dense than one might like. Therefore, to improve overall
1380 * grid quality I disable this feature for the first few attempts,
1381 * and fall back to it after no useful grid has been generated.
1383 static struct perturbations *mineperturb(void *vctx, signed char *grid,
1384 int setx, int sety, int mask)
1386 struct minectx *ctx = (struct minectx *)vctx;
1387 struct square *sqlist;
1388 int x, y, dx, dy, i, n, nfull, nempty;
1389 struct square **tofill, **toempty, **todo;
1390 int ntofill, ntoempty, ntodo, dtodo, dset;
1391 struct perturbations *ret;
1392 int *setlist;
1394 if (!mask && !ctx->allow_big_perturbs)
1395 return NULL;
1398 * Make a list of all the squares in the grid which we can
1399 * possibly use. This list should be in preference order, which
1400 * means
1402 * - first, unknown squares on the boundary of known space
1403 * - next, unknown squares beyond that boundary
1404 * - as a very last resort, known squares, but not within one
1405 * square of the starting position.
1407 * Each of these sections needs to be shuffled independently.
1408 * We do this by preparing list of all squares and then sorting
1409 * it with a random secondary key.
1411 sqlist = snewn(ctx->w * ctx->h, struct square);
1412 n = 0;
1413 for (y = 0; y < ctx->h; y++)
1414 for (x = 0; x < ctx->w; x++) {
1416 * If this square is too near the starting position,
1417 * don't put it on the list at all.
1419 if (abs(y - ctx->sy) <= 1 && abs(x - ctx->sx) <= 1)
1420 continue;
1423 * If this square is in the input set, also don't put
1424 * it on the list!
1426 if ((mask == 0 && grid[y*ctx->w+x] == -2) ||
1427 (x >= setx && x < setx + 3 &&
1428 y >= sety && y < sety + 3 &&
1429 mask & (1 << ((y-sety)*3+(x-setx)))))
1430 continue;
1432 sqlist[n].x = x;
1433 sqlist[n].y = y;
1435 if (grid[y*ctx->w+x] != -2) {
1436 sqlist[n].type = 3; /* known square */
1437 } else {
1439 * Unknown square. Examine everything around it and
1440 * see if it borders on any known squares. If it
1441 * does, it's class 1, otherwise it's 2.
1444 sqlist[n].type = 2;
1446 for (dy = -1; dy <= +1; dy++)
1447 for (dx = -1; dx <= +1; dx++)
1448 if (x+dx >= 0 && x+dx < ctx->w &&
1449 y+dy >= 0 && y+dy < ctx->h &&
1450 grid[(y+dy)*ctx->w+(x+dx)] != -2) {
1451 sqlist[n].type = 1;
1452 break;
1457 * Finally, a random number to cause qsort to
1458 * shuffle within each group.
1460 sqlist[n].random = random_bits(ctx->rs, 31);
1462 n++;
1465 qsort(sqlist, n, sizeof(struct square), squarecmp);
1468 * Now count up the number of full and empty squares in the set
1469 * we've been provided.
1471 nfull = nempty = 0;
1472 if (mask) {
1473 for (dy = 0; dy < 3; dy++)
1474 for (dx = 0; dx < 3; dx++)
1475 if (mask & (1 << (dy*3+dx))) {
1476 assert(setx+dx <= ctx->w);
1477 assert(sety+dy <= ctx->h);
1478 if (ctx->grid[(sety+dy)*ctx->w+(setx+dx)])
1479 nfull++;
1480 else
1481 nempty++;
1483 } else {
1484 for (y = 0; y < ctx->h; y++)
1485 for (x = 0; x < ctx->w; x++)
1486 if (grid[y*ctx->w+x] == -2) {
1487 if (ctx->grid[y*ctx->w+x])
1488 nfull++;
1489 else
1490 nempty++;
1495 * Now go through our sorted list until we find either `nfull'
1496 * empty squares, or `nempty' full squares; these will be
1497 * swapped with the appropriate squares in the set to either
1498 * fill or empty the set while keeping the same number of mines
1499 * overall.
1501 ntofill = ntoempty = 0;
1502 if (mask) {
1503 tofill = snewn(9, struct square *);
1504 toempty = snewn(9, struct square *);
1505 } else {
1506 tofill = snewn(ctx->w * ctx->h, struct square *);
1507 toempty = snewn(ctx->w * ctx->h, struct square *);
1509 for (i = 0; i < n; i++) {
1510 struct square *sq = &sqlist[i];
1511 if (ctx->grid[sq->y * ctx->w + sq->x])
1512 toempty[ntoempty++] = sq;
1513 else
1514 tofill[ntofill++] = sq;
1515 if (ntofill == nfull || ntoempty == nempty)
1516 break;
1520 * If we haven't found enough empty squares outside the set to
1521 * empty it into _or_ enough full squares outside it to fill it
1522 * up with, we'll have to settle for doing only a partial job.
1523 * In this case we choose to always _fill_ the set (because
1524 * this case will tend to crop up when we're working with very
1525 * high mine densities and the only way to get a solvable grid
1526 * is going to be to pack most of the mines solidly around the
1527 * edges). So now our job is to make a list of the empty
1528 * squares in the set, and shuffle that list so that we fill a
1529 * random selection of them.
1531 if (ntofill != nfull && ntoempty != nempty) {
1532 int k;
1534 assert(ntoempty != 0);
1536 setlist = snewn(ctx->w * ctx->h, int);
1537 i = 0;
1538 if (mask) {
1539 for (dy = 0; dy < 3; dy++)
1540 for (dx = 0; dx < 3; dx++)
1541 if (mask & (1 << (dy*3+dx))) {
1542 assert(setx+dx <= ctx->w);
1543 assert(sety+dy <= ctx->h);
1544 if (!ctx->grid[(sety+dy)*ctx->w+(setx+dx)])
1545 setlist[i++] = (sety+dy)*ctx->w+(setx+dx);
1547 } else {
1548 for (y = 0; y < ctx->h; y++)
1549 for (x = 0; x < ctx->w; x++)
1550 if (grid[y*ctx->w+x] == -2) {
1551 if (!ctx->grid[y*ctx->w+x])
1552 setlist[i++] = y*ctx->w+x;
1555 assert(i > ntoempty);
1557 * Now pick `ntoempty' items at random from the list.
1559 for (k = 0; k < ntoempty; k++) {
1560 int index = k + random_upto(ctx->rs, i - k);
1561 int tmp;
1563 tmp = setlist[k];
1564 setlist[k] = setlist[index];
1565 setlist[index] = tmp;
1567 } else
1568 setlist = NULL;
1571 * Now we're pretty much there. We need to either
1572 * (a) put a mine in each of the empty squares in the set, and
1573 * take one out of each square in `toempty'
1574 * (b) take a mine out of each of the full squares in the set,
1575 * and put one in each square in `tofill'
1576 * depending on which one we've found enough squares to do.
1578 * So we start by constructing our list of changes to return to
1579 * the solver, so that it can update its data structures
1580 * efficiently rather than having to rescan the whole grid.
1582 ret = snew(struct perturbations);
1583 if (ntofill == nfull) {
1584 todo = tofill;
1585 ntodo = ntofill;
1586 dtodo = +1;
1587 dset = -1;
1588 sfree(toempty);
1589 } else {
1591 * (We also fall into this case if we've constructed a
1592 * setlist.)
1594 todo = toempty;
1595 ntodo = ntoempty;
1596 dtodo = -1;
1597 dset = +1;
1598 sfree(tofill);
1600 ret->n = 2 * ntodo;
1601 ret->changes = snewn(ret->n, struct perturbation);
1602 for (i = 0; i < ntodo; i++) {
1603 ret->changes[i].x = todo[i]->x;
1604 ret->changes[i].y = todo[i]->y;
1605 ret->changes[i].delta = dtodo;
1607 /* now i == ntodo */
1608 if (setlist) {
1609 int j;
1610 assert(todo == toempty);
1611 for (j = 0; j < ntoempty; j++) {
1612 ret->changes[i].x = setlist[j] % ctx->w;
1613 ret->changes[i].y = setlist[j] / ctx->w;
1614 ret->changes[i].delta = dset;
1615 i++;
1617 sfree(setlist);
1618 } else if (mask) {
1619 for (dy = 0; dy < 3; dy++)
1620 for (dx = 0; dx < 3; dx++)
1621 if (mask & (1 << (dy*3+dx))) {
1622 int currval = (ctx->grid[(sety+dy)*ctx->w+(setx+dx)] ? +1 : -1);
1623 if (dset == -currval) {
1624 ret->changes[i].x = setx + dx;
1625 ret->changes[i].y = sety + dy;
1626 ret->changes[i].delta = dset;
1627 i++;
1630 } else {
1631 for (y = 0; y < ctx->h; y++)
1632 for (x = 0; x < ctx->w; x++)
1633 if (grid[y*ctx->w+x] == -2) {
1634 int currval = (ctx->grid[y*ctx->w+x] ? +1 : -1);
1635 if (dset == -currval) {
1636 ret->changes[i].x = x;
1637 ret->changes[i].y = y;
1638 ret->changes[i].delta = dset;
1639 i++;
1643 assert(i == ret->n);
1645 sfree(sqlist);
1646 sfree(todo);
1649 * Having set up the precise list of changes we're going to
1650 * make, we now simply make them and return.
1652 for (i = 0; i < ret->n; i++) {
1653 int delta;
1655 x = ret->changes[i].x;
1656 y = ret->changes[i].y;
1657 delta = ret->changes[i].delta;
1660 * Check we're not trying to add an existing mine or remove
1661 * an absent one.
1663 assert((delta < 0) ^ (ctx->grid[y*ctx->w+x] == 0));
1666 * Actually make the change.
1668 ctx->grid[y*ctx->w+x] = (delta > 0);
1671 * Update any numbers already present in the grid.
1673 for (dy = -1; dy <= +1; dy++)
1674 for (dx = -1; dx <= +1; dx++)
1675 if (x+dx >= 0 && x+dx < ctx->w &&
1676 y+dy >= 0 && y+dy < ctx->h &&
1677 grid[(y+dy)*ctx->w+(x+dx)] != -2) {
1678 if (dx == 0 && dy == 0) {
1680 * The square itself is marked as known in
1681 * the grid. Mark it as a mine if it's a
1682 * mine, or else work out its number.
1684 if (delta > 0) {
1685 grid[y*ctx->w+x] = -1;
1686 } else {
1687 int dx2, dy2, minecount = 0;
1688 for (dy2 = -1; dy2 <= +1; dy2++)
1689 for (dx2 = -1; dx2 <= +1; dx2++)
1690 if (x+dx2 >= 0 && x+dx2 < ctx->w &&
1691 y+dy2 >= 0 && y+dy2 < ctx->h &&
1692 ctx->grid[(y+dy2)*ctx->w+(x+dx2)])
1693 minecount++;
1694 grid[y*ctx->w+x] = minecount;
1696 } else {
1697 if (grid[(y+dy)*ctx->w+(x+dx)] >= 0)
1698 grid[(y+dy)*ctx->w+(x+dx)] += delta;
1703 #ifdef GENERATION_DIAGNOSTICS
1705 int yy, xx;
1706 printf("grid after perturbing:\n");
1707 for (yy = 0; yy < ctx->h; yy++) {
1708 for (xx = 0; xx < ctx->w; xx++) {
1709 int v = ctx->grid[yy*ctx->w+xx];
1710 if (yy == ctx->sy && xx == ctx->sx) {
1711 assert(!v);
1712 putchar('S');
1713 } else if (v) {
1714 putchar('*');
1715 } else {
1716 putchar('-');
1719 putchar('\n');
1721 printf("\n");
1723 #endif
1725 return ret;
1728 static char *minegen(int w, int h, int n, int x, int y, int unique,
1729 random_state *rs)
1731 char *ret = snewn(w*h, char);
1732 int success;
1733 int ntries = 0;
1735 do {
1736 success = FALSE;
1737 ntries++;
1739 memset(ret, 0, w*h);
1742 * Start by placing n mines, none of which is at x,y or within
1743 * one square of it.
1746 int *tmp = snewn(w*h, int);
1747 int i, j, k, nn;
1750 * Write down the list of possible mine locations.
1752 k = 0;
1753 for (i = 0; i < h; i++)
1754 for (j = 0; j < w; j++)
1755 if (abs(i - y) > 1 || abs(j - x) > 1)
1756 tmp[k++] = i*w+j;
1759 * Now pick n off the list at random.
1761 nn = n;
1762 while (nn-- > 0) {
1763 i = random_upto(rs, k);
1764 ret[tmp[i]] = 1;
1765 tmp[i] = tmp[--k];
1768 sfree(tmp);
1771 #ifdef GENERATION_DIAGNOSTICS
1773 int yy, xx;
1774 printf("grid after initial generation:\n");
1775 for (yy = 0; yy < h; yy++) {
1776 for (xx = 0; xx < w; xx++) {
1777 int v = ret[yy*w+xx];
1778 if (yy == y && xx == x) {
1779 assert(!v);
1780 putchar('S');
1781 } else if (v) {
1782 putchar('*');
1783 } else {
1784 putchar('-');
1787 putchar('\n');
1789 printf("\n");
1791 #endif
1794 * Now set up a results grid to run the solver in, and a
1795 * context for the solver to open squares. Then run the solver
1796 * repeatedly; if the number of perturb steps ever goes up or
1797 * it ever returns -1, give up completely.
1799 * We bypass this bit if we're not after a unique grid.
1801 if (unique) {
1802 signed char *solvegrid = snewn(w*h, signed char);
1803 struct minectx actx, *ctx = &actx;
1804 int solveret, prevret = -2;
1806 ctx->grid = ret;
1807 ctx->w = w;
1808 ctx->h = h;
1809 ctx->sx = x;
1810 ctx->sy = y;
1811 ctx->rs = rs;
1812 ctx->allow_big_perturbs = (ntries > 100);
1814 while (1) {
1815 memset(solvegrid, -2, w*h);
1816 solvegrid[y*w+x] = mineopen(ctx, x, y);
1817 assert(solvegrid[y*w+x] == 0); /* by deliberate arrangement */
1819 solveret =
1820 minesolve(w, h, n, solvegrid, mineopen, mineperturb, ctx, rs);
1821 if (solveret < 0 || (prevret >= 0 && solveret >= prevret)) {
1822 success = FALSE;
1823 break;
1824 } else if (solveret == 0) {
1825 success = TRUE;
1826 break;
1830 sfree(solvegrid);
1831 } else {
1832 success = TRUE;
1835 } while (!success);
1837 return ret;
1840 static char *describe_layout(char *grid, int area, int x, int y,
1841 int obfuscate)
1843 char *ret, *p;
1844 unsigned char *bmp;
1845 int i;
1848 * Set up the mine bitmap and obfuscate it.
1850 bmp = snewn((area + 7) / 8, unsigned char);
1851 memset(bmp, 0, (area + 7) / 8);
1852 for (i = 0; i < area; i++) {
1853 if (grid[i])
1854 bmp[i / 8] |= 0x80 >> (i % 8);
1856 if (obfuscate)
1857 obfuscate_bitmap(bmp, area, FALSE);
1860 * Now encode the resulting bitmap in hex. We can work to
1861 * nibble rather than byte granularity, since the obfuscation
1862 * function guarantees to return a bit string of the same
1863 * length as its input.
1865 ret = snewn((area+3)/4 + 100, char);
1866 p = ret + sprintf(ret, "%d,%d,%s", x, y,
1867 obfuscate ? "m" : "u"); /* 'm' == masked */
1868 for (i = 0; i < (area+3)/4; i++) {
1869 int v = bmp[i/2];
1870 if (i % 2 == 0)
1871 v >>= 4;
1872 *p++ = "0123456789abcdef"[v & 0xF];
1874 *p = '\0';
1876 sfree(bmp);
1878 return ret;
1881 static char *new_mine_layout(int w, int h, int n, int x, int y, int unique,
1882 random_state *rs, char **game_desc)
1884 char *grid;
1886 #ifdef TEST_OBFUSCATION
1887 static int tested_obfuscation = FALSE;
1888 if (!tested_obfuscation) {
1890 * A few simple test vectors for the obfuscator.
1892 * First test: the 28-bit stream 1234567. This divides up
1893 * into 1234 and 567[0]. The SHA of 56 70 30 (appending
1894 * "0") is 15ce8ab946640340bbb99f3f48fd2c45d1a31d30. Thus,
1895 * we XOR the 16-bit string 15CE into the input 1234 to get
1896 * 07FA. Next, we SHA that with "0": the SHA of 07 FA 30 is
1897 * 3370135c5e3da4fed937adc004a79533962b6391. So we XOR the
1898 * 12-bit string 337 into the input 567 to get 650. Thus
1899 * our output is 07FA650.
1902 unsigned char bmp1[] = "\x12\x34\x56\x70";
1903 obfuscate_bitmap(bmp1, 28, FALSE);
1904 printf("test 1 encode: %s\n",
1905 memcmp(bmp1, "\x07\xfa\x65\x00", 4) ? "failed" : "passed");
1906 obfuscate_bitmap(bmp1, 28, TRUE);
1907 printf("test 1 decode: %s\n",
1908 memcmp(bmp1, "\x12\x34\x56\x70", 4) ? "failed" : "passed");
1911 * Second test: a long string to make sure we switch from
1912 * one SHA to the next correctly. My input string this time
1913 * is simply fifty bytes of zeroes.
1916 unsigned char bmp2[50];
1917 unsigned char bmp2a[50];
1918 memset(bmp2, 0, 50);
1919 memset(bmp2a, 0, 50);
1920 obfuscate_bitmap(bmp2, 50 * 8, FALSE);
1922 * SHA of twenty-five zero bytes plus "0" is
1923 * b202c07b990c01f6ff2d544707f60e506019b671. SHA of
1924 * twenty-five zero bytes plus "1" is
1925 * fcb1d8b5a2f6b592fe6780b36aa9d65dd7aa6db9. Thus our
1926 * first half becomes
1927 * b202c07b990c01f6ff2d544707f60e506019b671fcb1d8b5a2.
1929 * SHA of that lot plus "0" is
1930 * 10b0af913db85d37ca27f52a9f78bba3a80030db. SHA of the
1931 * same string plus "1" is
1932 * 3d01d8df78e76d382b8106f480135a1bc751d725. So the
1933 * second half becomes
1934 * 10b0af913db85d37ca27f52a9f78bba3a80030db3d01d8df78.
1936 printf("test 2 encode: %s\n",
1937 memcmp(bmp2, "\xb2\x02\xc0\x7b\x99\x0c\x01\xf6\xff\x2d\x54"
1938 "\x47\x07\xf6\x0e\x50\x60\x19\xb6\x71\xfc\xb1\xd8"
1939 "\xb5\xa2\x10\xb0\xaf\x91\x3d\xb8\x5d\x37\xca\x27"
1940 "\xf5\x2a\x9f\x78\xbb\xa3\xa8\x00\x30\xdb\x3d\x01"
1941 "\xd8\xdf\x78", 50) ? "failed" : "passed");
1942 obfuscate_bitmap(bmp2, 50 * 8, TRUE);
1943 printf("test 2 decode: %s\n",
1944 memcmp(bmp2, bmp2a, 50) ? "failed" : "passed");
1947 #endif
1949 grid = minegen(w, h, n, x, y, unique, rs);
1951 if (game_desc)
1952 *game_desc = describe_layout(grid, w * h, x, y, TRUE);
1954 return grid;
1957 static char *new_game_desc(game_params *params, random_state *rs,
1958 char **aux, int interactive)
1961 * We generate the coordinates of an initial click even if they
1962 * aren't actually used. This has the effect of harmonising the
1963 * random number usage between interactive and batch use: if
1964 * you use `mines --generate' with an explicit random seed, you
1965 * should get exactly the same results as if you type the same
1966 * random seed into the interactive game and click in the same
1967 * initial location. (Of course you won't get the same grid if
1968 * you click in a _different_ initial location, but there's
1969 * nothing to be done about that.)
1971 int x = random_upto(rs, params->w);
1972 int y = random_upto(rs, params->h);
1974 if (!interactive) {
1976 * For batch-generated grids, pre-open one square.
1978 char *grid;
1979 char *desc;
1981 grid = new_mine_layout(params->w, params->h, params->n,
1982 x, y, params->unique, rs, &desc);
1983 sfree(grid);
1984 return desc;
1985 } else {
1986 char *rsdesc, *desc;
1988 rsdesc = random_state_encode(rs);
1989 desc = snewn(strlen(rsdesc) + 100, char);
1990 sprintf(desc, "r%d,%c,%s", params->n, (char)(params->unique ? 'u' : 'a'), rsdesc);
1991 sfree(rsdesc);
1992 return desc;
1996 static char *validate_desc(game_params *params, char *desc)
1998 int wh = params->w * params->h;
1999 int x, y;
2001 if (*desc == 'r') {
2002 desc++;
2003 if (!*desc || !isdigit((unsigned char)*desc))
2004 return "No initial mine count in game description";
2005 while (*desc && isdigit((unsigned char)*desc))
2006 desc++; /* skip over mine count */
2007 if (*desc != ',')
2008 return "No ',' after initial x-coordinate in game description";
2009 desc++;
2010 if (*desc != 'u' && *desc != 'a')
2011 return "No uniqueness specifier in game description";
2012 desc++;
2013 if (*desc != ',')
2014 return "No ',' after uniqueness specifier in game description";
2015 /* now ignore the rest */
2016 } else {
2017 if (*desc && isdigit((unsigned char)*desc)) {
2018 x = atoi(desc);
2019 if (x < 0 || x >= params->w)
2020 return "Initial x-coordinate was out of range";
2021 while (*desc && isdigit((unsigned char)*desc))
2022 desc++; /* skip over x coordinate */
2023 if (*desc != ',')
2024 return "No ',' after initial x-coordinate in game description";
2025 desc++; /* eat comma */
2026 if (!*desc || !isdigit((unsigned char)*desc))
2027 return "No initial y-coordinate in game description";
2028 y = atoi(desc);
2029 if (y < 0 || y >= params->h)
2030 return "Initial y-coordinate was out of range";
2031 while (*desc && isdigit((unsigned char)*desc))
2032 desc++; /* skip over y coordinate */
2033 if (*desc != ',')
2034 return "No ',' after initial y-coordinate in game description";
2035 desc++; /* eat comma */
2037 /* eat `m' for `masked' or `u' for `unmasked', if present */
2038 if (*desc == 'm' || *desc == 'u')
2039 desc++;
2040 /* now just check length of remainder */
2041 if (strlen(desc) != (wh+3)/4)
2042 return "Game description is wrong length";
2045 return NULL;
2048 static int open_square(game_state *state, int x, int y)
2050 int w = state->w, h = state->h;
2051 int xx, yy, nmines, ncovered;
2053 if (!state->layout->mines) {
2055 * We have a preliminary game in which the mine layout
2056 * hasn't been generated yet. Generate it based on the
2057 * initial click location.
2059 char *desc, *privdesc;
2060 state->layout->mines = new_mine_layout(w, h, state->layout->n,
2061 x, y, state->layout->unique,
2062 state->layout->rs,
2063 &desc);
2065 * Find the trailing substring of the game description
2066 * corresponding to just the mine layout; we will use this
2067 * as our second `private' game ID for serialisation.
2069 privdesc = desc;
2070 while (*privdesc && isdigit((unsigned char)*privdesc)) privdesc++;
2071 if (*privdesc == ',') privdesc++;
2072 while (*privdesc && isdigit((unsigned char)*privdesc)) privdesc++;
2073 if (*privdesc == ',') privdesc++;
2074 assert(*privdesc == 'm');
2075 midend_supersede_game_desc(state->layout->me, desc, privdesc);
2076 sfree(desc);
2077 random_free(state->layout->rs);
2078 state->layout->rs = NULL;
2081 if (state->layout->mines[y*w+x]) {
2083 * The player has landed on a mine. Bad luck. Expose the
2084 * mine that killed them, but not the rest (in case they
2085 * want to Undo and carry on playing).
2087 state->dead = TRUE;
2088 state->grid[y*w+x] = 65;
2089 return -1;
2093 * Otherwise, the player has opened a safe square. Mark it to-do.
2095 state->grid[y*w+x] = -10; /* `todo' value internal to this func */
2098 * Now go through the grid finding all `todo' values and
2099 * opening them. Every time one of them turns out to have no
2100 * neighbouring mines, we add all its unopened neighbours to
2101 * the list as well.
2103 * FIXME: We really ought to be able to do this better than
2104 * using repeated N^2 scans of the grid.
2106 while (1) {
2107 int done_something = FALSE;
2109 for (yy = 0; yy < h; yy++)
2110 for (xx = 0; xx < w; xx++)
2111 if (state->grid[yy*w+xx] == -10) {
2112 int dx, dy, v;
2114 assert(!state->layout->mines[yy*w+xx]);
2116 v = 0;
2118 for (dx = -1; dx <= +1; dx++)
2119 for (dy = -1; dy <= +1; dy++)
2120 if (xx+dx >= 0 && xx+dx < state->w &&
2121 yy+dy >= 0 && yy+dy < state->h &&
2122 state->layout->mines[(yy+dy)*w+(xx+dx)])
2123 v++;
2125 state->grid[yy*w+xx] = v;
2127 if (v == 0) {
2128 for (dx = -1; dx <= +1; dx++)
2129 for (dy = -1; dy <= +1; dy++)
2130 if (xx+dx >= 0 && xx+dx < state->w &&
2131 yy+dy >= 0 && yy+dy < state->h &&
2132 state->grid[(yy+dy)*w+(xx+dx)] == -2)
2133 state->grid[(yy+dy)*w+(xx+dx)] = -10;
2136 done_something = TRUE;
2139 if (!done_something)
2140 break;
2144 * Finally, scan the grid and see if exactly as many squares
2145 * are still covered as there are mines. If so, set the `won'
2146 * flag and fill in mine markers on all covered squares.
2148 nmines = ncovered = 0;
2149 for (yy = 0; yy < h; yy++)
2150 for (xx = 0; xx < w; xx++) {
2151 if (state->grid[yy*w+xx] < 0)
2152 ncovered++;
2153 if (state->layout->mines[yy*w+xx])
2154 nmines++;
2156 assert(ncovered >= nmines);
2157 if (ncovered == nmines) {
2158 for (yy = 0; yy < h; yy++)
2159 for (xx = 0; xx < w; xx++) {
2160 if (state->grid[yy*w+xx] < 0)
2161 state->grid[yy*w+xx] = -1;
2163 state->won = TRUE;
2166 return 0;
2169 static game_state *new_game(midend *me, game_params *params, char *desc)
2171 game_state *state = snew(game_state);
2172 int i, wh, x, y, ret, masked;
2173 unsigned char *bmp;
2175 state->w = params->w;
2176 state->h = params->h;
2177 state->n = params->n;
2178 state->dead = state->won = FALSE;
2179 state->used_solve = FALSE;
2181 wh = state->w * state->h;
2183 state->layout = snew(struct mine_layout);
2184 memset(state->layout, 0, sizeof(struct mine_layout));
2185 state->layout->refcount = 1;
2187 state->grid = snewn(wh, signed char);
2188 memset(state->grid, -2, wh);
2190 if (*desc == 'r') {
2191 desc++;
2192 state->layout->n = atoi(desc);
2193 while (*desc && isdigit((unsigned char)*desc))
2194 desc++; /* skip over mine count */
2195 if (*desc) desc++; /* eat comma */
2196 if (*desc == 'a')
2197 state->layout->unique = FALSE;
2198 else
2199 state->layout->unique = TRUE;
2200 desc++;
2201 if (*desc) desc++; /* eat comma */
2203 state->layout->mines = NULL;
2204 state->layout->rs = random_state_decode(desc);
2205 state->layout->me = me;
2207 } else {
2208 state->layout->rs = NULL;
2209 state->layout->me = NULL;
2210 state->layout->mines = snewn(wh, char);
2212 if (*desc && isdigit((unsigned char)*desc)) {
2213 x = atoi(desc);
2214 while (*desc && isdigit((unsigned char)*desc))
2215 desc++; /* skip over x coordinate */
2216 if (*desc) desc++; /* eat comma */
2217 y = atoi(desc);
2218 while (*desc && isdigit((unsigned char)*desc))
2219 desc++; /* skip over y coordinate */
2220 if (*desc) desc++; /* eat comma */
2221 } else {
2222 x = y = -1;
2225 if (*desc == 'm') {
2226 masked = TRUE;
2227 desc++;
2228 } else {
2229 if (*desc == 'u')
2230 desc++;
2232 * We permit game IDs to be entered by hand without the
2233 * masking transformation.
2235 masked = FALSE;
2238 bmp = snewn((wh + 7) / 8, unsigned char);
2239 memset(bmp, 0, (wh + 7) / 8);
2240 for (i = 0; i < (wh+3)/4; i++) {
2241 int c = desc[i];
2242 int v;
2244 assert(c != 0); /* validate_desc should have caught */
2245 if (c >= '0' && c <= '9')
2246 v = c - '0';
2247 else if (c >= 'a' && c <= 'f')
2248 v = c - 'a' + 10;
2249 else if (c >= 'A' && c <= 'F')
2250 v = c - 'A' + 10;
2251 else
2252 v = 0;
2254 bmp[i / 2] |= v << (4 * (1 - (i % 2)));
2257 if (masked)
2258 obfuscate_bitmap(bmp, wh, TRUE);
2260 memset(state->layout->mines, 0, wh);
2261 for (i = 0; i < wh; i++) {
2262 if (bmp[i / 8] & (0x80 >> (i % 8)))
2263 state->layout->mines[i] = 1;
2266 if (x >= 0 && y >= 0)
2267 ret = open_square(state, x, y);
2268 sfree(bmp);
2271 return state;
2274 static game_state *dup_game(game_state *state)
2276 game_state *ret = snew(game_state);
2278 ret->w = state->w;
2279 ret->h = state->h;
2280 ret->n = state->n;
2281 ret->dead = state->dead;
2282 ret->won = state->won;
2283 ret->used_solve = state->used_solve;
2284 ret->layout = state->layout;
2285 ret->layout->refcount++;
2286 ret->grid = snewn(ret->w * ret->h, signed char);
2287 memcpy(ret->grid, state->grid, ret->w * ret->h);
2289 return ret;
2292 static void free_game(game_state *state)
2294 if (--state->layout->refcount <= 0) {
2295 sfree(state->layout->mines);
2296 if (state->layout->rs)
2297 random_free(state->layout->rs);
2298 sfree(state->layout);
2300 sfree(state->grid);
2301 sfree(state);
2304 static char *solve_game(game_state *state, game_state *currstate,
2305 char *aux, char **error)
2307 if (!state->layout->mines) {
2308 *error = "Game has not been started yet";
2309 return NULL;
2312 return dupstr("S");
2315 static int game_can_format_as_text_now(game_params *params)
2317 return TRUE;
2320 static char *game_text_format(game_state *state)
2322 char *ret;
2323 int x, y;
2325 ret = snewn((state->w + 1) * state->h + 1, char);
2326 for (y = 0; y < state->h; y++) {
2327 for (x = 0; x < state->w; x++) {
2328 int v = state->grid[y*state->w+x];
2329 if (v == 0)
2330 v = '-';
2331 else if (v >= 1 && v <= 8)
2332 v = '0' + v;
2333 else if (v == -1)
2334 v = '*';
2335 else if (v == -2 || v == -3)
2336 v = '?';
2337 else if (v >= 64)
2338 v = '!';
2339 ret[y * (state->w+1) + x] = v;
2341 ret[y * (state->w+1) + state->w] = '\n';
2343 ret[(state->w + 1) * state->h] = '\0';
2345 return ret;
2348 struct game_ui {
2349 int hx, hy, hradius; /* for mouse-down highlights */
2350 int validradius;
2351 int flash_is_death;
2352 int deaths, completed;
2355 static game_ui *new_ui(game_state *state)
2357 game_ui *ui = snew(game_ui);
2358 ui->hx = ui->hy = -1;
2359 ui->hradius = ui->validradius = 0;
2360 ui->deaths = 0;
2361 ui->completed = FALSE;
2362 ui->flash_is_death = FALSE; /* *shrug* */
2363 return ui;
2366 static void free_ui(game_ui *ui)
2368 sfree(ui);
2371 static char *encode_ui(game_ui *ui)
2373 char buf[80];
2375 * The deaths counter and completion status need preserving
2376 * across a serialisation.
2378 sprintf(buf, "D%d", ui->deaths);
2379 if (ui->completed)
2380 strcat(buf, "C");
2381 return dupstr(buf);
2384 static void decode_ui(game_ui *ui, char *encoding)
2386 int p= 0;
2387 sscanf(encoding, "D%d%n", &ui->deaths, &p);
2388 if (encoding[p] == 'C')
2389 ui->completed = TRUE;
2392 static void game_changed_state(game_ui *ui, game_state *oldstate,
2393 game_state *newstate)
2395 if (newstate->won)
2396 ui->completed = TRUE;
2399 struct game_drawstate {
2400 int w, h, started, tilesize, bg;
2401 signed char *grid;
2403 * Items in this `grid' array have all the same values as in
2404 * the game_state grid, and in addition:
2406 * - -10 means the tile was drawn `specially' as a result of a
2407 * flash, so it will always need redrawing.
2409 * - -22 and -23 mean the tile is highlighted for a possible
2410 * click.
2414 static char *interpret_move(game_state *from, game_ui *ui, game_drawstate *ds,
2415 int x, int y, int button)
2417 int cx, cy;
2418 char buf[256];
2420 if (from->dead || from->won)
2421 return NULL; /* no further moves permitted */
2423 if (!IS_MOUSE_DOWN(button) && !IS_MOUSE_DRAG(button) &&
2424 !IS_MOUSE_RELEASE(button))
2425 return NULL;
2427 cx = FROMCOORD(x);
2428 cy = FROMCOORD(y);
2430 if (button == LEFT_BUTTON || button == LEFT_DRAG ||
2431 button == MIDDLE_BUTTON || button == MIDDLE_DRAG) {
2432 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
2433 return NULL;
2436 * Mouse-downs and mouse-drags just cause highlighting
2437 * updates.
2439 ui->hx = cx;
2440 ui->hy = cy;
2441 ui->hradius = (from->grid[cy*from->w+cx] >= 0 ? 1 : 0);
2442 if (button == LEFT_BUTTON)
2443 ui->validradius = ui->hradius;
2444 else if (button == MIDDLE_BUTTON)
2445 ui->validradius = 1;
2446 return "";
2449 if (button == RIGHT_BUTTON) {
2450 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
2451 return NULL;
2454 * Right-clicking only works on a covered square, and it
2455 * toggles between -1 (marked as mine) and -2 (not marked
2456 * as mine).
2458 * FIXME: question marks.
2460 if (from->grid[cy * from->w + cx] != -2 &&
2461 from->grid[cy * from->w + cx] != -1)
2462 return NULL;
2464 sprintf(buf, "F%d,%d", cx, cy);
2465 return dupstr(buf);
2468 if (button == LEFT_RELEASE || button == MIDDLE_RELEASE) {
2469 ui->hx = ui->hy = -1;
2470 ui->hradius = 0;
2473 * At this stage we must never return NULL: we have adjusted
2474 * the ui, so at worst we return "".
2476 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
2477 return "";
2480 * Left-clicking on a covered square opens a tile. Not
2481 * permitted if the tile is marked as a mine, for safety.
2482 * (Unmark it and _then_ open it.)
2484 if (button == LEFT_RELEASE &&
2485 (from->grid[cy * from->w + cx] == -2 ||
2486 from->grid[cy * from->w + cx] == -3) &&
2487 ui->validradius == 0) {
2488 /* Check if you've killed yourself. */
2489 if (from->layout->mines && from->layout->mines[cy * from->w + cx])
2490 ui->deaths++;
2492 sprintf(buf, "O%d,%d", cx, cy);
2493 return dupstr(buf);
2497 * Left-clicking or middle-clicking on an uncovered tile:
2498 * first we check to see if the number of mine markers
2499 * surrounding the tile is equal to its mine count, and if
2500 * so then we open all other surrounding squares.
2502 if (from->grid[cy * from->w + cx] > 0 && ui->validradius == 1) {
2503 int dy, dx, n;
2505 /* Count mine markers. */
2506 n = 0;
2507 for (dy = -1; dy <= +1; dy++)
2508 for (dx = -1; dx <= +1; dx++)
2509 if (cx+dx >= 0 && cx+dx < from->w &&
2510 cy+dy >= 0 && cy+dy < from->h) {
2511 if (from->grid[(cy+dy)*from->w+(cx+dx)] == -1)
2512 n++;
2515 if (n == from->grid[cy * from->w + cx]) {
2518 * Now see if any of the squares we're clearing
2519 * contains a mine (which will happen iff you've
2520 * incorrectly marked the mines around the clicked
2521 * square). If so, we open _just_ those squares, to
2522 * reveal as little additional information as we
2523 * can.
2525 char *p = buf;
2526 char *sep = "";
2528 for (dy = -1; dy <= +1; dy++)
2529 for (dx = -1; dx <= +1; dx++)
2530 if (cx+dx >= 0 && cx+dx < from->w &&
2531 cy+dy >= 0 && cy+dy < from->h) {
2532 if (from->grid[(cy+dy)*from->w+(cx+dx)] != -1 &&
2533 from->layout->mines &&
2534 from->layout->mines[(cy+dy)*from->w+(cx+dx)]) {
2535 p += sprintf(p, "%sO%d,%d", sep, cx+dx, cy+dy);
2536 sep = ";";
2540 if (p > buf) {
2541 ui->deaths++;
2542 } else {
2543 sprintf(buf, "C%d,%d", cx, cy);
2546 return dupstr(buf);
2550 return "";
2553 return NULL;
2556 static game_state *execute_move(game_state *from, char *move)
2558 int cy, cx;
2559 game_state *ret;
2561 if (!strcmp(move, "S")) {
2563 * Simply expose the entire grid as if it were a completed
2564 * solution.
2566 int yy, xx;
2568 ret = dup_game(from);
2569 for (yy = 0; yy < ret->h; yy++)
2570 for (xx = 0; xx < ret->w; xx++) {
2572 if (ret->layout->mines[yy*ret->w+xx]) {
2573 ret->grid[yy*ret->w+xx] = -1;
2574 } else {
2575 int dx, dy, v;
2577 v = 0;
2579 for (dx = -1; dx <= +1; dx++)
2580 for (dy = -1; dy <= +1; dy++)
2581 if (xx+dx >= 0 && xx+dx < ret->w &&
2582 yy+dy >= 0 && yy+dy < ret->h &&
2583 ret->layout->mines[(yy+dy)*ret->w+(xx+dx)])
2584 v++;
2586 ret->grid[yy*ret->w+xx] = v;
2589 ret->used_solve = TRUE;
2590 ret->won = TRUE;
2592 return ret;
2593 } else {
2594 ret = dup_game(from);
2596 while (*move) {
2597 if (move[0] == 'F' &&
2598 sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
2599 cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) {
2600 ret->grid[cy * from->w + cx] ^= (-2 ^ -1);
2601 } else if (move[0] == 'O' &&
2602 sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
2603 cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) {
2604 open_square(ret, cx, cy);
2605 } else if (move[0] == 'C' &&
2606 sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
2607 cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) {
2608 int dx, dy;
2610 for (dy = -1; dy <= +1; dy++)
2611 for (dx = -1; dx <= +1; dx++)
2612 if (cx+dx >= 0 && cx+dx < ret->w &&
2613 cy+dy >= 0 && cy+dy < ret->h &&
2614 (ret->grid[(cy+dy)*ret->w+(cx+dx)] == -2 ||
2615 ret->grid[(cy+dy)*ret->w+(cx+dx)] == -3))
2616 open_square(ret, cx+dx, cy+dy);
2617 } else {
2618 free_game(ret);
2619 return NULL;
2622 while (*move && *move != ';') move++;
2623 if (*move) move++;
2626 return ret;
2630 /* ----------------------------------------------------------------------
2631 * Drawing routines.
2634 static void game_compute_size(game_params *params, int tilesize,
2635 int *x, int *y)
2637 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2638 struct { int tilesize; } ads, *ds = &ads;
2639 ads.tilesize = tilesize;
2641 *x = BORDER * 2 + TILE_SIZE * params->w;
2642 *y = BORDER * 2 + TILE_SIZE * params->h;
2645 static void game_set_size(drawing *dr, game_drawstate *ds,
2646 game_params *params, int tilesize)
2648 ds->tilesize = tilesize;
2651 static float *game_colours(frontend *fe, int *ncolours)
2653 float *ret = snewn(3 * NCOLOURS, float);
2655 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
2657 ret[COL_BACKGROUND2 * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 19.0 / 20.0;
2658 ret[COL_BACKGROUND2 * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 19.0 / 20.0;
2659 ret[COL_BACKGROUND2 * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 19.0 / 20.0;
2661 ret[COL_1 * 3 + 0] = 0.0F;
2662 ret[COL_1 * 3 + 1] = 0.0F;
2663 ret[COL_1 * 3 + 2] = 1.0F;
2665 ret[COL_2 * 3 + 0] = 0.0F;
2666 ret[COL_2 * 3 + 1] = 0.5F;
2667 ret[COL_2 * 3 + 2] = 0.0F;
2669 ret[COL_3 * 3 + 0] = 1.0F;
2670 ret[COL_3 * 3 + 1] = 0.0F;
2671 ret[COL_3 * 3 + 2] = 0.0F;
2673 ret[COL_4 * 3 + 0] = 0.0F;
2674 ret[COL_4 * 3 + 1] = 0.0F;
2675 ret[COL_4 * 3 + 2] = 0.5F;
2677 ret[COL_5 * 3 + 0] = 0.5F;
2678 ret[COL_5 * 3 + 1] = 0.0F;
2679 ret[COL_5 * 3 + 2] = 0.0F;
2681 ret[COL_6 * 3 + 0] = 0.0F;
2682 ret[COL_6 * 3 + 1] = 0.5F;
2683 ret[COL_6 * 3 + 2] = 0.5F;
2685 ret[COL_7 * 3 + 0] = 0.0F;
2686 ret[COL_7 * 3 + 1] = 0.0F;
2687 ret[COL_7 * 3 + 2] = 0.0F;
2689 ret[COL_8 * 3 + 0] = 0.5F;
2690 ret[COL_8 * 3 + 1] = 0.5F;
2691 ret[COL_8 * 3 + 2] = 0.5F;
2693 ret[COL_MINE * 3 + 0] = 0.0F;
2694 ret[COL_MINE * 3 + 1] = 0.0F;
2695 ret[COL_MINE * 3 + 2] = 0.0F;
2697 ret[COL_BANG * 3 + 0] = 1.0F;
2698 ret[COL_BANG * 3 + 1] = 0.0F;
2699 ret[COL_BANG * 3 + 2] = 0.0F;
2701 ret[COL_CROSS * 3 + 0] = 1.0F;
2702 ret[COL_CROSS * 3 + 1] = 0.0F;
2703 ret[COL_CROSS * 3 + 2] = 0.0F;
2705 ret[COL_FLAG * 3 + 0] = 1.0F;
2706 ret[COL_FLAG * 3 + 1] = 0.0F;
2707 ret[COL_FLAG * 3 + 2] = 0.0F;
2709 ret[COL_FLAGBASE * 3 + 0] = 0.0F;
2710 ret[COL_FLAGBASE * 3 + 1] = 0.0F;
2711 ret[COL_FLAGBASE * 3 + 2] = 0.0F;
2713 ret[COL_QUERY * 3 + 0] = 0.0F;
2714 ret[COL_QUERY * 3 + 1] = 0.0F;
2715 ret[COL_QUERY * 3 + 2] = 0.0F;
2717 ret[COL_HIGHLIGHT * 3 + 0] = 1.0F;
2718 ret[COL_HIGHLIGHT * 3 + 1] = 1.0F;
2719 ret[COL_HIGHLIGHT * 3 + 2] = 1.0F;
2721 ret[COL_LOWLIGHT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2.0 / 3.0;
2722 ret[COL_LOWLIGHT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2.0 / 3.0;
2723 ret[COL_LOWLIGHT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2.0 / 3.0;
2725 ret[COL_WRONGNUMBER * 3 + 0] = 1.0F;
2726 ret[COL_WRONGNUMBER * 3 + 1] = 0.6F;
2727 ret[COL_WRONGNUMBER * 3 + 2] = 0.6F;
2729 *ncolours = NCOLOURS;
2730 return ret;
2733 static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
2735 struct game_drawstate *ds = snew(struct game_drawstate);
2737 ds->w = state->w;
2738 ds->h = state->h;
2739 ds->started = FALSE;
2740 ds->tilesize = 0; /* not decided yet */
2741 ds->grid = snewn(ds->w * ds->h, signed char);
2742 ds->bg = -1;
2744 memset(ds->grid, -99, ds->w * ds->h);
2746 return ds;
2749 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
2751 sfree(ds->grid);
2752 sfree(ds);
2755 static void draw_tile(drawing *dr, game_drawstate *ds,
2756 int x, int y, int v, int bg)
2758 if (v < 0) {
2759 int coords[12];
2760 int hl = 0;
2762 if (v == -22 || v == -23) {
2763 v += 20;
2766 * Omit the highlights in this case.
2768 draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE,
2769 bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg);
2770 draw_line(dr, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
2771 draw_line(dr, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
2772 } else {
2774 * Draw highlights to indicate the square is covered.
2776 coords[0] = x + TILE_SIZE - 1;
2777 coords[1] = y + TILE_SIZE - 1;
2778 coords[2] = x + TILE_SIZE - 1;
2779 coords[3] = y;
2780 coords[4] = x;
2781 coords[5] = y + TILE_SIZE - 1;
2782 draw_polygon(dr, coords, 3, COL_LOWLIGHT ^ hl, COL_LOWLIGHT ^ hl);
2784 coords[0] = x;
2785 coords[1] = y;
2786 draw_polygon(dr, coords, 3, COL_HIGHLIGHT ^ hl,
2787 COL_HIGHLIGHT ^ hl);
2789 draw_rect(dr, x + HIGHLIGHT_WIDTH, y + HIGHLIGHT_WIDTH,
2790 TILE_SIZE - 2*HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH,
2791 bg);
2794 if (v == -1) {
2796 * Draw a flag.
2798 #define SETCOORD(n, dx, dy) do { \
2799 coords[(n)*2+0] = x + TILE_SIZE * (dx); \
2800 coords[(n)*2+1] = y + TILE_SIZE * (dy); \
2801 } while (0)
2802 SETCOORD(0, 0.6, 0.35);
2803 SETCOORD(1, 0.6, 0.7);
2804 SETCOORD(2, 0.8, 0.8);
2805 SETCOORD(3, 0.25, 0.8);
2806 SETCOORD(4, 0.55, 0.7);
2807 SETCOORD(5, 0.55, 0.35);
2808 draw_polygon(dr, coords, 6, COL_FLAGBASE, COL_FLAGBASE);
2810 SETCOORD(0, 0.6, 0.2);
2811 SETCOORD(1, 0.6, 0.5);
2812 SETCOORD(2, 0.2, 0.35);
2813 draw_polygon(dr, coords, 3, COL_FLAG, COL_FLAG);
2814 #undef SETCOORD
2816 } else if (v == -3) {
2818 * Draw a question mark.
2820 draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
2821 FONT_VARIABLE, TILE_SIZE * 6 / 8,
2822 ALIGN_VCENTRE | ALIGN_HCENTRE,
2823 COL_QUERY, "?");
2825 } else {
2827 * Clear the square to the background colour, and draw thin
2828 * grid lines along the top and left.
2830 * Exception is that for value 65 (mine we've just trodden
2831 * on), we clear the square to COL_BANG.
2833 if (v & 32) {
2834 bg = COL_WRONGNUMBER;
2835 v &= ~32;
2837 draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE,
2838 (v == 65 ? COL_BANG :
2839 bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg));
2840 draw_line(dr, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
2841 draw_line(dr, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
2843 if (v > 0 && v <= 8) {
2845 * Mark a number.
2847 char str[2];
2848 str[0] = v + '0';
2849 str[1] = '\0';
2850 draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
2851 FONT_VARIABLE, TILE_SIZE * 7 / 8,
2852 ALIGN_VCENTRE | ALIGN_HCENTRE,
2853 (COL_1 - 1) + v, str);
2855 } else if (v >= 64) {
2857 * Mark a mine.
2859 * FIXME: this could be done better!
2861 #if 0
2862 draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
2863 FONT_VARIABLE, TILE_SIZE * 7 / 8,
2864 ALIGN_VCENTRE | ALIGN_HCENTRE,
2865 COL_MINE, "*");
2866 #else
2868 int cx = x + TILE_SIZE / 2;
2869 int cy = y + TILE_SIZE / 2;
2870 int r = TILE_SIZE / 2 - 3;
2871 int coords[4*5*2];
2872 int xdx = 1, xdy = 0, ydx = 0, ydy = 1;
2873 int tdx, tdy, i;
2875 for (i = 0; i < 4*5*2; i += 5*2) {
2876 coords[i+2*0+0] = cx - r/6*xdx + r*4/5*ydx;
2877 coords[i+2*0+1] = cy - r/6*xdy + r*4/5*ydy;
2878 coords[i+2*1+0] = cx - r/6*xdx + r*ydx;
2879 coords[i+2*1+1] = cy - r/6*xdy + r*ydy;
2880 coords[i+2*2+0] = cx + r/6*xdx + r*ydx;
2881 coords[i+2*2+1] = cy + r/6*xdy + r*ydy;
2882 coords[i+2*3+0] = cx + r/6*xdx + r*4/5*ydx;
2883 coords[i+2*3+1] = cy + r/6*xdy + r*4/5*ydy;
2884 coords[i+2*4+0] = cx + r*3/5*xdx + r*3/5*ydx;
2885 coords[i+2*4+1] = cy + r*3/5*xdy + r*3/5*ydy;
2887 tdx = ydx;
2888 tdy = ydy;
2889 ydx = xdx;
2890 ydy = xdy;
2891 xdx = -tdx;
2892 xdy = -tdy;
2895 draw_polygon(dr, coords, 5*4, COL_MINE, COL_MINE);
2897 draw_rect(dr, cx-r/3, cy-r/3, r/3, r/4, COL_HIGHLIGHT);
2899 #endif
2901 if (v == 66) {
2903 * Cross through the mine.
2905 int dx;
2906 for (dx = -1; dx <= +1; dx++) {
2907 draw_line(dr, x + 3 + dx, y + 2,
2908 x + TILE_SIZE - 3 + dx,
2909 y + TILE_SIZE - 2, COL_CROSS);
2910 draw_line(dr, x + TILE_SIZE - 3 + dx, y + 2,
2911 x + 3 + dx, y + TILE_SIZE - 2,
2912 COL_CROSS);
2918 draw_update(dr, x, y, TILE_SIZE, TILE_SIZE);
2921 static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
2922 game_state *state, int dir, game_ui *ui,
2923 float animtime, float flashtime)
2925 int x, y;
2926 int mines, markers, bg;
2928 if (flashtime) {
2929 int frame = (flashtime / FLASH_FRAME);
2930 if (frame % 2)
2931 bg = (ui->flash_is_death ? COL_BACKGROUND : COL_LOWLIGHT);
2932 else
2933 bg = (ui->flash_is_death ? COL_BANG : COL_HIGHLIGHT);
2934 } else
2935 bg = COL_BACKGROUND;
2937 if (!ds->started) {
2938 int coords[10];
2940 draw_rect(dr, 0, 0,
2941 TILE_SIZE * state->w + 2 * BORDER,
2942 TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
2943 draw_update(dr, 0, 0,
2944 TILE_SIZE * state->w + 2 * BORDER,
2945 TILE_SIZE * state->h + 2 * BORDER);
2948 * Recessed area containing the whole puzzle.
2950 coords[0] = COORD(state->w) + OUTER_HIGHLIGHT_WIDTH - 1;
2951 coords[1] = COORD(state->h) + OUTER_HIGHLIGHT_WIDTH - 1;
2952 coords[2] = COORD(state->w) + OUTER_HIGHLIGHT_WIDTH - 1;
2953 coords[3] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
2954 coords[4] = coords[2] - TILE_SIZE;
2955 coords[5] = coords[3] + TILE_SIZE;
2956 coords[8] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
2957 coords[9] = COORD(state->h) + OUTER_HIGHLIGHT_WIDTH - 1;
2958 coords[6] = coords[8] + TILE_SIZE;
2959 coords[7] = coords[9] - TILE_SIZE;
2960 draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT);
2962 coords[1] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
2963 coords[0] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
2964 draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT);
2966 ds->started = TRUE;
2970 * Now draw the tiles. Also in this loop, count up the number
2971 * of mines and mine markers.
2973 mines = markers = 0;
2974 for (y = 0; y < ds->h; y++)
2975 for (x = 0; x < ds->w; x++) {
2976 int v = state->grid[y*ds->w+x];
2978 if (v == -1)
2979 markers++;
2980 if (state->layout->mines && state->layout->mines[y*ds->w+x])
2981 mines++;
2983 if (v >= 0 && v <= 8) {
2985 * Count up the flags around this tile, and if
2986 * there are too _many_, highlight the tile.
2988 int dx, dy, flags = 0;
2990 for (dy = -1; dy <= +1; dy++)
2991 for (dx = -1; dx <= +1; dx++) {
2992 int nx = x+dx, ny = y+dy;
2993 if (nx >= 0 && nx < ds->w &&
2994 ny >= 0 && ny < ds->h &&
2995 state->grid[ny*ds->w+nx] == -1)
2996 flags++;
2999 if (flags > v)
3000 v |= 32;
3003 if ((v == -2 || v == -3) &&
3004 (abs(x-ui->hx) <= ui->hradius && abs(y-ui->hy) <= ui->hradius))
3005 v -= 20;
3007 if (ds->grid[y*ds->w+x] != v || bg != ds->bg) {
3008 draw_tile(dr, ds, COORD(x), COORD(y), v, bg);
3009 ds->grid[y*ds->w+x] = v;
3012 ds->bg = bg;
3014 if (!state->layout->mines)
3015 mines = state->layout->n;
3018 * Update the status bar.
3021 char statusbar[512];
3022 if (state->dead) {
3023 sprintf(statusbar, "DEAD!");
3024 } else if (state->won) {
3025 if (state->used_solve)
3026 sprintf(statusbar, "Auto-solved.");
3027 else
3028 sprintf(statusbar, "COMPLETED!");
3029 } else {
3030 sprintf(statusbar, "Marked: %d / %d", markers, mines);
3032 if (ui->deaths)
3033 sprintf(statusbar + strlen(statusbar),
3034 " Deaths: %d", ui->deaths);
3035 status_bar(dr, statusbar);
3039 static float game_anim_length(game_state *oldstate, game_state *newstate,
3040 int dir, game_ui *ui)
3042 return 0.0F;
3045 static float game_flash_length(game_state *oldstate, game_state *newstate,
3046 int dir, game_ui *ui)
3048 if (oldstate->used_solve || newstate->used_solve)
3049 return 0.0F;
3051 if (dir > 0 && !oldstate->dead && !oldstate->won) {
3052 if (newstate->dead) {
3053 ui->flash_is_death = TRUE;
3054 return 3 * FLASH_FRAME;
3056 if (newstate->won) {
3057 ui->flash_is_death = FALSE;
3058 return 2 * FLASH_FRAME;
3061 return 0.0F;
3064 static int game_timing_state(game_state *state, game_ui *ui)
3066 if (state->dead || state->won || ui->completed || !state->layout->mines)
3067 return FALSE;
3068 return TRUE;
3071 static void game_print_size(game_params *params, float *x, float *y)
3075 static void game_print(drawing *dr, game_state *state, int tilesize)
3079 #ifdef COMBINED
3080 #define thegame mines
3081 #endif
3083 const struct game thegame = {
3084 "Mines", "games.mines", "mines",
3085 default_params,
3086 game_fetch_preset,
3087 decode_params,
3088 encode_params,
3089 free_params,
3090 dup_params,
3091 TRUE, game_configure, custom_params,
3092 validate_params,
3093 new_game_desc,
3094 validate_desc,
3095 new_game,
3096 dup_game,
3097 free_game,
3098 TRUE, solve_game,
3099 TRUE, game_can_format_as_text_now, game_text_format,
3100 new_ui,
3101 free_ui,
3102 encode_ui,
3103 decode_ui,
3104 game_changed_state,
3105 interpret_move,
3106 execute_move,
3107 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
3108 game_colours,
3109 game_new_drawstate,
3110 game_free_drawstate,
3111 game_redraw,
3112 game_anim_length,
3113 game_flash_length,
3114 FALSE, FALSE, game_print_size, game_print,
3115 TRUE, /* wants_statusbar */
3116 TRUE, game_timing_state,
3117 BUTTON_BEATS(LEFT_BUTTON, RIGHT_BUTTON) | REQUIRE_RBUTTON,
3120 #ifdef STANDALONE_OBFUSCATOR
3123 * Vaguely useful stand-alone program which translates between
3124 * obfuscated and clear Mines game descriptions. Pass in a game
3125 * description on the command line, and if it's clear it will be
3126 * obfuscated and vice versa. The output text should also be a
3127 * valid game ID describing the same game. Like this:
3129 * $ ./mineobfusc 9x9:4,4,mb071b49fbd1cb6a0d5868
3130 * 9x9:4,4,004000007c00010022080
3131 * $ ./mineobfusc 9x9:4,4,004000007c00010022080
3132 * 9x9:4,4,mb071b49fbd1cb6a0d5868
3135 int main(int argc, char **argv)
3137 game_params *p;
3138 game_state *s;
3139 char *id = NULL, *desc, *err;
3140 int y, x;
3142 while (--argc > 0) {
3143 char *p = *++argv;
3144 if (*p == '-') {
3145 fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
3146 return 1;
3147 } else {
3148 id = p;
3152 if (!id) {
3153 fprintf(stderr, "usage: %s <game_id>\n", argv[0]);
3154 return 1;
3157 desc = strchr(id, ':');
3158 if (!desc) {
3159 fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
3160 return 1;
3162 *desc++ = '\0';
3164 p = default_params();
3165 decode_params(p, id);
3166 err = validate_desc(p, desc);
3167 if (err) {
3168 fprintf(stderr, "%s: %s\n", argv[0], err);
3169 return 1;
3171 s = new_game(NULL, p, desc);
3173 x = atoi(desc);
3174 while (*desc && *desc != ',') desc++;
3175 if (*desc) desc++;
3176 y = atoi(desc);
3177 while (*desc && *desc != ',') desc++;
3178 if (*desc) desc++;
3180 printf("%s:%s\n", id, describe_layout(s->layout->mines,
3181 p->w * p->h,
3182 x, y,
3183 (*desc != 'm')));
3185 return 0;
3188 #endif