Keyboard control patch for Twiddle, from James H.
[sgt-puzzles/ydirson.git] / mines.c
blobaf6aa443e4c16d3686bcd367220554d767e29bf9
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 COL_CURSOR,
27 NCOLOURS
30 #define PREFERRED_TILE_SIZE 20
31 #define TILE_SIZE (ds->tilesize)
32 #ifdef SMALL_SCREEN
33 #define BORDER 8
34 #else
35 #define BORDER (TILE_SIZE * 3 / 2)
36 #endif
37 #define HIGHLIGHT_WIDTH (TILE_SIZE / 10)
38 #define OUTER_HIGHLIGHT_WIDTH (BORDER / 10)
39 #define COORD(x) ( (x) * TILE_SIZE + BORDER )
40 #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 )
42 #define FLASH_FRAME 0.13F
44 struct game_params {
45 int w, h, n;
46 int unique;
49 struct mine_layout {
51 * This structure is shared between all the game_states for a
52 * given instance of the puzzle, so we reference-count it.
54 int refcount;
55 char *mines;
57 * If we haven't yet actually generated the mine layout, here's
58 * all the data we will need to do so.
60 int n, unique;
61 random_state *rs;
62 midend *me; /* to give back the new game desc */
65 struct game_state {
66 int w, h, n, dead, won;
67 int used_solve;
68 struct mine_layout *layout; /* real mine positions */
69 signed char *grid; /* player knowledge */
71 * Each item in the `grid' array is one of the following values:
73 * - 0 to 8 mean the square is open and has a surrounding mine
74 * count.
76 * - -1 means the square is marked as a mine.
78 * - -2 means the square is unknown.
80 * - -3 means the square is marked with a question mark
81 * (FIXME: do we even want to bother with this?).
83 * - 64 means the square has had a mine revealed when the game
84 * was lost.
86 * - 65 means the square had a mine revealed and this was the
87 * one the player hits.
89 * - 66 means the square has a crossed-out mine because the
90 * player had incorrectly marked it.
94 static game_params *default_params(void)
96 game_params *ret = snew(game_params);
98 ret->w = ret->h = 9;
99 ret->n = 10;
100 ret->unique = TRUE;
102 return ret;
105 static const struct game_params mines_presets[] = {
106 {9, 9, 10, TRUE},
107 {9, 9, 35, TRUE},
108 {16, 16, 40, TRUE},
109 {16, 16, 99, TRUE},
110 #ifndef SMALL_SCREEN
111 {30, 16, 99, TRUE},
112 {30, 16, 170, TRUE},
113 #endif
116 static int game_fetch_preset(int i, char **name, game_params **params)
118 game_params *ret;
119 char str[80];
121 if (i < 0 || i >= lenof(mines_presets))
122 return FALSE;
124 ret = snew(game_params);
125 *ret = mines_presets[i];
127 sprintf(str, "%dx%d, %d mines", ret->w, ret->h, ret->n);
129 *name = dupstr(str);
130 *params = ret;
131 return TRUE;
134 static void free_params(game_params *params)
136 sfree(params);
139 static game_params *dup_params(game_params *params)
141 game_params *ret = snew(game_params);
142 *ret = *params; /* structure copy */
143 return ret;
146 static void decode_params(game_params *params, char const *string)
148 char const *p = string;
150 params->w = atoi(p);
151 while (*p && isdigit((unsigned char)*p)) p++;
152 if (*p == 'x') {
153 p++;
154 params->h = atoi(p);
155 while (*p && isdigit((unsigned char)*p)) p++;
156 } else {
157 params->h = params->w;
159 if (*p == 'n') {
160 p++;
161 params->n = atoi(p);
162 while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++;
163 } else {
164 params->n = params->w * params->h / 10;
167 while (*p) {
168 if (*p == 'a') {
169 p++;
170 params->unique = FALSE;
171 } else
172 p++; /* skip any other gunk */
176 static char *encode_params(game_params *params, int full)
178 char ret[400];
179 int len;
181 len = sprintf(ret, "%dx%d", params->w, params->h);
183 * Mine count is a generation-time parameter, since it can be
184 * deduced from the mine bitmap!
186 if (full)
187 len += sprintf(ret+len, "n%d", params->n);
188 if (full && !params->unique)
189 ret[len++] = 'a';
190 assert(len < lenof(ret));
191 ret[len] = '\0';
193 return dupstr(ret);
196 static config_item *game_configure(game_params *params)
198 config_item *ret;
199 char buf[80];
201 ret = snewn(5, config_item);
203 ret[0].name = "Width";
204 ret[0].type = C_STRING;
205 sprintf(buf, "%d", params->w);
206 ret[0].sval = dupstr(buf);
207 ret[0].ival = 0;
209 ret[1].name = "Height";
210 ret[1].type = C_STRING;
211 sprintf(buf, "%d", params->h);
212 ret[1].sval = dupstr(buf);
213 ret[1].ival = 0;
215 ret[2].name = "Mines";
216 ret[2].type = C_STRING;
217 sprintf(buf, "%d", params->n);
218 ret[2].sval = dupstr(buf);
219 ret[2].ival = 0;
221 ret[3].name = "Ensure solubility";
222 ret[3].type = C_BOOLEAN;
223 ret[3].sval = NULL;
224 ret[3].ival = params->unique;
226 ret[4].name = NULL;
227 ret[4].type = C_END;
228 ret[4].sval = NULL;
229 ret[4].ival = 0;
231 return ret;
234 static game_params *custom_params(config_item *cfg)
236 game_params *ret = snew(game_params);
238 ret->w = atoi(cfg[0].sval);
239 ret->h = atoi(cfg[1].sval);
240 ret->n = atoi(cfg[2].sval);
241 if (strchr(cfg[2].sval, '%'))
242 ret->n = ret->n * (ret->w * ret->h) / 100;
243 ret->unique = cfg[3].ival;
245 return ret;
248 static char *validate_params(game_params *params, int full)
251 * Lower limit on grid size: each dimension must be at least 3.
252 * 1 is theoretically workable if rather boring, but 2 is a
253 * real problem: there is often _no_ way to generate a uniquely
254 * solvable 2xn Mines grid. You either run into two mines
255 * blocking the way and no idea what's behind them, or one mine
256 * and no way to know which of the two rows it's in. If the
257 * mine count is even you can create a soluble grid by packing
258 * all the mines at one end (so what when you hit a two-mine
259 * wall there are only as many covered squares left as there
260 * are mines); but if it's odd, you are doomed, because you
261 * _have_ to have a gap somewhere which you can't determine the
262 * position of.
264 if (full && params->unique && (params->w <= 2 || params->h <= 2))
265 return "Width and height must both be greater than two";
266 if (params->n > params->w * params->h - 9)
267 return "Too many mines for grid size";
270 * FIXME: Need more constraints here. Not sure what the
271 * sensible limits for Minesweeper actually are. The limits
272 * probably ought to change, however, depending on uniqueness.
275 return NULL;
278 /* ----------------------------------------------------------------------
279 * Minesweeper solver, used to ensure the generated grids are
280 * solvable without having to take risks.
284 * Count the bits in a word. Only needs to cope with 16 bits.
286 static int bitcount16(int inword)
288 unsigned int word = inword;
290 word = ((word & 0xAAAA) >> 1) + (word & 0x5555);
291 word = ((word & 0xCCCC) >> 2) + (word & 0x3333);
292 word = ((word & 0xF0F0) >> 4) + (word & 0x0F0F);
293 word = ((word & 0xFF00) >> 8) + (word & 0x00FF);
295 return (int)word;
299 * We use a tree234 to store a large number of small localised
300 * sets, each with a mine count. We also keep some of those sets
301 * linked together into a to-do list.
303 struct set {
304 short x, y, mask, mines;
305 int todo;
306 struct set *prev, *next;
309 static int setcmp(void *av, void *bv)
311 struct set *a = (struct set *)av;
312 struct set *b = (struct set *)bv;
314 if (a->y < b->y)
315 return -1;
316 else if (a->y > b->y)
317 return +1;
318 else if (a->x < b->x)
319 return -1;
320 else if (a->x > b->x)
321 return +1;
322 else if (a->mask < b->mask)
323 return -1;
324 else if (a->mask > b->mask)
325 return +1;
326 else
327 return 0;
330 struct setstore {
331 tree234 *sets;
332 struct set *todo_head, *todo_tail;
335 static struct setstore *ss_new(void)
337 struct setstore *ss = snew(struct setstore);
338 ss->sets = newtree234(setcmp);
339 ss->todo_head = ss->todo_tail = NULL;
340 return ss;
344 * Take two input sets, in the form (x,y,mask). Munge the first by
345 * taking either its intersection with the second or its difference
346 * with the second. Return the new mask part of the first set.
348 static int setmunge(int x1, int y1, int mask1, int x2, int y2, int mask2,
349 int diff)
352 * Adjust the second set so that it has the same x,y
353 * coordinates as the first.
355 if (abs(x2-x1) >= 3 || abs(y2-y1) >= 3) {
356 mask2 = 0;
357 } else {
358 while (x2 > x1) {
359 mask2 &= ~(4|32|256);
360 mask2 <<= 1;
361 x2--;
363 while (x2 < x1) {
364 mask2 &= ~(1|8|64);
365 mask2 >>= 1;
366 x2++;
368 while (y2 > y1) {
369 mask2 &= ~(64|128|256);
370 mask2 <<= 3;
371 y2--;
373 while (y2 < y1) {
374 mask2 &= ~(1|2|4);
375 mask2 >>= 3;
376 y2++;
381 * Invert the second set if `diff' is set (we're after A &~ B
382 * rather than A & B).
384 if (diff)
385 mask2 ^= 511;
388 * Now all that's left is a logical AND.
390 return mask1 & mask2;
393 static void ss_add_todo(struct setstore *ss, struct set *s)
395 if (s->todo)
396 return; /* already on it */
398 #ifdef SOLVER_DIAGNOSTICS
399 printf("adding set on todo list: %d,%d %03x %d\n",
400 s->x, s->y, s->mask, s->mines);
401 #endif
403 s->prev = ss->todo_tail;
404 if (s->prev)
405 s->prev->next = s;
406 else
407 ss->todo_head = s;
408 ss->todo_tail = s;
409 s->next = NULL;
410 s->todo = TRUE;
413 static void ss_add(struct setstore *ss, int x, int y, int mask, int mines)
415 struct set *s;
417 assert(mask != 0);
420 * Normalise so that x and y are genuinely the bounding
421 * rectangle.
423 while (!(mask & (1|8|64)))
424 mask >>= 1, x++;
425 while (!(mask & (1|2|4)))
426 mask >>= 3, y++;
429 * Create a set structure and add it to the tree.
431 s = snew(struct set);
432 s->x = x;
433 s->y = y;
434 s->mask = mask;
435 s->mines = mines;
436 s->todo = FALSE;
437 if (add234(ss->sets, s) != s) {
439 * This set already existed! Free it and return.
441 sfree(s);
442 return;
446 * We've added a new set to the tree, so put it on the todo
447 * list.
449 ss_add_todo(ss, s);
452 static void ss_remove(struct setstore *ss, struct set *s)
454 struct set *next = s->next, *prev = s->prev;
456 #ifdef SOLVER_DIAGNOSTICS
457 printf("removing set %d,%d %03x\n", s->x, s->y, s->mask);
458 #endif
460 * Remove s from the todo list.
462 if (prev)
463 prev->next = next;
464 else if (s == ss->todo_head)
465 ss->todo_head = next;
467 if (next)
468 next->prev = prev;
469 else if (s == ss->todo_tail)
470 ss->todo_tail = prev;
472 s->todo = FALSE;
475 * Remove s from the tree.
477 del234(ss->sets, s);
480 * Destroy the actual set structure.
482 sfree(s);
486 * Return a dynamically allocated list of all the sets which
487 * overlap a provided input set.
489 static struct set **ss_overlap(struct setstore *ss, int x, int y, int mask)
491 struct set **ret = NULL;
492 int nret = 0, retsize = 0;
493 int xx, yy;
495 for (xx = x-3; xx < x+3; xx++)
496 for (yy = y-3; yy < y+3; yy++) {
497 struct set stmp, *s;
498 int pos;
501 * Find the first set with these top left coordinates.
503 stmp.x = xx;
504 stmp.y = yy;
505 stmp.mask = 0;
507 if (findrelpos234(ss->sets, &stmp, NULL, REL234_GE, &pos)) {
508 while ((s = index234(ss->sets, pos)) != NULL &&
509 s->x == xx && s->y == yy) {
511 * This set potentially overlaps the input one.
512 * Compute the intersection to see if they
513 * really overlap, and add it to the list if
514 * so.
516 if (setmunge(x, y, mask, s->x, s->y, s->mask, FALSE)) {
518 * There's an overlap.
520 if (nret >= retsize) {
521 retsize = nret + 32;
522 ret = sresize(ret, retsize, struct set *);
524 ret[nret++] = s;
527 pos++;
532 ret = sresize(ret, nret+1, struct set *);
533 ret[nret] = NULL;
535 return ret;
539 * Get an element from the head of the set todo list.
541 static struct set *ss_todo(struct setstore *ss)
543 if (ss->todo_head) {
544 struct set *ret = ss->todo_head;
545 ss->todo_head = ret->next;
546 if (ss->todo_head)
547 ss->todo_head->prev = NULL;
548 else
549 ss->todo_tail = NULL;
550 ret->next = ret->prev = NULL;
551 ret->todo = FALSE;
552 return ret;
553 } else {
554 return NULL;
558 struct squaretodo {
559 int *next;
560 int head, tail;
563 static void std_add(struct squaretodo *std, int i)
565 if (std->tail >= 0)
566 std->next[std->tail] = i;
567 else
568 std->head = i;
569 std->tail = i;
570 std->next[i] = -1;
573 typedef int (*open_cb)(void *, int, int);
575 static void known_squares(int w, int h, struct squaretodo *std,
576 signed char *grid,
577 open_cb open, void *openctx,
578 int x, int y, int mask, int mine)
580 int xx, yy, bit;
582 bit = 1;
584 for (yy = 0; yy < 3; yy++)
585 for (xx = 0; xx < 3; xx++) {
586 if (mask & bit) {
587 int i = (y + yy) * w + (x + xx);
590 * It's possible that this square is _already_
591 * known, in which case we don't try to add it to
592 * the list twice.
594 if (grid[i] == -2) {
596 if (mine) {
597 grid[i] = -1; /* and don't open it! */
598 } else {
599 grid[i] = open(openctx, x + xx, y + yy);
600 assert(grid[i] != -1); /* *bang* */
602 std_add(std, i);
606 bit <<= 1;
611 * This is data returned from the `perturb' function. It details
612 * which squares have become mines and which have become clear. The
613 * solver is (of course) expected to honourably not use that
614 * knowledge directly, but to efficently adjust its internal data
615 * structures and proceed based on only the information it
616 * legitimately has.
618 struct perturbation {
619 int x, y;
620 int delta; /* +1 == become a mine; -1 == cleared */
622 struct perturbations {
623 int n;
624 struct perturbation *changes;
628 * Main solver entry point. You give it a grid of existing
629 * knowledge (-1 for a square known to be a mine, 0-8 for empty
630 * squares with a given number of neighbours, -2 for completely
631 * unknown), plus a function which you can call to open new squares
632 * once you're confident of them. It fills in as much more of the
633 * grid as it can.
635 * Return value is:
637 * - -1 means deduction stalled and nothing could be done
638 * - 0 means deduction succeeded fully
639 * - >0 means deduction succeeded but some number of perturbation
640 * steps were required; the exact return value is the number of
641 * perturb calls.
644 typedef struct perturbations *(*perturb_cb) (void *, signed char *, int, int, int);
646 static int minesolve(int w, int h, int n, signed char *grid,
647 open_cb open,
648 perturb_cb perturb,
649 void *ctx, random_state *rs)
651 struct setstore *ss = ss_new();
652 struct set **list;
653 struct squaretodo astd, *std = &astd;
654 int x, y, i, j;
655 int nperturbs = 0;
658 * Set up a linked list of squares with known contents, so that
659 * we can process them one by one.
661 std->next = snewn(w*h, int);
662 std->head = std->tail = -1;
665 * Initialise that list with all known squares in the input
666 * grid.
668 for (y = 0; y < h; y++) {
669 for (x = 0; x < w; x++) {
670 i = y*w+x;
671 if (grid[i] != -2)
672 std_add(std, i);
677 * Main deductive loop.
679 while (1) {
680 int done_something = FALSE;
681 struct set *s;
684 * If there are any known squares on the todo list, process
685 * them and construct a set for each.
687 while (std->head != -1) {
688 i = std->head;
689 #ifdef SOLVER_DIAGNOSTICS
690 printf("known square at %d,%d [%d]\n", i%w, i/w, grid[i]);
691 #endif
692 std->head = std->next[i];
693 if (std->head == -1)
694 std->tail = -1;
696 x = i % w;
697 y = i / w;
699 if (grid[i] >= 0) {
700 int dx, dy, mines, bit, val;
701 #ifdef SOLVER_DIAGNOSTICS
702 printf("creating set around this square\n");
703 #endif
705 * Empty square. Construct the set of non-known squares
706 * around this one, and determine its mine count.
708 mines = grid[i];
709 bit = 1;
710 val = 0;
711 for (dy = -1; dy <= +1; dy++) {
712 for (dx = -1; dx <= +1; dx++) {
713 #ifdef SOLVER_DIAGNOSTICS
714 printf("grid %d,%d = %d\n", x+dx, y+dy, grid[i+dy*w+dx]);
715 #endif
716 if (x+dx < 0 || x+dx >= w || y+dy < 0 || y+dy >= h)
717 /* ignore this one */;
718 else if (grid[i+dy*w+dx] == -1)
719 mines--;
720 else if (grid[i+dy*w+dx] == -2)
721 val |= bit;
722 bit <<= 1;
725 if (val)
726 ss_add(ss, x-1, y-1, val, mines);
730 * Now, whether the square is empty or full, we must
731 * find any set which contains it and replace it with
732 * one which does not.
735 #ifdef SOLVER_DIAGNOSTICS
736 printf("finding sets containing known square %d,%d\n", x, y);
737 #endif
738 list = ss_overlap(ss, x, y, 1);
740 for (j = 0; list[j]; j++) {
741 int newmask, newmines;
743 s = list[j];
746 * Compute the mask for this set minus the
747 * newly known square.
749 newmask = setmunge(s->x, s->y, s->mask, x, y, 1, TRUE);
752 * Compute the new mine count.
754 newmines = s->mines - (grid[i] == -1);
757 * Insert the new set into the collection,
758 * unless it's been whittled right down to
759 * nothing.
761 if (newmask)
762 ss_add(ss, s->x, s->y, newmask, newmines);
765 * Destroy the old one; it is actually obsolete.
767 ss_remove(ss, s);
770 sfree(list);
774 * Marking a fresh square as known certainly counts as
775 * doing something.
777 done_something = TRUE;
781 * Now pick a set off the to-do list and attempt deductions
782 * based on it.
784 if ((s = ss_todo(ss)) != NULL) {
786 #ifdef SOLVER_DIAGNOSTICS
787 printf("set to do: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines);
788 #endif
790 * Firstly, see if this set has a mine count of zero or
791 * of its own cardinality.
793 if (s->mines == 0 || s->mines == bitcount16(s->mask)) {
795 * If so, we can immediately mark all the squares
796 * in the set as known.
798 #ifdef SOLVER_DIAGNOSTICS
799 printf("easy\n");
800 #endif
801 known_squares(w, h, std, grid, open, ctx,
802 s->x, s->y, s->mask, (s->mines != 0));
805 * Having done that, we need do nothing further
806 * with this set; marking all the squares in it as
807 * known will eventually eliminate it, and will
808 * also permit further deductions about anything
809 * that overlaps it.
811 continue;
815 * Failing that, we now search through all the sets
816 * which overlap this one.
818 list = ss_overlap(ss, s->x, s->y, s->mask);
820 for (j = 0; list[j]; j++) {
821 struct set *s2 = list[j];
822 int swing, s2wing, swc, s2wc;
825 * Find the non-overlapping parts s2-s and s-s2,
826 * and their cardinalities.
828 * I'm going to refer to these parts as `wings'
829 * surrounding the central part common to both
830 * sets. The `s wing' is s-s2; the `s2 wing' is
831 * s2-s.
833 swing = setmunge(s->x, s->y, s->mask, s2->x, s2->y, s2->mask,
834 TRUE);
835 s2wing = setmunge(s2->x, s2->y, s2->mask, s->x, s->y, s->mask,
836 TRUE);
837 swc = bitcount16(swing);
838 s2wc = bitcount16(s2wing);
841 * If one set has more mines than the other, and
842 * the number of extra mines is equal to the
843 * cardinality of that set's wing, then we can mark
844 * every square in the wing as a known mine, and
845 * every square in the other wing as known clear.
847 if (swc == s->mines - s2->mines ||
848 s2wc == s2->mines - s->mines) {
849 known_squares(w, h, std, grid, open, ctx,
850 s->x, s->y, swing,
851 (swc == s->mines - s2->mines));
852 known_squares(w, h, std, grid, open, ctx,
853 s2->x, s2->y, s2wing,
854 (s2wc == s2->mines - s->mines));
855 continue;
859 * Failing that, see if one set is a subset of the
860 * other. If so, we can divide up the mine count of
861 * the larger set between the smaller set and its
862 * complement, even if neither smaller set ends up
863 * being immediately clearable.
865 if (swc == 0 && s2wc != 0) {
866 /* s is a subset of s2. */
867 assert(s2->mines > s->mines);
868 ss_add(ss, s2->x, s2->y, s2wing, s2->mines - s->mines);
869 } else if (s2wc == 0 && swc != 0) {
870 /* s2 is a subset of s. */
871 assert(s->mines > s2->mines);
872 ss_add(ss, s->x, s->y, swing, s->mines - s2->mines);
876 sfree(list);
879 * In this situation we have definitely done
880 * _something_, even if it's only reducing the size of
881 * our to-do list.
883 done_something = TRUE;
884 } else if (n >= 0) {
886 * We have nothing left on our todo list, which means
887 * all localised deductions have failed. Our next step
888 * is to resort to global deduction based on the total
889 * mine count. This is computationally expensive
890 * compared to any of the above deductions, which is
891 * why we only ever do it when all else fails, so that
892 * hopefully it won't have to happen too often.
894 * If you pass n<0 into this solver, that informs it
895 * that you do not know the total mine count, so it
896 * won't even attempt these deductions.
899 int minesleft, squaresleft;
900 int nsets, setused[10], cursor;
903 * Start by scanning the current grid state to work out
904 * how many unknown squares we still have, and how many
905 * mines are to be placed in them.
907 squaresleft = 0;
908 minesleft = n;
909 for (i = 0; i < w*h; i++) {
910 if (grid[i] == -1)
911 minesleft--;
912 else if (grid[i] == -2)
913 squaresleft++;
916 #ifdef SOLVER_DIAGNOSTICS
917 printf("global deduction time: squaresleft=%d minesleft=%d\n",
918 squaresleft, minesleft);
919 for (y = 0; y < h; y++) {
920 for (x = 0; x < w; x++) {
921 int v = grid[y*w+x];
922 if (v == -1)
923 putchar('*');
924 else if (v == -2)
925 putchar('?');
926 else if (v == 0)
927 putchar('-');
928 else
929 putchar('0' + v);
931 putchar('\n');
933 #endif
936 * If there _are_ no unknown squares, we have actually
937 * finished.
939 if (squaresleft == 0) {
940 assert(minesleft == 0);
941 break;
945 * First really simple case: if there are no more mines
946 * left, or if there are exactly as many mines left as
947 * squares to play them in, then it's all easy.
949 if (minesleft == 0 || minesleft == squaresleft) {
950 for (i = 0; i < w*h; i++)
951 if (grid[i] == -2)
952 known_squares(w, h, std, grid, open, ctx,
953 i % w, i / w, 1, minesleft != 0);
954 continue; /* now go back to main deductive loop */
958 * Failing that, we have to do some _real_ work.
959 * Ideally what we do here is to try every single
960 * combination of the currently available sets, in an
961 * attempt to find a disjoint union (i.e. a set of
962 * squares with a known mine count between them) such
963 * that the remaining unknown squares _not_ contained
964 * in that union either contain no mines or are all
965 * mines.
967 * Actually enumerating all 2^n possibilities will get
968 * a bit slow for large n, so I artificially cap this
969 * recursion at n=10 to avoid too much pain.
971 nsets = count234(ss->sets);
972 if (nsets <= lenof(setused)) {
974 * Doing this with actual recursive function calls
975 * would get fiddly because a load of local
976 * variables from this function would have to be
977 * passed down through the recursion. So instead
978 * I'm going to use a virtual recursion within this
979 * function. The way this works is:
981 * - we have an array `setused', such that
982 * setused[n] is 0 or 1 depending on whether set
983 * n is currently in the union we are
984 * considering.
986 * - we have a value `cursor' which indicates how
987 * much of `setused' we have so far filled in.
988 * It's conceptually the recursion depth.
990 * We begin by setting `cursor' to zero. Then:
992 * - if cursor can advance, we advance it by one.
993 * We set the value in `setused' that it went
994 * past to 1 if that set is disjoint from
995 * anything else currently in `setused', or to 0
996 * otherwise.
998 * - If cursor cannot advance because it has
999 * reached the end of the setused list, then we
1000 * have a maximal disjoint union. Check to see
1001 * whether its mine count has any useful
1002 * properties. If so, mark all the squares not
1003 * in the union as known and terminate.
1005 * - If cursor has reached the end of setused and
1006 * the algorithm _hasn't_ terminated, back
1007 * cursor up to the nearest 1, turn it into a 0
1008 * and advance cursor just past it.
1010 * - If we attempt to back up to the nearest 1 and
1011 * there isn't one at all, then we have gone
1012 * through all disjoint unions of sets in the
1013 * list and none of them has been helpful, so we
1014 * give up.
1016 struct set *sets[lenof(setused)];
1017 for (i = 0; i < nsets; i++)
1018 sets[i] = index234(ss->sets, i);
1020 cursor = 0;
1021 while (1) {
1023 if (cursor < nsets) {
1024 int ok = TRUE;
1026 /* See if any existing set overlaps this one. */
1027 for (i = 0; i < cursor; i++)
1028 if (setused[i] &&
1029 setmunge(sets[cursor]->x,
1030 sets[cursor]->y,
1031 sets[cursor]->mask,
1032 sets[i]->x, sets[i]->y, sets[i]->mask,
1033 FALSE)) {
1034 ok = FALSE;
1035 break;
1038 if (ok) {
1040 * We're adding this set to our union,
1041 * so adjust minesleft and squaresleft
1042 * appropriately.
1044 minesleft -= sets[cursor]->mines;
1045 squaresleft -= bitcount16(sets[cursor]->mask);
1048 setused[cursor++] = ok;
1049 } else {
1050 #ifdef SOLVER_DIAGNOSTICS
1051 printf("trying a set combination with %d %d\n",
1052 squaresleft, minesleft);
1053 #endif /* SOLVER_DIAGNOSTICS */
1056 * We've reached the end. See if we've got
1057 * anything interesting.
1059 if (squaresleft > 0 &&
1060 (minesleft == 0 || minesleft == squaresleft)) {
1062 * We have! There is at least one
1063 * square not contained within the set
1064 * union we've just found, and we can
1065 * deduce that either all such squares
1066 * are mines or all are not (depending
1067 * on whether minesleft==0). So now all
1068 * we have to do is actually go through
1069 * the grid, find those squares, and
1070 * mark them.
1072 for (i = 0; i < w*h; i++)
1073 if (grid[i] == -2) {
1074 int outside = TRUE;
1075 y = i / w;
1076 x = i % w;
1077 for (j = 0; j < nsets; j++)
1078 if (setused[j] &&
1079 setmunge(sets[j]->x, sets[j]->y,
1080 sets[j]->mask, x, y, 1,
1081 FALSE)) {
1082 outside = FALSE;
1083 break;
1085 if (outside)
1086 known_squares(w, h, std, grid,
1087 open, ctx,
1088 x, y, 1, minesleft != 0);
1091 done_something = TRUE;
1092 break; /* return to main deductive loop */
1096 * If we reach here, then this union hasn't
1097 * done us any good, so move on to the
1098 * next. Backtrack cursor to the nearest 1,
1099 * change it to a 0 and continue.
1101 while (--cursor >= 0 && !setused[cursor]);
1102 if (cursor >= 0) {
1103 assert(setused[cursor]);
1106 * We're removing this set from our
1107 * union, so re-increment minesleft and
1108 * squaresleft.
1110 minesleft += sets[cursor]->mines;
1111 squaresleft += bitcount16(sets[cursor]->mask);
1113 setused[cursor++] = 0;
1114 } else {
1116 * We've backtracked all the way to the
1117 * start without finding a single 1,
1118 * which means that our virtual
1119 * recursion is complete and nothing
1120 * helped.
1122 break;
1131 if (done_something)
1132 continue;
1134 #ifdef SOLVER_DIAGNOSTICS
1136 * Dump the current known state of the grid.
1138 printf("solver ran out of steam, ret=%d, grid:\n", nperturbs);
1139 for (y = 0; y < h; y++) {
1140 for (x = 0; x < w; x++) {
1141 int v = grid[y*w+x];
1142 if (v == -1)
1143 putchar('*');
1144 else if (v == -2)
1145 putchar('?');
1146 else if (v == 0)
1147 putchar('-');
1148 else
1149 putchar('0' + v);
1151 putchar('\n');
1155 struct set *s;
1157 for (i = 0; (s = index234(ss->sets, i)) != NULL; i++)
1158 printf("remaining set: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines);
1160 #endif
1163 * Now we really are at our wits' end as far as solving
1164 * this grid goes. Our only remaining option is to call
1165 * a perturb function and ask it to modify the grid to
1166 * make it easier.
1168 if (perturb) {
1169 struct perturbations *ret;
1170 struct set *s;
1172 nperturbs++;
1175 * Choose a set at random from the current selection,
1176 * and ask the perturb function to either fill or empty
1177 * it.
1179 * If we have no sets at all, we must give up.
1181 if (count234(ss->sets) == 0) {
1182 #ifdef SOLVER_DIAGNOSTICS
1183 printf("perturbing on entire unknown set\n");
1184 #endif
1185 ret = perturb(ctx, grid, 0, 0, 0);
1186 } else {
1187 s = index234(ss->sets, random_upto(rs, count234(ss->sets)));
1188 #ifdef SOLVER_DIAGNOSTICS
1189 printf("perturbing on set %d,%d %03x\n", s->x, s->y, s->mask);
1190 #endif
1191 ret = perturb(ctx, grid, s->x, s->y, s->mask);
1194 if (ret) {
1195 assert(ret->n > 0); /* otherwise should have been NULL */
1198 * A number of squares have been fiddled with, and
1199 * the returned structure tells us which. Adjust
1200 * the mine count in any set which overlaps one of
1201 * those squares, and put them back on the to-do
1202 * list. Also, if the square itself is marked as a
1203 * known non-mine, put it back on the squares-to-do
1204 * list.
1206 for (i = 0; i < ret->n; i++) {
1207 #ifdef SOLVER_DIAGNOSTICS
1208 printf("perturbation %s mine at %d,%d\n",
1209 ret->changes[i].delta > 0 ? "added" : "removed",
1210 ret->changes[i].x, ret->changes[i].y);
1211 #endif
1213 if (ret->changes[i].delta < 0 &&
1214 grid[ret->changes[i].y*w+ret->changes[i].x] != -2) {
1215 std_add(std, ret->changes[i].y*w+ret->changes[i].x);
1218 list = ss_overlap(ss,
1219 ret->changes[i].x, ret->changes[i].y, 1);
1221 for (j = 0; list[j]; j++) {
1222 list[j]->mines += ret->changes[i].delta;
1223 ss_add_todo(ss, list[j]);
1226 sfree(list);
1230 * Now free the returned data.
1232 sfree(ret->changes);
1233 sfree(ret);
1235 #ifdef SOLVER_DIAGNOSTICS
1237 * Dump the current known state of the grid.
1239 printf("state after perturbation:\n");
1240 for (y = 0; y < h; y++) {
1241 for (x = 0; x < w; x++) {
1242 int v = grid[y*w+x];
1243 if (v == -1)
1244 putchar('*');
1245 else if (v == -2)
1246 putchar('?');
1247 else if (v == 0)
1248 putchar('-');
1249 else
1250 putchar('0' + v);
1252 putchar('\n');
1256 struct set *s;
1258 for (i = 0; (s = index234(ss->sets, i)) != NULL; i++)
1259 printf("remaining set: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines);
1261 #endif
1264 * And now we can go back round the deductive loop.
1266 continue;
1271 * If we get here, even that didn't work (either we didn't
1272 * have a perturb function or it returned failure), so we
1273 * give up entirely.
1275 break;
1279 * See if we've got any unknown squares left.
1281 for (y = 0; y < h; y++)
1282 for (x = 0; x < w; x++)
1283 if (grid[y*w+x] == -2) {
1284 nperturbs = -1; /* failed to complete */
1285 break;
1289 * Free the set list and square-todo list.
1292 struct set *s;
1293 while ((s = delpos234(ss->sets, 0)) != NULL)
1294 sfree(s);
1295 freetree234(ss->sets);
1296 sfree(ss);
1297 sfree(std->next);
1300 return nperturbs;
1303 /* ----------------------------------------------------------------------
1304 * Grid generator which uses the above solver.
1307 struct minectx {
1308 char *grid;
1309 int w, h;
1310 int sx, sy;
1311 int allow_big_perturbs;
1312 random_state *rs;
1315 static int mineopen(void *vctx, int x, int y)
1317 struct minectx *ctx = (struct minectx *)vctx;
1318 int i, j, n;
1320 assert(x >= 0 && x < ctx->w && y >= 0 && y < ctx->h);
1321 if (ctx->grid[y * ctx->w + x])
1322 return -1; /* *bang* */
1324 n = 0;
1325 for (i = -1; i <= +1; i++) {
1326 if (x + i < 0 || x + i >= ctx->w)
1327 continue;
1328 for (j = -1; j <= +1; j++) {
1329 if (y + j < 0 || y + j >= ctx->h)
1330 continue;
1331 if (i == 0 && j == 0)
1332 continue;
1333 if (ctx->grid[(y+j) * ctx->w + (x+i)])
1334 n++;
1338 return n;
1341 /* Structure used internally to mineperturb(). */
1342 struct square {
1343 int x, y, type, random;
1345 static int squarecmp(const void *av, const void *bv)
1347 const struct square *a = (const struct square *)av;
1348 const struct square *b = (const struct square *)bv;
1349 if (a->type < b->type)
1350 return -1;
1351 else if (a->type > b->type)
1352 return +1;
1353 else if (a->random < b->random)
1354 return -1;
1355 else if (a->random > b->random)
1356 return +1;
1357 else if (a->y < b->y)
1358 return -1;
1359 else if (a->y > b->y)
1360 return +1;
1361 else if (a->x < b->x)
1362 return -1;
1363 else if (a->x > b->x)
1364 return +1;
1365 return 0;
1369 * Normally this function is passed an (x,y,mask) set description.
1370 * On occasions, though, there is no _localised_ set being used,
1371 * and the set being perturbed is supposed to be the entirety of
1372 * the unreachable area. This is signified by the special case
1373 * mask==0: in this case, anything labelled -2 in the grid is part
1374 * of the set.
1376 * Allowing perturbation in this special case appears to make it
1377 * guaranteeably possible to generate a workable grid for any mine
1378 * density, but they tend to be a bit boring, with mines packed
1379 * densely into far corners of the grid and the remainder being
1380 * less dense than one might like. Therefore, to improve overall
1381 * grid quality I disable this feature for the first few attempts,
1382 * and fall back to it after no useful grid has been generated.
1384 static struct perturbations *mineperturb(void *vctx, signed char *grid,
1385 int setx, int sety, int mask)
1387 struct minectx *ctx = (struct minectx *)vctx;
1388 struct square *sqlist;
1389 int x, y, dx, dy, i, n, nfull, nempty;
1390 struct square **tofill, **toempty, **todo;
1391 int ntofill, ntoempty, ntodo, dtodo, dset;
1392 struct perturbations *ret;
1393 int *setlist;
1395 if (!mask && !ctx->allow_big_perturbs)
1396 return NULL;
1399 * Make a list of all the squares in the grid which we can
1400 * possibly use. This list should be in preference order, which
1401 * means
1403 * - first, unknown squares on the boundary of known space
1404 * - next, unknown squares beyond that boundary
1405 * - as a very last resort, known squares, but not within one
1406 * square of the starting position.
1408 * Each of these sections needs to be shuffled independently.
1409 * We do this by preparing list of all squares and then sorting
1410 * it with a random secondary key.
1412 sqlist = snewn(ctx->w * ctx->h, struct square);
1413 n = 0;
1414 for (y = 0; y < ctx->h; y++)
1415 for (x = 0; x < ctx->w; x++) {
1417 * If this square is too near the starting position,
1418 * don't put it on the list at all.
1420 if (abs(y - ctx->sy) <= 1 && abs(x - ctx->sx) <= 1)
1421 continue;
1424 * If this square is in the input set, also don't put
1425 * it on the list!
1427 if ((mask == 0 && grid[y*ctx->w+x] == -2) ||
1428 (x >= setx && x < setx + 3 &&
1429 y >= sety && y < sety + 3 &&
1430 mask & (1 << ((y-sety)*3+(x-setx)))))
1431 continue;
1433 sqlist[n].x = x;
1434 sqlist[n].y = y;
1436 if (grid[y*ctx->w+x] != -2) {
1437 sqlist[n].type = 3; /* known square */
1438 } else {
1440 * Unknown square. Examine everything around it and
1441 * see if it borders on any known squares. If it
1442 * does, it's class 1, otherwise it's 2.
1445 sqlist[n].type = 2;
1447 for (dy = -1; dy <= +1; dy++)
1448 for (dx = -1; dx <= +1; dx++)
1449 if (x+dx >= 0 && x+dx < ctx->w &&
1450 y+dy >= 0 && y+dy < ctx->h &&
1451 grid[(y+dy)*ctx->w+(x+dx)] != -2) {
1452 sqlist[n].type = 1;
1453 break;
1458 * Finally, a random number to cause qsort to
1459 * shuffle within each group.
1461 sqlist[n].random = random_bits(ctx->rs, 31);
1463 n++;
1466 qsort(sqlist, n, sizeof(struct square), squarecmp);
1469 * Now count up the number of full and empty squares in the set
1470 * we've been provided.
1472 nfull = nempty = 0;
1473 if (mask) {
1474 for (dy = 0; dy < 3; dy++)
1475 for (dx = 0; dx < 3; dx++)
1476 if (mask & (1 << (dy*3+dx))) {
1477 assert(setx+dx <= ctx->w);
1478 assert(sety+dy <= ctx->h);
1479 if (ctx->grid[(sety+dy)*ctx->w+(setx+dx)])
1480 nfull++;
1481 else
1482 nempty++;
1484 } else {
1485 for (y = 0; y < ctx->h; y++)
1486 for (x = 0; x < ctx->w; x++)
1487 if (grid[y*ctx->w+x] == -2) {
1488 if (ctx->grid[y*ctx->w+x])
1489 nfull++;
1490 else
1491 nempty++;
1496 * Now go through our sorted list until we find either `nfull'
1497 * empty squares, or `nempty' full squares; these will be
1498 * swapped with the appropriate squares in the set to either
1499 * fill or empty the set while keeping the same number of mines
1500 * overall.
1502 ntofill = ntoempty = 0;
1503 if (mask) {
1504 tofill = snewn(9, struct square *);
1505 toempty = snewn(9, struct square *);
1506 } else {
1507 tofill = snewn(ctx->w * ctx->h, struct square *);
1508 toempty = snewn(ctx->w * ctx->h, struct square *);
1510 for (i = 0; i < n; i++) {
1511 struct square *sq = &sqlist[i];
1512 if (ctx->grid[sq->y * ctx->w + sq->x])
1513 toempty[ntoempty++] = sq;
1514 else
1515 tofill[ntofill++] = sq;
1516 if (ntofill == nfull || ntoempty == nempty)
1517 break;
1521 * If we haven't found enough empty squares outside the set to
1522 * empty it into _or_ enough full squares outside it to fill it
1523 * up with, we'll have to settle for doing only a partial job.
1524 * In this case we choose to always _fill_ the set (because
1525 * this case will tend to crop up when we're working with very
1526 * high mine densities and the only way to get a solvable grid
1527 * is going to be to pack most of the mines solidly around the
1528 * edges). So now our job is to make a list of the empty
1529 * squares in the set, and shuffle that list so that we fill a
1530 * random selection of them.
1532 if (ntofill != nfull && ntoempty != nempty) {
1533 int k;
1535 assert(ntoempty != 0);
1537 setlist = snewn(ctx->w * ctx->h, int);
1538 i = 0;
1539 if (mask) {
1540 for (dy = 0; dy < 3; dy++)
1541 for (dx = 0; dx < 3; dx++)
1542 if (mask & (1 << (dy*3+dx))) {
1543 assert(setx+dx <= ctx->w);
1544 assert(sety+dy <= ctx->h);
1545 if (!ctx->grid[(sety+dy)*ctx->w+(setx+dx)])
1546 setlist[i++] = (sety+dy)*ctx->w+(setx+dx);
1548 } else {
1549 for (y = 0; y < ctx->h; y++)
1550 for (x = 0; x < ctx->w; x++)
1551 if (grid[y*ctx->w+x] == -2) {
1552 if (!ctx->grid[y*ctx->w+x])
1553 setlist[i++] = y*ctx->w+x;
1556 assert(i > ntoempty);
1558 * Now pick `ntoempty' items at random from the list.
1560 for (k = 0; k < ntoempty; k++) {
1561 int index = k + random_upto(ctx->rs, i - k);
1562 int tmp;
1564 tmp = setlist[k];
1565 setlist[k] = setlist[index];
1566 setlist[index] = tmp;
1568 } else
1569 setlist = NULL;
1572 * Now we're pretty much there. We need to either
1573 * (a) put a mine in each of the empty squares in the set, and
1574 * take one out of each square in `toempty'
1575 * (b) take a mine out of each of the full squares in the set,
1576 * and put one in each square in `tofill'
1577 * depending on which one we've found enough squares to do.
1579 * So we start by constructing our list of changes to return to
1580 * the solver, so that it can update its data structures
1581 * efficiently rather than having to rescan the whole grid.
1583 ret = snew(struct perturbations);
1584 if (ntofill == nfull) {
1585 todo = tofill;
1586 ntodo = ntofill;
1587 dtodo = +1;
1588 dset = -1;
1589 sfree(toempty);
1590 } else {
1592 * (We also fall into this case if we've constructed a
1593 * setlist.)
1595 todo = toempty;
1596 ntodo = ntoempty;
1597 dtodo = -1;
1598 dset = +1;
1599 sfree(tofill);
1601 ret->n = 2 * ntodo;
1602 ret->changes = snewn(ret->n, struct perturbation);
1603 for (i = 0; i < ntodo; i++) {
1604 ret->changes[i].x = todo[i]->x;
1605 ret->changes[i].y = todo[i]->y;
1606 ret->changes[i].delta = dtodo;
1608 /* now i == ntodo */
1609 if (setlist) {
1610 int j;
1611 assert(todo == toempty);
1612 for (j = 0; j < ntoempty; j++) {
1613 ret->changes[i].x = setlist[j] % ctx->w;
1614 ret->changes[i].y = setlist[j] / ctx->w;
1615 ret->changes[i].delta = dset;
1616 i++;
1618 sfree(setlist);
1619 } else if (mask) {
1620 for (dy = 0; dy < 3; dy++)
1621 for (dx = 0; dx < 3; dx++)
1622 if (mask & (1 << (dy*3+dx))) {
1623 int currval = (ctx->grid[(sety+dy)*ctx->w+(setx+dx)] ? +1 : -1);
1624 if (dset == -currval) {
1625 ret->changes[i].x = setx + dx;
1626 ret->changes[i].y = sety + dy;
1627 ret->changes[i].delta = dset;
1628 i++;
1631 } else {
1632 for (y = 0; y < ctx->h; y++)
1633 for (x = 0; x < ctx->w; x++)
1634 if (grid[y*ctx->w+x] == -2) {
1635 int currval = (ctx->grid[y*ctx->w+x] ? +1 : -1);
1636 if (dset == -currval) {
1637 ret->changes[i].x = x;
1638 ret->changes[i].y = y;
1639 ret->changes[i].delta = dset;
1640 i++;
1644 assert(i == ret->n);
1646 sfree(sqlist);
1647 sfree(todo);
1650 * Having set up the precise list of changes we're going to
1651 * make, we now simply make them and return.
1653 for (i = 0; i < ret->n; i++) {
1654 int delta;
1656 x = ret->changes[i].x;
1657 y = ret->changes[i].y;
1658 delta = ret->changes[i].delta;
1661 * Check we're not trying to add an existing mine or remove
1662 * an absent one.
1664 assert((delta < 0) ^ (ctx->grid[y*ctx->w+x] == 0));
1667 * Actually make the change.
1669 ctx->grid[y*ctx->w+x] = (delta > 0);
1672 * Update any numbers already present in the grid.
1674 for (dy = -1; dy <= +1; dy++)
1675 for (dx = -1; dx <= +1; dx++)
1676 if (x+dx >= 0 && x+dx < ctx->w &&
1677 y+dy >= 0 && y+dy < ctx->h &&
1678 grid[(y+dy)*ctx->w+(x+dx)] != -2) {
1679 if (dx == 0 && dy == 0) {
1681 * The square itself is marked as known in
1682 * the grid. Mark it as a mine if it's a
1683 * mine, or else work out its number.
1685 if (delta > 0) {
1686 grid[y*ctx->w+x] = -1;
1687 } else {
1688 int dx2, dy2, minecount = 0;
1689 for (dy2 = -1; dy2 <= +1; dy2++)
1690 for (dx2 = -1; dx2 <= +1; dx2++)
1691 if (x+dx2 >= 0 && x+dx2 < ctx->w &&
1692 y+dy2 >= 0 && y+dy2 < ctx->h &&
1693 ctx->grid[(y+dy2)*ctx->w+(x+dx2)])
1694 minecount++;
1695 grid[y*ctx->w+x] = minecount;
1697 } else {
1698 if (grid[(y+dy)*ctx->w+(x+dx)] >= 0)
1699 grid[(y+dy)*ctx->w+(x+dx)] += delta;
1704 #ifdef GENERATION_DIAGNOSTICS
1706 int yy, xx;
1707 printf("grid after perturbing:\n");
1708 for (yy = 0; yy < ctx->h; yy++) {
1709 for (xx = 0; xx < ctx->w; xx++) {
1710 int v = ctx->grid[yy*ctx->w+xx];
1711 if (yy == ctx->sy && xx == ctx->sx) {
1712 assert(!v);
1713 putchar('S');
1714 } else if (v) {
1715 putchar('*');
1716 } else {
1717 putchar('-');
1720 putchar('\n');
1722 printf("\n");
1724 #endif
1726 return ret;
1729 static char *minegen(int w, int h, int n, int x, int y, int unique,
1730 random_state *rs)
1732 char *ret = snewn(w*h, char);
1733 int success;
1734 int ntries = 0;
1736 do {
1737 success = FALSE;
1738 ntries++;
1740 memset(ret, 0, w*h);
1743 * Start by placing n mines, none of which is at x,y or within
1744 * one square of it.
1747 int *tmp = snewn(w*h, int);
1748 int i, j, k, nn;
1751 * Write down the list of possible mine locations.
1753 k = 0;
1754 for (i = 0; i < h; i++)
1755 for (j = 0; j < w; j++)
1756 if (abs(i - y) > 1 || abs(j - x) > 1)
1757 tmp[k++] = i*w+j;
1760 * Now pick n off the list at random.
1762 nn = n;
1763 while (nn-- > 0) {
1764 i = random_upto(rs, k);
1765 ret[tmp[i]] = 1;
1766 tmp[i] = tmp[--k];
1769 sfree(tmp);
1772 #ifdef GENERATION_DIAGNOSTICS
1774 int yy, xx;
1775 printf("grid after initial generation:\n");
1776 for (yy = 0; yy < h; yy++) {
1777 for (xx = 0; xx < w; xx++) {
1778 int v = ret[yy*w+xx];
1779 if (yy == y && xx == x) {
1780 assert(!v);
1781 putchar('S');
1782 } else if (v) {
1783 putchar('*');
1784 } else {
1785 putchar('-');
1788 putchar('\n');
1790 printf("\n");
1792 #endif
1795 * Now set up a results grid to run the solver in, and a
1796 * context for the solver to open squares. Then run the solver
1797 * repeatedly; if the number of perturb steps ever goes up or
1798 * it ever returns -1, give up completely.
1800 * We bypass this bit if we're not after a unique grid.
1802 if (unique) {
1803 signed char *solvegrid = snewn(w*h, signed char);
1804 struct minectx actx, *ctx = &actx;
1805 int solveret, prevret = -2;
1807 ctx->grid = ret;
1808 ctx->w = w;
1809 ctx->h = h;
1810 ctx->sx = x;
1811 ctx->sy = y;
1812 ctx->rs = rs;
1813 ctx->allow_big_perturbs = (ntries > 100);
1815 while (1) {
1816 memset(solvegrid, -2, w*h);
1817 solvegrid[y*w+x] = mineopen(ctx, x, y);
1818 assert(solvegrid[y*w+x] == 0); /* by deliberate arrangement */
1820 solveret =
1821 minesolve(w, h, n, solvegrid, mineopen, mineperturb, ctx, rs);
1822 if (solveret < 0 || (prevret >= 0 && solveret >= prevret)) {
1823 success = FALSE;
1824 break;
1825 } else if (solveret == 0) {
1826 success = TRUE;
1827 break;
1831 sfree(solvegrid);
1832 } else {
1833 success = TRUE;
1836 } while (!success);
1838 return ret;
1841 static char *describe_layout(char *grid, int area, int x, int y,
1842 int obfuscate)
1844 char *ret, *p;
1845 unsigned char *bmp;
1846 int i;
1849 * Set up the mine bitmap and obfuscate it.
1851 bmp = snewn((area + 7) / 8, unsigned char);
1852 memset(bmp, 0, (area + 7) / 8);
1853 for (i = 0; i < area; i++) {
1854 if (grid[i])
1855 bmp[i / 8] |= 0x80 >> (i % 8);
1857 if (obfuscate)
1858 obfuscate_bitmap(bmp, area, FALSE);
1861 * Now encode the resulting bitmap in hex. We can work to
1862 * nibble rather than byte granularity, since the obfuscation
1863 * function guarantees to return a bit string of the same
1864 * length as its input.
1866 ret = snewn((area+3)/4 + 100, char);
1867 p = ret + sprintf(ret, "%d,%d,%s", x, y,
1868 obfuscate ? "m" : "u"); /* 'm' == masked */
1869 for (i = 0; i < (area+3)/4; i++) {
1870 int v = bmp[i/2];
1871 if (i % 2 == 0)
1872 v >>= 4;
1873 *p++ = "0123456789abcdef"[v & 0xF];
1875 *p = '\0';
1877 sfree(bmp);
1879 return ret;
1882 static char *new_mine_layout(int w, int h, int n, int x, int y, int unique,
1883 random_state *rs, char **game_desc)
1885 char *grid;
1887 #ifdef TEST_OBFUSCATION
1888 static int tested_obfuscation = FALSE;
1889 if (!tested_obfuscation) {
1891 * A few simple test vectors for the obfuscator.
1893 * First test: the 28-bit stream 1234567. This divides up
1894 * into 1234 and 567[0]. The SHA of 56 70 30 (appending
1895 * "0") is 15ce8ab946640340bbb99f3f48fd2c45d1a31d30. Thus,
1896 * we XOR the 16-bit string 15CE into the input 1234 to get
1897 * 07FA. Next, we SHA that with "0": the SHA of 07 FA 30 is
1898 * 3370135c5e3da4fed937adc004a79533962b6391. So we XOR the
1899 * 12-bit string 337 into the input 567 to get 650. Thus
1900 * our output is 07FA650.
1903 unsigned char bmp1[] = "\x12\x34\x56\x70";
1904 obfuscate_bitmap(bmp1, 28, FALSE);
1905 printf("test 1 encode: %s\n",
1906 memcmp(bmp1, "\x07\xfa\x65\x00", 4) ? "failed" : "passed");
1907 obfuscate_bitmap(bmp1, 28, TRUE);
1908 printf("test 1 decode: %s\n",
1909 memcmp(bmp1, "\x12\x34\x56\x70", 4) ? "failed" : "passed");
1912 * Second test: a long string to make sure we switch from
1913 * one SHA to the next correctly. My input string this time
1914 * is simply fifty bytes of zeroes.
1917 unsigned char bmp2[50];
1918 unsigned char bmp2a[50];
1919 memset(bmp2, 0, 50);
1920 memset(bmp2a, 0, 50);
1921 obfuscate_bitmap(bmp2, 50 * 8, FALSE);
1923 * SHA of twenty-five zero bytes plus "0" is
1924 * b202c07b990c01f6ff2d544707f60e506019b671. SHA of
1925 * twenty-five zero bytes plus "1" is
1926 * fcb1d8b5a2f6b592fe6780b36aa9d65dd7aa6db9. Thus our
1927 * first half becomes
1928 * b202c07b990c01f6ff2d544707f60e506019b671fcb1d8b5a2.
1930 * SHA of that lot plus "0" is
1931 * 10b0af913db85d37ca27f52a9f78bba3a80030db. SHA of the
1932 * same string plus "1" is
1933 * 3d01d8df78e76d382b8106f480135a1bc751d725. So the
1934 * second half becomes
1935 * 10b0af913db85d37ca27f52a9f78bba3a80030db3d01d8df78.
1937 printf("test 2 encode: %s\n",
1938 memcmp(bmp2, "\xb2\x02\xc0\x7b\x99\x0c\x01\xf6\xff\x2d\x54"
1939 "\x47\x07\xf6\x0e\x50\x60\x19\xb6\x71\xfc\xb1\xd8"
1940 "\xb5\xa2\x10\xb0\xaf\x91\x3d\xb8\x5d\x37\xca\x27"
1941 "\xf5\x2a\x9f\x78\xbb\xa3\xa8\x00\x30\xdb\x3d\x01"
1942 "\xd8\xdf\x78", 50) ? "failed" : "passed");
1943 obfuscate_bitmap(bmp2, 50 * 8, TRUE);
1944 printf("test 2 decode: %s\n",
1945 memcmp(bmp2, bmp2a, 50) ? "failed" : "passed");
1948 #endif
1950 grid = minegen(w, h, n, x, y, unique, rs);
1952 if (game_desc)
1953 *game_desc = describe_layout(grid, w * h, x, y, TRUE);
1955 return grid;
1958 static char *new_game_desc(game_params *params, random_state *rs,
1959 char **aux, int interactive)
1962 * We generate the coordinates of an initial click even if they
1963 * aren't actually used. This has the effect of harmonising the
1964 * random number usage between interactive and batch use: if
1965 * you use `mines --generate' with an explicit random seed, you
1966 * should get exactly the same results as if you type the same
1967 * random seed into the interactive game and click in the same
1968 * initial location. (Of course you won't get the same grid if
1969 * you click in a _different_ initial location, but there's
1970 * nothing to be done about that.)
1972 int x = random_upto(rs, params->w);
1973 int y = random_upto(rs, params->h);
1975 if (!interactive) {
1977 * For batch-generated grids, pre-open one square.
1979 char *grid;
1980 char *desc;
1982 grid = new_mine_layout(params->w, params->h, params->n,
1983 x, y, params->unique, rs, &desc);
1984 sfree(grid);
1985 return desc;
1986 } else {
1987 char *rsdesc, *desc;
1989 rsdesc = random_state_encode(rs);
1990 desc = snewn(strlen(rsdesc) + 100, char);
1991 sprintf(desc, "r%d,%c,%s", params->n, (char)(params->unique ? 'u' : 'a'), rsdesc);
1992 sfree(rsdesc);
1993 return desc;
1997 static char *validate_desc(game_params *params, char *desc)
1999 int wh = params->w * params->h;
2000 int x, y;
2002 if (*desc == 'r') {
2003 desc++;
2004 if (!*desc || !isdigit((unsigned char)*desc))
2005 return "No initial mine count in game description";
2006 while (*desc && isdigit((unsigned char)*desc))
2007 desc++; /* skip over mine count */
2008 if (*desc != ',')
2009 return "No ',' after initial x-coordinate in game description";
2010 desc++;
2011 if (*desc != 'u' && *desc != 'a')
2012 return "No uniqueness specifier in game description";
2013 desc++;
2014 if (*desc != ',')
2015 return "No ',' after uniqueness specifier in game description";
2016 /* now ignore the rest */
2017 } else {
2018 if (*desc && isdigit((unsigned char)*desc)) {
2019 x = atoi(desc);
2020 if (x < 0 || x >= params->w)
2021 return "Initial x-coordinate was out of range";
2022 while (*desc && isdigit((unsigned char)*desc))
2023 desc++; /* skip over x coordinate */
2024 if (*desc != ',')
2025 return "No ',' after initial x-coordinate in game description";
2026 desc++; /* eat comma */
2027 if (!*desc || !isdigit((unsigned char)*desc))
2028 return "No initial y-coordinate in game description";
2029 y = atoi(desc);
2030 if (y < 0 || y >= params->h)
2031 return "Initial y-coordinate was out of range";
2032 while (*desc && isdigit((unsigned char)*desc))
2033 desc++; /* skip over y coordinate */
2034 if (*desc != ',')
2035 return "No ',' after initial y-coordinate in game description";
2036 desc++; /* eat comma */
2038 /* eat `m' for `masked' or `u' for `unmasked', if present */
2039 if (*desc == 'm' || *desc == 'u')
2040 desc++;
2041 /* now just check length of remainder */
2042 if (strlen(desc) != (wh+3)/4)
2043 return "Game description is wrong length";
2046 return NULL;
2049 static int open_square(game_state *state, int x, int y)
2051 int w = state->w, h = state->h;
2052 int xx, yy, nmines, ncovered;
2054 if (!state->layout->mines) {
2056 * We have a preliminary game in which the mine layout
2057 * hasn't been generated yet. Generate it based on the
2058 * initial click location.
2060 char *desc, *privdesc;
2061 state->layout->mines = new_mine_layout(w, h, state->layout->n,
2062 x, y, state->layout->unique,
2063 state->layout->rs,
2064 &desc);
2066 * Find the trailing substring of the game description
2067 * corresponding to just the mine layout; we will use this
2068 * as our second `private' game ID for serialisation.
2070 privdesc = desc;
2071 while (*privdesc && isdigit((unsigned char)*privdesc)) privdesc++;
2072 if (*privdesc == ',') privdesc++;
2073 while (*privdesc && isdigit((unsigned char)*privdesc)) privdesc++;
2074 if (*privdesc == ',') privdesc++;
2075 assert(*privdesc == 'm');
2076 midend_supersede_game_desc(state->layout->me, desc, privdesc);
2077 sfree(desc);
2078 random_free(state->layout->rs);
2079 state->layout->rs = NULL;
2082 if (state->layout->mines[y*w+x]) {
2084 * The player has landed on a mine. Bad luck. Expose the
2085 * mine that killed them, but not the rest (in case they
2086 * want to Undo and carry on playing).
2088 state->dead = TRUE;
2089 state->grid[y*w+x] = 65;
2090 return -1;
2094 * Otherwise, the player has opened a safe square. Mark it to-do.
2096 state->grid[y*w+x] = -10; /* `todo' value internal to this func */
2099 * Now go through the grid finding all `todo' values and
2100 * opening them. Every time one of them turns out to have no
2101 * neighbouring mines, we add all its unopened neighbours to
2102 * the list as well.
2104 * FIXME: We really ought to be able to do this better than
2105 * using repeated N^2 scans of the grid.
2107 while (1) {
2108 int done_something = FALSE;
2110 for (yy = 0; yy < h; yy++)
2111 for (xx = 0; xx < w; xx++)
2112 if (state->grid[yy*w+xx] == -10) {
2113 int dx, dy, v;
2115 assert(!state->layout->mines[yy*w+xx]);
2117 v = 0;
2119 for (dx = -1; dx <= +1; dx++)
2120 for (dy = -1; dy <= +1; dy++)
2121 if (xx+dx >= 0 && xx+dx < state->w &&
2122 yy+dy >= 0 && yy+dy < state->h &&
2123 state->layout->mines[(yy+dy)*w+(xx+dx)])
2124 v++;
2126 state->grid[yy*w+xx] = v;
2128 if (v == 0) {
2129 for (dx = -1; dx <= +1; dx++)
2130 for (dy = -1; dy <= +1; dy++)
2131 if (xx+dx >= 0 && xx+dx < state->w &&
2132 yy+dy >= 0 && yy+dy < state->h &&
2133 state->grid[(yy+dy)*w+(xx+dx)] == -2)
2134 state->grid[(yy+dy)*w+(xx+dx)] = -10;
2137 done_something = TRUE;
2140 if (!done_something)
2141 break;
2145 * Finally, scan the grid and see if exactly as many squares
2146 * are still covered as there are mines. If so, set the `won'
2147 * flag and fill in mine markers on all covered squares.
2149 nmines = ncovered = 0;
2150 for (yy = 0; yy < h; yy++)
2151 for (xx = 0; xx < w; xx++) {
2152 if (state->grid[yy*w+xx] < 0)
2153 ncovered++;
2154 if (state->layout->mines[yy*w+xx])
2155 nmines++;
2157 assert(ncovered >= nmines);
2158 if (ncovered == nmines) {
2159 for (yy = 0; yy < h; yy++)
2160 for (xx = 0; xx < w; xx++) {
2161 if (state->grid[yy*w+xx] < 0)
2162 state->grid[yy*w+xx] = -1;
2164 state->won = TRUE;
2167 return 0;
2170 static game_state *new_game(midend *me, game_params *params, char *desc)
2172 game_state *state = snew(game_state);
2173 int i, wh, x, y, ret, masked;
2174 unsigned char *bmp;
2176 state->w = params->w;
2177 state->h = params->h;
2178 state->n = params->n;
2179 state->dead = state->won = FALSE;
2180 state->used_solve = FALSE;
2182 wh = state->w * state->h;
2184 state->layout = snew(struct mine_layout);
2185 memset(state->layout, 0, sizeof(struct mine_layout));
2186 state->layout->refcount = 1;
2188 state->grid = snewn(wh, signed char);
2189 memset(state->grid, -2, wh);
2191 if (*desc == 'r') {
2192 desc++;
2193 state->layout->n = atoi(desc);
2194 while (*desc && isdigit((unsigned char)*desc))
2195 desc++; /* skip over mine count */
2196 if (*desc) desc++; /* eat comma */
2197 if (*desc == 'a')
2198 state->layout->unique = FALSE;
2199 else
2200 state->layout->unique = TRUE;
2201 desc++;
2202 if (*desc) desc++; /* eat comma */
2204 state->layout->mines = NULL;
2205 state->layout->rs = random_state_decode(desc);
2206 state->layout->me = me;
2208 } else {
2209 state->layout->rs = NULL;
2210 state->layout->me = NULL;
2211 state->layout->mines = snewn(wh, char);
2213 if (*desc && isdigit((unsigned char)*desc)) {
2214 x = atoi(desc);
2215 while (*desc && isdigit((unsigned char)*desc))
2216 desc++; /* skip over x coordinate */
2217 if (*desc) desc++; /* eat comma */
2218 y = atoi(desc);
2219 while (*desc && isdigit((unsigned char)*desc))
2220 desc++; /* skip over y coordinate */
2221 if (*desc) desc++; /* eat comma */
2222 } else {
2223 x = y = -1;
2226 if (*desc == 'm') {
2227 masked = TRUE;
2228 desc++;
2229 } else {
2230 if (*desc == 'u')
2231 desc++;
2233 * We permit game IDs to be entered by hand without the
2234 * masking transformation.
2236 masked = FALSE;
2239 bmp = snewn((wh + 7) / 8, unsigned char);
2240 memset(bmp, 0, (wh + 7) / 8);
2241 for (i = 0; i < (wh+3)/4; i++) {
2242 int c = desc[i];
2243 int v;
2245 assert(c != 0); /* validate_desc should have caught */
2246 if (c >= '0' && c <= '9')
2247 v = c - '0';
2248 else if (c >= 'a' && c <= 'f')
2249 v = c - 'a' + 10;
2250 else if (c >= 'A' && c <= 'F')
2251 v = c - 'A' + 10;
2252 else
2253 v = 0;
2255 bmp[i / 2] |= v << (4 * (1 - (i % 2)));
2258 if (masked)
2259 obfuscate_bitmap(bmp, wh, TRUE);
2261 memset(state->layout->mines, 0, wh);
2262 for (i = 0; i < wh; i++) {
2263 if (bmp[i / 8] & (0x80 >> (i % 8)))
2264 state->layout->mines[i] = 1;
2267 if (x >= 0 && y >= 0)
2268 ret = open_square(state, x, y);
2269 sfree(bmp);
2272 return state;
2275 static game_state *dup_game(game_state *state)
2277 game_state *ret = snew(game_state);
2279 ret->w = state->w;
2280 ret->h = state->h;
2281 ret->n = state->n;
2282 ret->dead = state->dead;
2283 ret->won = state->won;
2284 ret->used_solve = state->used_solve;
2285 ret->layout = state->layout;
2286 ret->layout->refcount++;
2287 ret->grid = snewn(ret->w * ret->h, signed char);
2288 memcpy(ret->grid, state->grid, ret->w * ret->h);
2290 return ret;
2293 static void free_game(game_state *state)
2295 if (--state->layout->refcount <= 0) {
2296 sfree(state->layout->mines);
2297 if (state->layout->rs)
2298 random_free(state->layout->rs);
2299 sfree(state->layout);
2301 sfree(state->grid);
2302 sfree(state);
2305 static char *solve_game(game_state *state, game_state *currstate,
2306 char *aux, char **error)
2308 if (!state->layout->mines) {
2309 *error = "Game has not been started yet";
2310 return NULL;
2313 return dupstr("S");
2316 static int game_can_format_as_text_now(game_params *params)
2318 return TRUE;
2321 static char *game_text_format(game_state *state)
2323 char *ret;
2324 int x, y;
2326 ret = snewn((state->w + 1) * state->h + 1, char);
2327 for (y = 0; y < state->h; y++) {
2328 for (x = 0; x < state->w; x++) {
2329 int v = state->grid[y*state->w+x];
2330 if (v == 0)
2331 v = '-';
2332 else if (v >= 1 && v <= 8)
2333 v = '0' + v;
2334 else if (v == -1)
2335 v = '*';
2336 else if (v == -2 || v == -3)
2337 v = '?';
2338 else if (v >= 64)
2339 v = '!';
2340 ret[y * (state->w+1) + x] = v;
2342 ret[y * (state->w+1) + state->w] = '\n';
2344 ret[(state->w + 1) * state->h] = '\0';
2346 return ret;
2349 struct game_ui {
2350 int hx, hy, hradius; /* for mouse-down highlights */
2351 int validradius;
2352 int flash_is_death;
2353 int deaths, completed;
2354 int cur_x, cur_y, cur_visible;
2357 static game_ui *new_ui(game_state *state)
2359 game_ui *ui = snew(game_ui);
2360 ui->hx = ui->hy = -1;
2361 ui->hradius = ui->validradius = 0;
2362 ui->deaths = 0;
2363 ui->completed = FALSE;
2364 ui->flash_is_death = FALSE; /* *shrug* */
2365 ui->cur_x = ui->cur_y = ui->cur_visible = 0;
2366 return ui;
2369 static void free_ui(game_ui *ui)
2371 sfree(ui);
2374 static char *encode_ui(game_ui *ui)
2376 char buf[80];
2378 * The deaths counter and completion status need preserving
2379 * across a serialisation.
2381 sprintf(buf, "D%d", ui->deaths);
2382 if (ui->completed)
2383 strcat(buf, "C");
2384 return dupstr(buf);
2387 static void decode_ui(game_ui *ui, char *encoding)
2389 int p= 0;
2390 sscanf(encoding, "D%d%n", &ui->deaths, &p);
2391 if (encoding[p] == 'C')
2392 ui->completed = TRUE;
2395 static void game_changed_state(game_ui *ui, game_state *oldstate,
2396 game_state *newstate)
2398 if (newstate->won)
2399 ui->completed = TRUE;
2402 struct game_drawstate {
2403 int w, h, started, tilesize, bg;
2404 signed char *grid;
2406 * Items in this `grid' array have all the same values as in
2407 * the game_state grid, and in addition:
2409 * - -10 means the tile was drawn `specially' as a result of a
2410 * flash, so it will always need redrawing.
2412 * - -22 and -23 mean the tile is highlighted for a possible
2413 * click.
2415 int cur_x, cur_y; /* -1, -1 for no cursor displayed. */
2418 static char *interpret_move(game_state *from, game_ui *ui, game_drawstate *ds,
2419 int x, int y, int button)
2421 int cx, cy;
2422 char buf[256];
2424 if (from->dead || from->won)
2425 return NULL; /* no further moves permitted */
2427 cx = FROMCOORD(x);
2428 cy = FROMCOORD(y);
2430 if (IS_CURSOR_MOVE(button)) {
2431 move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h, 0);
2432 ui->cur_visible = 1;
2433 return "";
2435 if (IS_CURSOR_SELECT(button)) {
2436 int v = from->grid[ui->cur_y * from->w + ui->cur_x];
2438 if (!ui->cur_visible) {
2439 ui->cur_visible = 1;
2440 return "";
2442 if (button == CURSOR_SELECT2) {
2443 /* As for RIGHT_BUTTON; only works on covered square. */
2444 if (v != -2 && v != -1)
2445 return NULL;
2446 sprintf(buf, "F%d,%d", ui->cur_x, ui->cur_y);
2447 return dupstr(buf);
2449 /* Otherwise, treat as LEFT_BUTTON, for a single square. */
2450 if (v == -2 || v == -3) {
2451 if (from->layout->mines &&
2452 from->layout->mines[ui->cur_y * from->w + ui->cur_x])
2453 ui->deaths++;
2455 sprintf(buf, "O%d,%d", ui->cur_x, ui->cur_y);
2456 return dupstr(buf);
2458 cx = ui->cur_x; cy = ui->cur_y;
2459 ui->validradius = 1;
2460 goto uncover;
2463 if (button == LEFT_BUTTON || button == LEFT_DRAG ||
2464 button == MIDDLE_BUTTON || button == MIDDLE_DRAG) {
2465 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
2466 return NULL;
2469 * Mouse-downs and mouse-drags just cause highlighting
2470 * updates.
2472 ui->hx = cx;
2473 ui->hy = cy;
2474 ui->hradius = (from->grid[cy*from->w+cx] >= 0 ? 1 : 0);
2475 if (button == LEFT_BUTTON)
2476 ui->validradius = ui->hradius;
2477 else if (button == MIDDLE_BUTTON)
2478 ui->validradius = 1;
2479 ui->cur_visible = 0;
2480 return "";
2483 if (button == RIGHT_BUTTON) {
2484 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
2485 return NULL;
2488 * Right-clicking only works on a covered square, and it
2489 * toggles between -1 (marked as mine) and -2 (not marked
2490 * as mine).
2492 * FIXME: question marks.
2494 if (from->grid[cy * from->w + cx] != -2 &&
2495 from->grid[cy * from->w + cx] != -1)
2496 return NULL;
2498 sprintf(buf, "F%d,%d", cx, cy);
2499 return dupstr(buf);
2502 if (button == LEFT_RELEASE || button == MIDDLE_RELEASE) {
2503 ui->hx = ui->hy = -1;
2504 ui->hradius = 0;
2507 * At this stage we must never return NULL: we have adjusted
2508 * the ui, so at worst we return "".
2510 if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h)
2511 return "";
2514 * Left-clicking on a covered square opens a tile. Not
2515 * permitted if the tile is marked as a mine, for safety.
2516 * (Unmark it and _then_ open it.)
2518 if (button == LEFT_RELEASE &&
2519 (from->grid[cy * from->w + cx] == -2 ||
2520 from->grid[cy * from->w + cx] == -3) &&
2521 ui->validradius == 0) {
2522 /* Check if you've killed yourself. */
2523 if (from->layout->mines && from->layout->mines[cy * from->w + cx])
2524 ui->deaths++;
2526 sprintf(buf, "O%d,%d", cx, cy);
2527 return dupstr(buf);
2529 goto uncover;
2531 return NULL;
2533 uncover:
2536 * Left-clicking or middle-clicking on an uncovered tile:
2537 * first we check to see if the number of mine markers
2538 * surrounding the tile is equal to its mine count, and if
2539 * so then we open all other surrounding squares.
2541 if (from->grid[cy * from->w + cx] > 0 && ui->validradius == 1) {
2542 int dy, dx, n;
2544 /* Count mine markers. */
2545 n = 0;
2546 for (dy = -1; dy <= +1; dy++)
2547 for (dx = -1; dx <= +1; dx++)
2548 if (cx+dx >= 0 && cx+dx < from->w &&
2549 cy+dy >= 0 && cy+dy < from->h) {
2550 if (from->grid[(cy+dy)*from->w+(cx+dx)] == -1)
2551 n++;
2554 if (n == from->grid[cy * from->w + cx]) {
2557 * Now see if any of the squares we're clearing
2558 * contains a mine (which will happen iff you've
2559 * incorrectly marked the mines around the clicked
2560 * square). If so, we open _just_ those squares, to
2561 * reveal as little additional information as we
2562 * can.
2564 char *p = buf;
2565 char *sep = "";
2567 for (dy = -1; dy <= +1; dy++)
2568 for (dx = -1; dx <= +1; dx++)
2569 if (cx+dx >= 0 && cx+dx < from->w &&
2570 cy+dy >= 0 && cy+dy < from->h) {
2571 if (from->grid[(cy+dy)*from->w+(cx+dx)] != -1 &&
2572 from->layout->mines &&
2573 from->layout->mines[(cy+dy)*from->w+(cx+dx)]) {
2574 p += sprintf(p, "%sO%d,%d", sep, cx+dx, cy+dy);
2575 sep = ";";
2579 if (p > buf) {
2580 ui->deaths++;
2581 } else {
2582 sprintf(buf, "C%d,%d", cx, cy);
2585 return dupstr(buf);
2589 return "";
2593 static game_state *execute_move(game_state *from, char *move)
2595 int cy, cx;
2596 game_state *ret;
2598 if (!strcmp(move, "S")) {
2600 * Simply expose the entire grid as if it were a completed
2601 * solution.
2603 int yy, xx;
2605 ret = dup_game(from);
2606 for (yy = 0; yy < ret->h; yy++)
2607 for (xx = 0; xx < ret->w; xx++) {
2609 if (ret->layout->mines[yy*ret->w+xx]) {
2610 ret->grid[yy*ret->w+xx] = -1;
2611 } else {
2612 int dx, dy, v;
2614 v = 0;
2616 for (dx = -1; dx <= +1; dx++)
2617 for (dy = -1; dy <= +1; dy++)
2618 if (xx+dx >= 0 && xx+dx < ret->w &&
2619 yy+dy >= 0 && yy+dy < ret->h &&
2620 ret->layout->mines[(yy+dy)*ret->w+(xx+dx)])
2621 v++;
2623 ret->grid[yy*ret->w+xx] = v;
2626 ret->used_solve = TRUE;
2627 ret->won = TRUE;
2629 return ret;
2630 } else {
2631 ret = dup_game(from);
2633 while (*move) {
2634 if (move[0] == 'F' &&
2635 sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
2636 cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) {
2637 ret->grid[cy * from->w + cx] ^= (-2 ^ -1);
2638 } else if (move[0] == 'O' &&
2639 sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
2640 cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) {
2641 open_square(ret, cx, cy);
2642 } else if (move[0] == 'C' &&
2643 sscanf(move+1, "%d,%d", &cx, &cy) == 2 &&
2644 cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) {
2645 int dx, dy;
2647 for (dy = -1; dy <= +1; dy++)
2648 for (dx = -1; dx <= +1; dx++)
2649 if (cx+dx >= 0 && cx+dx < ret->w &&
2650 cy+dy >= 0 && cy+dy < ret->h &&
2651 (ret->grid[(cy+dy)*ret->w+(cx+dx)] == -2 ||
2652 ret->grid[(cy+dy)*ret->w+(cx+dx)] == -3))
2653 open_square(ret, cx+dx, cy+dy);
2654 } else {
2655 free_game(ret);
2656 return NULL;
2659 while (*move && *move != ';') move++;
2660 if (*move) move++;
2663 return ret;
2667 /* ----------------------------------------------------------------------
2668 * Drawing routines.
2671 static void game_compute_size(game_params *params, int tilesize,
2672 int *x, int *y)
2674 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2675 struct { int tilesize; } ads, *ds = &ads;
2676 ads.tilesize = tilesize;
2678 *x = BORDER * 2 + TILE_SIZE * params->w;
2679 *y = BORDER * 2 + TILE_SIZE * params->h;
2682 static void game_set_size(drawing *dr, game_drawstate *ds,
2683 game_params *params, int tilesize)
2685 ds->tilesize = tilesize;
2688 static float *game_colours(frontend *fe, int *ncolours)
2690 float *ret = snewn(3 * NCOLOURS, float);
2692 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
2694 ret[COL_BACKGROUND2 * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 19.0F / 20.0F;
2695 ret[COL_BACKGROUND2 * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 19.0F / 20.0F;
2696 ret[COL_BACKGROUND2 * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 19.0F / 20.0F;
2698 ret[COL_1 * 3 + 0] = 0.0F;
2699 ret[COL_1 * 3 + 1] = 0.0F;
2700 ret[COL_1 * 3 + 2] = 1.0F;
2702 ret[COL_2 * 3 + 0] = 0.0F;
2703 ret[COL_2 * 3 + 1] = 0.5F;
2704 ret[COL_2 * 3 + 2] = 0.0F;
2706 ret[COL_3 * 3 + 0] = 1.0F;
2707 ret[COL_3 * 3 + 1] = 0.0F;
2708 ret[COL_3 * 3 + 2] = 0.0F;
2710 ret[COL_4 * 3 + 0] = 0.0F;
2711 ret[COL_4 * 3 + 1] = 0.0F;
2712 ret[COL_4 * 3 + 2] = 0.5F;
2714 ret[COL_5 * 3 + 0] = 0.5F;
2715 ret[COL_5 * 3 + 1] = 0.0F;
2716 ret[COL_5 * 3 + 2] = 0.0F;
2718 ret[COL_6 * 3 + 0] = 0.0F;
2719 ret[COL_6 * 3 + 1] = 0.5F;
2720 ret[COL_6 * 3 + 2] = 0.5F;
2722 ret[COL_7 * 3 + 0] = 0.0F;
2723 ret[COL_7 * 3 + 1] = 0.0F;
2724 ret[COL_7 * 3 + 2] = 0.0F;
2726 ret[COL_8 * 3 + 0] = 0.5F;
2727 ret[COL_8 * 3 + 1] = 0.5F;
2728 ret[COL_8 * 3 + 2] = 0.5F;
2730 ret[COL_MINE * 3 + 0] = 0.0F;
2731 ret[COL_MINE * 3 + 1] = 0.0F;
2732 ret[COL_MINE * 3 + 2] = 0.0F;
2734 ret[COL_BANG * 3 + 0] = 1.0F;
2735 ret[COL_BANG * 3 + 1] = 0.0F;
2736 ret[COL_BANG * 3 + 2] = 0.0F;
2738 ret[COL_CROSS * 3 + 0] = 1.0F;
2739 ret[COL_CROSS * 3 + 1] = 0.0F;
2740 ret[COL_CROSS * 3 + 2] = 0.0F;
2742 ret[COL_FLAG * 3 + 0] = 1.0F;
2743 ret[COL_FLAG * 3 + 1] = 0.0F;
2744 ret[COL_FLAG * 3 + 2] = 0.0F;
2746 ret[COL_FLAGBASE * 3 + 0] = 0.0F;
2747 ret[COL_FLAGBASE * 3 + 1] = 0.0F;
2748 ret[COL_FLAGBASE * 3 + 2] = 0.0F;
2750 ret[COL_QUERY * 3 + 0] = 0.0F;
2751 ret[COL_QUERY * 3 + 1] = 0.0F;
2752 ret[COL_QUERY * 3 + 2] = 0.0F;
2754 ret[COL_HIGHLIGHT * 3 + 0] = 1.0F;
2755 ret[COL_HIGHLIGHT * 3 + 1] = 1.0F;
2756 ret[COL_HIGHLIGHT * 3 + 2] = 1.0F;
2758 ret[COL_LOWLIGHT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2.0F / 3.0F;
2759 ret[COL_LOWLIGHT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2.0F / 3.0F;
2760 ret[COL_LOWLIGHT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2.0F / 3.0F;
2762 ret[COL_WRONGNUMBER * 3 + 0] = 1.0F;
2763 ret[COL_WRONGNUMBER * 3 + 1] = 0.6F;
2764 ret[COL_WRONGNUMBER * 3 + 2] = 0.6F;
2766 /* Red tinge to a light colour, for the cursor. */
2767 ret[COL_CURSOR * 3 + 0] = ret[COL_HIGHLIGHT * 3 + 0];
2768 ret[COL_CURSOR * 3 + 1] = ret[COL_HIGHLIGHT * 3 + 0] / 2.0F;
2769 ret[COL_CURSOR * 3 + 2] = ret[COL_HIGHLIGHT * 3 + 0] / 2.0F;
2771 *ncolours = NCOLOURS;
2772 return ret;
2775 static game_drawstate *game_new_drawstate(drawing *dr, game_state *state)
2777 struct game_drawstate *ds = snew(struct game_drawstate);
2779 ds->w = state->w;
2780 ds->h = state->h;
2781 ds->started = FALSE;
2782 ds->tilesize = 0; /* not decided yet */
2783 ds->grid = snewn(ds->w * ds->h, signed char);
2784 ds->bg = -1;
2785 ds->cur_x = ds->cur_y = -1;
2787 memset(ds->grid, -99, ds->w * ds->h);
2789 return ds;
2792 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
2794 sfree(ds->grid);
2795 sfree(ds);
2798 static void draw_tile(drawing *dr, game_drawstate *ds,
2799 int x, int y, int v, int bg)
2801 if (v < 0) {
2802 int coords[12];
2803 int hl = 0;
2805 if (v == -22 || v == -23) {
2806 v += 20;
2809 * Omit the highlights in this case.
2811 draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE,
2812 bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg);
2813 draw_line(dr, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
2814 draw_line(dr, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
2815 } else {
2817 * Draw highlights to indicate the square is covered.
2819 coords[0] = x + TILE_SIZE - 1;
2820 coords[1] = y + TILE_SIZE - 1;
2821 coords[2] = x + TILE_SIZE - 1;
2822 coords[3] = y;
2823 coords[4] = x;
2824 coords[5] = y + TILE_SIZE - 1;
2825 draw_polygon(dr, coords, 3, COL_LOWLIGHT ^ hl, COL_LOWLIGHT ^ hl);
2827 coords[0] = x;
2828 coords[1] = y;
2829 draw_polygon(dr, coords, 3, COL_HIGHLIGHT ^ hl,
2830 COL_HIGHLIGHT ^ hl);
2832 draw_rect(dr, x + HIGHLIGHT_WIDTH, y + HIGHLIGHT_WIDTH,
2833 TILE_SIZE - 2*HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH,
2834 bg);
2837 if (v == -1) {
2839 * Draw a flag.
2841 #define SETCOORD(n, dx, dy) do { \
2842 coords[(n)*2+0] = x + (int)(TILE_SIZE * (dx)); \
2843 coords[(n)*2+1] = y + (int)(TILE_SIZE * (dy)); \
2844 } while (0)
2845 SETCOORD(0, 0.6F, 0.35F);
2846 SETCOORD(1, 0.6F, 0.7F);
2847 SETCOORD(2, 0.8F, 0.8F);
2848 SETCOORD(3, 0.25F, 0.8F);
2849 SETCOORD(4, 0.55F, 0.7F);
2850 SETCOORD(5, 0.55F, 0.35F);
2851 draw_polygon(dr, coords, 6, COL_FLAGBASE, COL_FLAGBASE);
2853 SETCOORD(0, 0.6F, 0.2F);
2854 SETCOORD(1, 0.6F, 0.5F);
2855 SETCOORD(2, 0.2F, 0.35F);
2856 draw_polygon(dr, coords, 3, COL_FLAG, COL_FLAG);
2857 #undef SETCOORD
2859 } else if (v == -3) {
2861 * Draw a question mark.
2863 draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
2864 FONT_VARIABLE, TILE_SIZE * 6 / 8,
2865 ALIGN_VCENTRE | ALIGN_HCENTRE,
2866 COL_QUERY, "?");
2868 } else {
2870 * Clear the square to the background colour, and draw thin
2871 * grid lines along the top and left.
2873 * Exception is that for value 65 (mine we've just trodden
2874 * on), we clear the square to COL_BANG.
2876 if (v & 32) {
2877 bg = COL_WRONGNUMBER;
2878 v &= ~32;
2880 draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE,
2881 (v == 65 ? COL_BANG :
2882 bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg));
2883 draw_line(dr, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT);
2884 draw_line(dr, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT);
2886 if (v > 0 && v <= 8) {
2888 * Mark a number.
2890 char str[2];
2891 str[0] = v + '0';
2892 str[1] = '\0';
2893 draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
2894 FONT_VARIABLE, TILE_SIZE * 7 / 8,
2895 ALIGN_VCENTRE | ALIGN_HCENTRE,
2896 (COL_1 - 1) + v, str);
2898 } else if (v >= 64) {
2900 * Mark a mine.
2902 * FIXME: this could be done better!
2904 #if 0
2905 draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2,
2906 FONT_VARIABLE, TILE_SIZE * 7 / 8,
2907 ALIGN_VCENTRE | ALIGN_HCENTRE,
2908 COL_MINE, "*");
2909 #else
2911 int cx = x + TILE_SIZE / 2;
2912 int cy = y + TILE_SIZE / 2;
2913 int r = TILE_SIZE / 2 - 3;
2914 int coords[4*5*2];
2915 int xdx = 1, xdy = 0, ydx = 0, ydy = 1;
2916 int tdx, tdy, i;
2918 for (i = 0; i < 4*5*2; i += 5*2) {
2919 coords[i+2*0+0] = cx - r/6*xdx + r*4/5*ydx;
2920 coords[i+2*0+1] = cy - r/6*xdy + r*4/5*ydy;
2921 coords[i+2*1+0] = cx - r/6*xdx + r*ydx;
2922 coords[i+2*1+1] = cy - r/6*xdy + r*ydy;
2923 coords[i+2*2+0] = cx + r/6*xdx + r*ydx;
2924 coords[i+2*2+1] = cy + r/6*xdy + r*ydy;
2925 coords[i+2*3+0] = cx + r/6*xdx + r*4/5*ydx;
2926 coords[i+2*3+1] = cy + r/6*xdy + r*4/5*ydy;
2927 coords[i+2*4+0] = cx + r*3/5*xdx + r*3/5*ydx;
2928 coords[i+2*4+1] = cy + r*3/5*xdy + r*3/5*ydy;
2930 tdx = ydx;
2931 tdy = ydy;
2932 ydx = xdx;
2933 ydy = xdy;
2934 xdx = -tdx;
2935 xdy = -tdy;
2938 draw_polygon(dr, coords, 5*4, COL_MINE, COL_MINE);
2940 draw_rect(dr, cx-r/3, cy-r/3, r/3, r/4, COL_HIGHLIGHT);
2942 #endif
2944 if (v == 66) {
2946 * Cross through the mine.
2948 int dx;
2949 for (dx = -1; dx <= +1; dx++) {
2950 draw_line(dr, x + 3 + dx, y + 2,
2951 x + TILE_SIZE - 3 + dx,
2952 y + TILE_SIZE - 2, COL_CROSS);
2953 draw_line(dr, x + TILE_SIZE - 3 + dx, y + 2,
2954 x + 3 + dx, y + TILE_SIZE - 2,
2955 COL_CROSS);
2961 draw_update(dr, x, y, TILE_SIZE, TILE_SIZE);
2964 static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
2965 game_state *state, int dir, game_ui *ui,
2966 float animtime, float flashtime)
2968 int x, y;
2969 int mines, markers, bg;
2970 int cx = -1, cy = -1, cmoved;
2972 if (flashtime) {
2973 int frame = (int)(flashtime / FLASH_FRAME);
2974 if (frame % 2)
2975 bg = (ui->flash_is_death ? COL_BACKGROUND : COL_LOWLIGHT);
2976 else
2977 bg = (ui->flash_is_death ? COL_BANG : COL_HIGHLIGHT);
2978 } else
2979 bg = COL_BACKGROUND;
2981 if (!ds->started) {
2982 int coords[10];
2984 draw_rect(dr, 0, 0,
2985 TILE_SIZE * state->w + 2 * BORDER,
2986 TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND);
2987 draw_update(dr, 0, 0,
2988 TILE_SIZE * state->w + 2 * BORDER,
2989 TILE_SIZE * state->h + 2 * BORDER);
2992 * Recessed area containing the whole puzzle.
2994 coords[0] = COORD(state->w) + OUTER_HIGHLIGHT_WIDTH - 1;
2995 coords[1] = COORD(state->h) + OUTER_HIGHLIGHT_WIDTH - 1;
2996 coords[2] = COORD(state->w) + OUTER_HIGHLIGHT_WIDTH - 1;
2997 coords[3] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
2998 coords[4] = coords[2] - TILE_SIZE;
2999 coords[5] = coords[3] + TILE_SIZE;
3000 coords[8] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
3001 coords[9] = COORD(state->h) + OUTER_HIGHLIGHT_WIDTH - 1;
3002 coords[6] = coords[8] + TILE_SIZE;
3003 coords[7] = coords[9] - TILE_SIZE;
3004 draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT);
3006 coords[1] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
3007 coords[0] = COORD(0) - OUTER_HIGHLIGHT_WIDTH;
3008 draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT);
3010 ds->started = TRUE;
3013 if (ui->cur_visible) cx = ui->cur_x;
3014 if (ui->cur_visible) cy = ui->cur_y;
3015 cmoved = (cx != ds->cur_x || cy != ds->cur_y);
3018 * Now draw the tiles. Also in this loop, count up the number
3019 * of mines and mine markers.
3021 mines = markers = 0;
3022 for (y = 0; y < ds->h; y++)
3023 for (x = 0; x < ds->w; x++) {
3024 int v = state->grid[y*ds->w+x], cc = 0;
3026 if (v == -1)
3027 markers++;
3028 if (state->layout->mines && state->layout->mines[y*ds->w+x])
3029 mines++;
3031 if (v >= 0 && v <= 8) {
3033 * Count up the flags around this tile, and if
3034 * there are too _many_, highlight the tile.
3036 int dx, dy, flags = 0;
3038 for (dy = -1; dy <= +1; dy++)
3039 for (dx = -1; dx <= +1; dx++) {
3040 int nx = x+dx, ny = y+dy;
3041 if (nx >= 0 && nx < ds->w &&
3042 ny >= 0 && ny < ds->h &&
3043 state->grid[ny*ds->w+nx] == -1)
3044 flags++;
3047 if (flags > v)
3048 v |= 32;
3051 if ((v == -2 || v == -3) &&
3052 (abs(x-ui->hx) <= ui->hradius && abs(y-ui->hy) <= ui->hradius))
3053 v -= 20;
3055 if (cmoved && /* if cursor has moved, force redraw of curr and prev pos */
3056 ((x == cx && y == cy) || (x == ds->cur_x && y == ds->cur_y)))
3057 cc = 1;
3059 if (ds->grid[y*ds->w+x] != v || bg != ds->bg || cc) {
3060 draw_tile(dr, ds, COORD(x), COORD(y), v,
3061 (x == cx && y == cy) ? COL_CURSOR : bg);
3062 ds->grid[y*ds->w+x] = v;
3065 ds->bg = bg;
3066 ds->cur_x = cx; ds->cur_y = cy;
3068 if (!state->layout->mines)
3069 mines = state->layout->n;
3072 * Update the status bar.
3075 char statusbar[512];
3076 if (state->dead) {
3077 sprintf(statusbar, "DEAD!");
3078 } else if (state->won) {
3079 if (state->used_solve)
3080 sprintf(statusbar, "Auto-solved.");
3081 else
3082 sprintf(statusbar, "COMPLETED!");
3083 } else {
3084 sprintf(statusbar, "Marked: %d / %d", markers, mines);
3086 if (ui->deaths)
3087 sprintf(statusbar + strlen(statusbar),
3088 " Deaths: %d", ui->deaths);
3089 status_bar(dr, statusbar);
3093 static float game_anim_length(game_state *oldstate, game_state *newstate,
3094 int dir, game_ui *ui)
3096 return 0.0F;
3099 static float game_flash_length(game_state *oldstate, game_state *newstate,
3100 int dir, game_ui *ui)
3102 if (oldstate->used_solve || newstate->used_solve)
3103 return 0.0F;
3105 if (dir > 0 && !oldstate->dead && !oldstate->won) {
3106 if (newstate->dead) {
3107 ui->flash_is_death = TRUE;
3108 return 3 * FLASH_FRAME;
3110 if (newstate->won) {
3111 ui->flash_is_death = FALSE;
3112 return 2 * FLASH_FRAME;
3115 return 0.0F;
3118 static int game_timing_state(game_state *state, game_ui *ui)
3120 if (state->dead || state->won || ui->completed || !state->layout->mines)
3121 return FALSE;
3122 return TRUE;
3125 static void game_print_size(game_params *params, float *x, float *y)
3129 static void game_print(drawing *dr, game_state *state, int tilesize)
3133 #ifdef COMBINED
3134 #define thegame mines
3135 #endif
3137 const struct game thegame = {
3138 "Mines", "games.mines", "mines",
3139 default_params,
3140 game_fetch_preset,
3141 decode_params,
3142 encode_params,
3143 free_params,
3144 dup_params,
3145 TRUE, game_configure, custom_params,
3146 validate_params,
3147 new_game_desc,
3148 validate_desc,
3149 new_game,
3150 dup_game,
3151 free_game,
3152 TRUE, solve_game,
3153 TRUE, game_can_format_as_text_now, game_text_format,
3154 new_ui,
3155 free_ui,
3156 encode_ui,
3157 decode_ui,
3158 game_changed_state,
3159 interpret_move,
3160 execute_move,
3161 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
3162 game_colours,
3163 game_new_drawstate,
3164 game_free_drawstate,
3165 game_redraw,
3166 game_anim_length,
3167 game_flash_length,
3168 FALSE, FALSE, game_print_size, game_print,
3169 TRUE, /* wants_statusbar */
3170 TRUE, game_timing_state,
3171 BUTTON_BEATS(LEFT_BUTTON, RIGHT_BUTTON) | REQUIRE_RBUTTON,
3174 #ifdef STANDALONE_OBFUSCATOR
3177 * Vaguely useful stand-alone program which translates between
3178 * obfuscated and clear Mines game descriptions. Pass in a game
3179 * description on the command line, and if it's clear it will be
3180 * obfuscated and vice versa. The output text should also be a
3181 * valid game ID describing the same game. Like this:
3183 * $ ./mineobfusc 9x9:4,4,mb071b49fbd1cb6a0d5868
3184 * 9x9:4,4,004000007c00010022080
3185 * $ ./mineobfusc 9x9:4,4,004000007c00010022080
3186 * 9x9:4,4,mb071b49fbd1cb6a0d5868
3189 int main(int argc, char **argv)
3191 game_params *p;
3192 game_state *s;
3193 char *id = NULL, *desc, *err;
3194 int y, x;
3196 while (--argc > 0) {
3197 char *p = *++argv;
3198 if (*p == '-') {
3199 fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
3200 return 1;
3201 } else {
3202 id = p;
3206 if (!id) {
3207 fprintf(stderr, "usage: %s <game_id>\n", argv[0]);
3208 return 1;
3211 desc = strchr(id, ':');
3212 if (!desc) {
3213 fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
3214 return 1;
3216 *desc++ = '\0';
3218 p = default_params();
3219 decode_params(p, id);
3220 err = validate_desc(p, desc);
3221 if (err) {
3222 fprintf(stderr, "%s: %s\n", argv[0], err);
3223 return 1;
3225 s = new_game(NULL, p, desc);
3227 x = atoi(desc);
3228 while (*desc && *desc != ',') desc++;
3229 if (*desc) desc++;
3230 y = atoi(desc);
3231 while (*desc && *desc != ',') desc++;
3232 if (*desc) desc++;
3234 printf("%s:%s\n", id, describe_layout(s->layout->mines,
3235 p->w * p->h,
3236 x, y,
3237 (*desc != 'm')));
3239 return 0;
3242 #endif
3244 /* vim: set shiftwidth=4 tabstop=8: */