A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/*
2 * map.c: Game involving four-colouring a map.
3 */
4
5/*
6 * TODO:
7 *
8 * - clue marking
9 * - better four-colouring algorithm?
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <assert.h>
16#include <ctype.h>
17#include <limits.h>
18#ifdef NO_TGMATH_H
19# include <math.h>
20#else
21# include <tgmath.h>
22#endif
23
24#include "puzzles.h"
25
26/*
27 * In standalone solver mode, `verbose' is a variable which can be
28 * set by command-line option; in debugging mode it's simply always
29 * true.
30 */
31#if defined STANDALONE_SOLVER
32#define SOLVER_DIAGNOSTICS
33static bool verbose = false;
34#elif defined SOLVER_DIAGNOSTICS
35#define verbose true
36#endif
37
38/*
39 * I don't seriously anticipate wanting to change the number of
40 * colours used in this game, but it doesn't cost much to use a
41 * #define just in case :-)
42 */
43#define FOUR 4
44#define THREE (FOUR-1)
45#define FIVE (FOUR+1)
46#define SIX (FOUR+2)
47
48/*
49 * Difficulty levels. I do some macro ickery here to ensure that my
50 * enum and the various forms of my name list always match up.
51 */
52#define DIFFLIST(A) \
53 A(EASY,Easy,e) \
54 A(NORMAL,Normal,n) \
55 A(HARD,Hard,h) \
56 A(RECURSE,Unreasonable,u)
57#define ENUM(upper,title,lower) DIFF_ ## upper,
58#define TITLE(upper,title,lower) #title,
59#define ENCODE(upper,title,lower) #lower
60#define CONFIG(upper,title,lower) ":" #title
61enum { DIFFLIST(ENUM) DIFFCOUNT };
62static char const *const map_diffnames[] = { DIFFLIST(TITLE) };
63static char const map_diffchars[] = DIFFLIST(ENCODE);
64#define DIFFCONFIG DIFFLIST(CONFIG)
65
66enum { TE, BE, LE, RE }; /* top/bottom/left/right edges */
67
68enum {
69 COL_BACKGROUND,
70 COL_GRID,
71 COL_0, COL_1, COL_2, COL_3,
72 COL_ERROR, COL_ERRTEXT,
73 NCOLOURS
74};
75
76enum {
77 PREF_FLASH_TYPE,
78 PREF_SHOW_NUMBERS,
79 PREF_STIPPLE_STYLE,
80 N_PREF_ITEMS
81};
82
83struct game_params {
84 int w, h, n, diff;
85};
86
87struct map {
88 int refcount;
89 int *map;
90 int *graph;
91 int n;
92 int ngraph;
93 bool *immutable;
94 int *edgex, *edgey; /* position of a point on each edge */
95 int *regionx, *regiony; /* position of a point in each region */
96};
97
98struct game_state {
99 game_params p;
100 struct map *map;
101 int *colouring, *pencil;
102 bool completed, cheated;
103};
104
105static game_params *default_params(void)
106{
107 game_params *ret = snew(game_params);
108
109#ifdef PORTRAIT_SCREEN
110 ret->w = 16;
111 ret->h = 18;
112#else
113 ret->w = 20;
114 ret->h = 15;
115#endif
116 ret->n = 30;
117 ret->diff = DIFF_NORMAL;
118
119 return ret;
120}
121
122static const struct game_params map_presets[] = {
123#ifdef PORTRAIT_SCREEN
124 {16, 18, 30, DIFF_EASY},
125 {16, 18, 30, DIFF_NORMAL},
126 {16, 18, 30, DIFF_HARD},
127 {16, 18, 30, DIFF_RECURSE},
128 {25, 30, 75, DIFF_NORMAL},
129 {25, 30, 75, DIFF_HARD},
130#else
131 {20, 15, 30, DIFF_EASY},
132 {20, 15, 30, DIFF_NORMAL},
133 {20, 15, 30, DIFF_HARD},
134 {20, 15, 30, DIFF_RECURSE},
135 {30, 25, 75, DIFF_NORMAL},
136 {30, 25, 75, DIFF_HARD},
137#endif
138};
139
140static bool game_fetch_preset(int i, char **name, game_params **params)
141{
142 game_params *ret;
143 char str[80];
144
145 if (i < 0 || i >= lenof(map_presets))
146 return false;
147
148 ret = snew(game_params);
149 *ret = map_presets[i];
150
151 sprintf(str, "%dx%d, %d regions, %s", ret->w, ret->h, ret->n,
152 map_diffnames[ret->diff]);
153
154 *name = dupstr(str);
155 *params = ret;
156 return true;
157}
158
159static void free_params(game_params *params)
160{
161 sfree(params);
162}
163
164static game_params *dup_params(const game_params *params)
165{
166 game_params *ret = snew(game_params);
167 *ret = *params; /* structure copy */
168 return ret;
169}
170
171static void decode_params(game_params *params, char const *string)
172{
173 char const *p = string;
174
175 params->w = atoi(p);
176 while (*p && isdigit((unsigned char)*p)) p++;
177 if (*p == 'x') {
178 p++;
179 params->h = atoi(p);
180 while (*p && isdigit((unsigned char)*p)) p++;
181 } else {
182 params->h = params->w;
183 }
184 if (*p == 'n') {
185 p++;
186 params->n = atoi(p);
187 while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++;
188 } else {
189 if (params->h > 0 && params->w > 0 &&
190 params->w <= INT_MAX / params->h)
191 params->n = params->w * params->h / 8;
192 }
193 if (*p == 'd') {
194 int i;
195 p++;
196 for (i = 0; i < DIFFCOUNT; i++)
197 if (*p == map_diffchars[i])
198 params->diff = i;
199 if (*p) p++;
200 }
201}
202
203static char *encode_params(const game_params *params, bool full)
204{
205 char ret[400];
206
207 sprintf(ret, "%dx%dn%d", params->w, params->h, params->n);
208 if (full)
209 sprintf(ret + strlen(ret), "d%c", map_diffchars[params->diff]);
210
211 return dupstr(ret);
212}
213
214static config_item *game_configure(const game_params *params)
215{
216 config_item *ret;
217 char buf[80];
218
219 ret = snewn(5, config_item);
220
221 ret[0].name = "Width";
222 ret[0].type = C_STRING;
223 sprintf(buf, "%d", params->w);
224 ret[0].u.string.sval = dupstr(buf);
225
226 ret[1].name = "Height";
227 ret[1].type = C_STRING;
228 sprintf(buf, "%d", params->h);
229 ret[1].u.string.sval = dupstr(buf);
230
231 ret[2].name = "Regions";
232 ret[2].type = C_STRING;
233 sprintf(buf, "%d", params->n);
234 ret[2].u.string.sval = dupstr(buf);
235
236 ret[3].name = "Difficulty";
237 ret[3].type = C_CHOICES;
238 ret[3].u.choices.choicenames = DIFFCONFIG;
239 ret[3].u.choices.selected = params->diff;
240
241 ret[4].name = NULL;
242 ret[4].type = C_END;
243
244 return ret;
245}
246
247static game_params *custom_params(const config_item *cfg)
248{
249 game_params *ret = snew(game_params);
250
251 ret->w = atoi(cfg[0].u.string.sval);
252 ret->h = atoi(cfg[1].u.string.sval);
253 ret->n = atoi(cfg[2].u.string.sval);
254 ret->diff = cfg[3].u.choices.selected;
255
256 return ret;
257}
258
259static const char *validate_params(const game_params *params, bool full)
260{
261 if (params->w < 2 || params->h < 2)
262 return "Width and height must be at least two";
263 if (params->w > INT_MAX / 2 / params->h)
264 return "Width times height must not be unreasonably large";
265 if (params->n < 5)
266 return "Must have at least five regions";
267 if (params->n > params->w * params->h)
268 return "Too many regions to fit in grid";
269 return NULL;
270}
271
272/* ----------------------------------------------------------------------
273 * Cumulative frequency table functions.
274 */
275
276/*
277 * Initialise a cumulative frequency table. (Hardly worth writing
278 * this function; all it does is to initialise everything in the
279 * array to zero.)
280 */
281static void cf_init(int *table, int n)
282{
283 int i;
284
285 for (i = 0; i < n; i++)
286 table[i] = 0;
287}
288
289/*
290 * Increment the count of symbol `sym' by `count'.
291 */
292static void cf_add(int *table, int n, int sym, int count)
293{
294 int bit;
295
296 bit = 1;
297 while (sym != 0) {
298 if (sym & bit) {
299 table[sym] += count;
300 sym &= ~bit;
301 }
302 bit <<= 1;
303 }
304
305 table[0] += count;
306}
307
308/*
309 * Cumulative frequency lookup: return the total count of symbols
310 * with value less than `sym'.
311 */
312static int cf_clookup(int *table, int n, int sym)
313{
314 int bit, index, limit, count;
315
316 if (sym == 0)
317 return 0;
318
319 assert(0 < sym && sym <= n);
320
321 count = table[0]; /* start with the whole table size */
322
323 bit = 1;
324 while (bit < n)
325 bit <<= 1;
326
327 limit = n;
328
329 while (bit > 0) {
330 /*
331 * Find the least number with its lowest set bit in this
332 * position which is greater than or equal to sym.
333 */
334 index = ((sym + bit - 1) &~ (bit * 2 - 1)) + bit;
335
336 if (index < limit) {
337 count -= table[index];
338 limit = index;
339 }
340
341 bit >>= 1;
342 }
343
344 return count;
345}
346
347/*
348 * Single frequency lookup: return the count of symbol `sym'.
349 */
350static int cf_slookup(int *table, int n, int sym)
351{
352 int count, bit;
353
354 assert(0 <= sym && sym < n);
355
356 count = table[sym];
357
358 for (bit = 1; sym+bit < n && !(sym & bit); bit <<= 1)
359 count -= table[sym+bit];
360
361 return count;
362}
363
364/*
365 * Return the largest symbol index such that the cumulative
366 * frequency up to that symbol is less than _or equal to_ count.
367 */
368static int cf_whichsym(int *table, int n, int count) {
369 int bit, sym, top;
370
371 assert(count >= 0 && count < table[0]);
372
373 bit = 1;
374 while (bit < n)
375 bit <<= 1;
376
377 sym = 0;
378 top = table[0];
379
380 while (bit > 0) {
381 if (sym+bit < n) {
382 if (count >= top - table[sym+bit])
383 sym += bit;
384 else
385 top -= table[sym+bit];
386 }
387
388 bit >>= 1;
389 }
390
391 return sym;
392}
393
394/* ----------------------------------------------------------------------
395 * Map generation.
396 *
397 * FIXME: this isn't entirely optimal at present, because it
398 * inherently prioritises growing the largest region since there
399 * are more squares adjacent to it. This acts as a destabilising
400 * influence leading to a few large regions and mostly small ones.
401 * It might be better to do it some other way.
402 */
403
404#define WEIGHT_INCREASED 2 /* for increased perimeter */
405#define WEIGHT_DECREASED 4 /* for decreased perimeter */
406#define WEIGHT_UNCHANGED 3 /* for unchanged perimeter */
407
408/*
409 * Look at a square and decide which colours can be extended into
410 * it.
411 *
412 * If called with index < 0, it adds together one of
413 * WEIGHT_INCREASED, WEIGHT_DECREASED or WEIGHT_UNCHANGED for each
414 * colour that has a valid extension (according to the effect that
415 * it would have on the perimeter of the region being extended) and
416 * returns the overall total.
417 *
418 * If called with index >= 0, it returns one of the possible
419 * colours depending on the value of index, in such a way that the
420 * number of possible inputs which would give rise to a given
421 * return value correspond to the weight of that value.
422 */
423static int extend_options(int w, int h, int n, int *map,
424 int x, int y, int index)
425{
426 int c, i, dx, dy;
427 int col[8];
428 int total = 0;
429
430 if (map[y*w+x] >= 0) {
431 assert(index < 0);
432 return 0; /* can't do this square at all */
433 }
434
435 /*
436 * Fetch the eight neighbours of this square, in order around
437 * the square.
438 */
439 for (dy = -1; dy <= +1; dy++)
440 for (dx = -1; dx <= +1; dx++) {
441 int index = (dy < 0 ? 6-dx : dy > 0 ? 2+dx : 2*(1+dx));
442 if (x+dx >= 0 && x+dx < w && y+dy >= 0 && y+dy < h)
443 col[index] = map[(y+dy)*w+(x+dx)];
444 else
445 col[index] = -1;
446 }
447
448 /*
449 * Iterate over each colour that might be feasible.
450 *
451 * FIXME: this routine currently has O(n) running time. We
452 * could turn it into O(FOUR) by only bothering to iterate over
453 * the colours mentioned in the four neighbouring squares.
454 */
455
456 for (c = 0; c < n; c++) {
457 int count, neighbours, runs;
458
459 /*
460 * One of the even indices of col (representing the
461 * orthogonal neighbours of this square) must be equal to
462 * c, or else this square is not adjacent to region c and
463 * obviously cannot become an extension of it at this time.
464 */
465 neighbours = 0;
466 for (i = 0; i < 8; i += 2)
467 if (col[i] == c)
468 neighbours++;
469 if (!neighbours)
470 continue;
471
472 /*
473 * Now we know this square is adjacent to region c. The
474 * next question is, would extending it cause the region to
475 * become non-simply-connected? If so, we mustn't do it.
476 *
477 * We determine this by looking around col to see if we can
478 * find more than one separate run of colour c.
479 */
480 runs = 0;
481 for (i = 0; i < 8; i++)
482 if (col[i] == c && col[(i+1) & 7] != c)
483 runs++;
484 if (runs > 1)
485 continue;
486
487 assert(runs == 1);
488
489 /*
490 * This square is a possibility. Determine its effect on
491 * the region's perimeter (computed from the number of
492 * orthogonal neighbours - 1 means a perimeter increase, 3
493 * a decrease, 2 no change; 4 is impossible because the
494 * region would already not be simply connected) and we're
495 * done.
496 */
497 assert(neighbours > 0 && neighbours < 4);
498 count = (neighbours == 1 ? WEIGHT_INCREASED :
499 neighbours == 2 ? WEIGHT_UNCHANGED : WEIGHT_DECREASED);
500
501 total += count;
502 if (index >= 0 && index < count)
503 return c;
504 else
505 index -= count;
506 }
507
508 assert(index < 0);
509
510 return total;
511}
512
513static void genmap(int w, int h, int n, int *map, random_state *rs)
514{
515 int wh = w*h;
516 int x, y, i, k;
517 int *tmp;
518
519 assert(n <= wh);
520 tmp = snewn(wh, int);
521
522 /*
523 * Clear the map, and set up `tmp' as a list of grid indices.
524 */
525 for (i = 0; i < wh; i++) {
526 map[i] = -1;
527 tmp[i] = i;
528 }
529
530 /*
531 * Place the region seeds by selecting n members from `tmp'.
532 */
533 k = wh;
534 for (i = 0; i < n; i++) {
535 int j = random_upto(rs, k);
536 map[tmp[j]] = i;
537 tmp[j] = tmp[--k];
538 }
539
540 /*
541 * Re-initialise `tmp' as a cumulative frequency table. This
542 * will store the number of possible region colours we can
543 * extend into each square.
544 */
545 cf_init(tmp, wh);
546
547 /*
548 * Go through the grid and set up the initial cumulative
549 * frequencies.
550 */
551 for (y = 0; y < h; y++)
552 for (x = 0; x < w; x++)
553 cf_add(tmp, wh, y*w+x,
554 extend_options(w, h, n, map, x, y, -1));
555
556 /*
557 * Now repeatedly choose a square we can extend a region into,
558 * and do so.
559 */
560 while (tmp[0] > 0) {
561 int k = random_upto(rs, tmp[0]);
562 int sq;
563 int colour;
564 int xx, yy;
565
566 sq = cf_whichsym(tmp, wh, k);
567 k -= cf_clookup(tmp, wh, sq);
568 x = sq % w;
569 y = sq / w;
570 colour = extend_options(w, h, n, map, x, y, k);
571
572 map[sq] = colour;
573
574 /*
575 * Re-scan the nine cells around the one we've just
576 * modified.
577 */
578 for (yy = max(y-1, 0); yy < min(y+2, h); yy++)
579 for (xx = max(x-1, 0); xx < min(x+2, w); xx++) {
580 cf_add(tmp, wh, yy*w+xx,
581 -cf_slookup(tmp, wh, yy*w+xx) +
582 extend_options(w, h, n, map, xx, yy, -1));
583 }
584 }
585
586 /*
587 * Finally, go through and normalise the region labels into
588 * order, meaning that indistinguishable maps are actually
589 * identical.
590 */
591 for (i = 0; i < n; i++)
592 tmp[i] = -1;
593 k = 0;
594 for (i = 0; i < wh; i++) {
595 assert(map[i] >= 0);
596 if (tmp[map[i]] < 0)
597 tmp[map[i]] = k++;
598 map[i] = tmp[map[i]];
599 }
600
601 sfree(tmp);
602}
603
604/* ----------------------------------------------------------------------
605 * Functions to handle graphs.
606 */
607
608/*
609 * Having got a map in a square grid, convert it into a graph
610 * representation.
611 */
612static int gengraph(int w, int h, int n, int *map, int *graph)
613{
614 int i, j, x, y;
615
616 /*
617 * Start by setting the graph up as an adjacency matrix. We'll
618 * turn it into a list later.
619 */
620 for (i = 0; i < n*n; i++)
621 graph[i] = 0;
622
623 /*
624 * Iterate over the map looking for all adjacencies.
625 */
626 for (y = 0; y < h; y++)
627 for (x = 0; x < w; x++) {
628 int v, vx, vy;
629 v = map[y*w+x];
630 if (x+1 < w && (vx = map[y*w+(x+1)]) != v)
631 graph[v*n+vx] = graph[vx*n+v] = 1;
632 if (y+1 < h && (vy = map[(y+1)*w+x]) != v)
633 graph[v*n+vy] = graph[vy*n+v] = 1;
634 }
635
636 /*
637 * Turn the matrix into a list.
638 */
639 for (i = j = 0; i < n*n; i++)
640 if (graph[i])
641 graph[j++] = i;
642
643 return j;
644}
645
646static int graph_edge_index(int *graph, int n, int ngraph, int i, int j)
647{
648 int v = i*n+j;
649 int top, bot, mid;
650
651 bot = -1;
652 top = ngraph;
653 while (top - bot > 1) {
654 mid = (top + bot) / 2;
655 if (graph[mid] == v)
656 return mid;
657 else if (graph[mid] < v)
658 bot = mid;
659 else
660 top = mid;
661 }
662 return -1;
663}
664
665#define graph_adjacent(graph, n, ngraph, i, j) \
666 (graph_edge_index((graph), (n), (ngraph), (i), (j)) >= 0)
667
668static int graph_vertex_start(int *graph, int n, int ngraph, int i)
669{
670 int v = i*n;
671 int top, bot, mid;
672
673 bot = -1;
674 top = ngraph;
675 while (top - bot > 1) {
676 mid = (top + bot) / 2;
677 if (graph[mid] < v)
678 bot = mid;
679 else
680 top = mid;
681 }
682 return top;
683}
684
685/* ----------------------------------------------------------------------
686 * Generate a four-colouring of a graph.
687 *
688 * FIXME: it would be nice if we could convert this recursion into
689 * pseudo-recursion using some sort of explicit stack array, for
690 * the sake of the Palm port and its limited stack.
691 */
692
693static bool fourcolour_recurse(int *graph, int n, int ngraph,
694 int *colouring, int *scratch, random_state *rs)
695{
696 int nfree, nvert, start, i, j, k, c, ci;
697 int cs[FOUR];
698
699 /*
700 * Find the smallest number of free colours in any uncoloured
701 * vertex, and count the number of such vertices.
702 */
703
704 nfree = FIVE; /* start off bigger than FOUR! */
705 nvert = 0;
706 for (i = 0; i < n; i++)
707 if (colouring[i] < 0 && scratch[i*FIVE+FOUR] <= nfree) {
708 if (nfree > scratch[i*FIVE+FOUR]) {
709 nfree = scratch[i*FIVE+FOUR];
710 nvert = 0;
711 }
712 nvert++;
713 }
714
715 /*
716 * If there aren't any uncoloured vertices at all, we're done.
717 */
718 if (nvert == 0)
719 return true; /* we've got a colouring! */
720
721 /*
722 * Pick a random vertex in that set.
723 */
724 j = random_upto(rs, nvert);
725 for (i = 0; i < n; i++)
726 if (colouring[i] < 0 && scratch[i*FIVE+FOUR] == nfree)
727 if (j-- == 0)
728 break;
729 assert(i < n);
730 start = graph_vertex_start(graph, n, ngraph, i);
731
732 /*
733 * Loop over the possible colours for i, and recurse for each
734 * one.
735 */
736 ci = 0;
737 for (c = 0; c < FOUR; c++)
738 if (scratch[i*FIVE+c] == 0)
739 cs[ci++] = c;
740 shuffle(cs, ci, sizeof(*cs), rs);
741
742 while (ci-- > 0) {
743 c = cs[ci];
744
745 /*
746 * Fill in this colour.
747 */
748 colouring[i] = c;
749
750 /*
751 * Update the scratch space to reflect a new neighbour
752 * of this colour for each neighbour of vertex i.
753 */
754 for (j = start; j < ngraph && graph[j] < n*(i+1); j++) {
755 k = graph[j] - i*n;
756 if (scratch[k*FIVE+c] == 0)
757 scratch[k*FIVE+FOUR]--;
758 scratch[k*FIVE+c]++;
759 }
760
761 /*
762 * Recurse.
763 */
764 if (fourcolour_recurse(graph, n, ngraph, colouring, scratch, rs))
765 return true; /* got one! */
766
767 /*
768 * If that didn't work, clean up and try again with a
769 * different colour.
770 */
771 for (j = start; j < ngraph && graph[j] < n*(i+1); j++) {
772 k = graph[j] - i*n;
773 scratch[k*FIVE+c]--;
774 if (scratch[k*FIVE+c] == 0)
775 scratch[k*FIVE+FOUR]++;
776 }
777 colouring[i] = -1;
778 }
779
780 /*
781 * If we reach here, we were unable to find a colouring at all.
782 * (This doesn't necessarily mean the Four Colour Theorem is
783 * violated; it might just mean we've gone down a dead end and
784 * need to back up and look somewhere else. It's only an FCT
785 * violation if we get all the way back up to the top level and
786 * still fail.)
787 */
788 return false;
789}
790
791static void fourcolour(int *graph, int n, int ngraph, int *colouring,
792 random_state *rs)
793{
794 int *scratch;
795 int i;
796 bool retd;
797
798 /*
799 * For each vertex and each colour, we store the number of
800 * neighbours that have that colour. Also, we store the number
801 * of free colours for the vertex.
802 */
803 scratch = snewn(n * FIVE, int);
804 for (i = 0; i < n * FIVE; i++)
805 scratch[i] = (i % FIVE == FOUR ? FOUR : 0);
806
807 /*
808 * Clear the colouring to start with.
809 */
810 for (i = 0; i < n; i++)
811 colouring[i] = -1;
812
813 retd = fourcolour_recurse(graph, n, ngraph, colouring, scratch, rs);
814 assert(retd); /* by the Four Colour Theorem :-) */
815
816 sfree(scratch);
817}
818
819/* ----------------------------------------------------------------------
820 * Non-recursive solver.
821 */
822
823struct solver_scratch {
824 unsigned char *possible; /* bitmap of colours for each region */
825
826 int *graph;
827 int n;
828 int ngraph;
829
830 int *bfsqueue;
831 int *bfscolour;
832#ifdef SOLVER_DIAGNOSTICS
833 int *bfsprev;
834#endif
835
836 int depth;
837};
838
839static struct solver_scratch *new_scratch(int *graph, int n, int ngraph)
840{
841 struct solver_scratch *sc;
842
843 sc = snew(struct solver_scratch);
844 sc->graph = graph;
845 sc->n = n;
846 sc->ngraph = ngraph;
847 sc->possible = snewn(n, unsigned char);
848 sc->depth = 0;
849 sc->bfsqueue = snewn(n, int);
850 sc->bfscolour = snewn(n, int);
851#ifdef SOLVER_DIAGNOSTICS
852 sc->bfsprev = snewn(n, int);
853#endif
854
855 return sc;
856}
857
858static void free_scratch(struct solver_scratch *sc)
859{
860 sfree(sc->possible);
861 sfree(sc->bfsqueue);
862 sfree(sc->bfscolour);
863#ifdef SOLVER_DIAGNOSTICS
864 sfree(sc->bfsprev);
865#endif
866 sfree(sc);
867}
868
869/*
870 * Count the bits in a word. Only needs to cope with FOUR bits.
871 */
872static int bitcount(int word)
873{
874 assert(FOUR <= 4); /* or this needs changing */
875 word = ((word & 0xA) >> 1) + (word & 0x5);
876 word = ((word & 0xC) >> 2) + (word & 0x3);
877 return word;
878}
879
880#ifdef SOLVER_DIAGNOSTICS
881static const char colnames[FOUR] = { 'R', 'Y', 'G', 'B' };
882#endif
883
884static bool place_colour(struct solver_scratch *sc,
885 int *colouring, int index, int colour
886#ifdef SOLVER_DIAGNOSTICS
887 , const char *verb
888#endif
889 )
890{
891 int *graph = sc->graph, n = sc->n, ngraph = sc->ngraph;
892 int j, k;
893
894 if (!(sc->possible[index] & (1 << colour))) {
895#ifdef SOLVER_DIAGNOSTICS
896 if (verbose)
897 printf("%*scannot place %c in region %d\n", 2*sc->depth, "",
898 colnames[colour], index);
899#endif
900 return false; /* can't do it */
901 }
902
903 sc->possible[index] = 1 << colour;
904 colouring[index] = colour;
905
906#ifdef SOLVER_DIAGNOSTICS
907 if (verbose)
908 printf("%*s%s %c in region %d\n", 2*sc->depth, "",
909 verb, colnames[colour], index);
910#endif
911
912 /*
913 * Rule out this colour from all the region's neighbours.
914 */
915 for (j = graph_vertex_start(graph, n, ngraph, index);
916 j < ngraph && graph[j] < n*(index+1); j++) {
917 k = graph[j] - index*n;
918#ifdef SOLVER_DIAGNOSTICS
919 if (verbose && (sc->possible[k] & (1 << colour)))
920 printf("%*s ruling out %c in region %d\n", 2*sc->depth, "",
921 colnames[colour], k);
922#endif
923 sc->possible[k] &= ~(1 << colour);
924 }
925
926 return true;
927}
928
929#ifdef SOLVER_DIAGNOSTICS
930static char *colourset(char *buf, int set)
931{
932 int i;
933 char *p = buf;
934 const char *sep = "";
935
936 for (i = 0; i < FOUR; i++)
937 if (set & (1 << i)) {
938 p += sprintf(p, "%s%c", sep, colnames[i]);
939 sep = ",";
940 }
941
942 return buf;
943}
944#endif
945
946/*
947 * Returns 0 for impossible, 1 for success, 2 for failure to
948 * converge (i.e. puzzle is either ambiguous or just too
949 * difficult).
950 */
951static int map_solver(struct solver_scratch *sc,
952 int *graph, int n, int ngraph, int *colouring,
953 int difficulty)
954{
955 int i;
956
957 if (sc->depth == 0) {
958 /*
959 * Initialise scratch space.
960 */
961 for (i = 0; i < n; i++)
962 sc->possible[i] = (1 << FOUR) - 1;
963
964 /*
965 * Place clues.
966 */
967 for (i = 0; i < n; i++)
968 if (colouring[i] >= 0) {
969 if (!place_colour(sc, colouring, i, colouring[i]
970#ifdef SOLVER_DIAGNOSTICS
971 , "initial clue:"
972#endif
973 )) {
974#ifdef SOLVER_DIAGNOSTICS
975 if (verbose)
976 printf("%*sinitial clue set is inconsistent\n",
977 2*sc->depth, "");
978#endif
979 return 0; /* the clues aren't even consistent! */
980 }
981 }
982 }
983
984 /*
985 * Now repeatedly loop until we find nothing further to do.
986 */
987 while (1) {
988 bool done_something = false;
989
990 if (difficulty < DIFF_EASY)
991 break; /* can't do anything at all! */
992
993 /*
994 * Simplest possible deduction: find a region with only one
995 * possible colour.
996 */
997 for (i = 0; i < n; i++) if (colouring[i] < 0) {
998 int p = sc->possible[i];
999
1000 if (p == 0) {
1001#ifdef SOLVER_DIAGNOSTICS
1002 if (verbose)
1003 printf("%*sregion %d has no possible colours left\n",
1004 2*sc->depth, "", i);
1005#endif
1006 return 0; /* puzzle is inconsistent */
1007 }
1008
1009 if ((p & (p-1)) == 0) { /* p is a power of two */
1010 int c;
1011 bool ret;
1012 for (c = 0; c < FOUR; c++)
1013 if (p == (1 << c))
1014 break;
1015 assert(c < FOUR);
1016 ret = place_colour(sc, colouring, i, c
1017#ifdef SOLVER_DIAGNOSTICS
1018 , "placing"
1019#endif
1020 );
1021 /*
1022 * place_colour() can only fail if colour c was not
1023 * even a _possibility_ for region i, and we're
1024 * pretty sure it was because we checked before
1025 * calling place_colour(). So we can safely assert
1026 * here rather than having to return a nice
1027 * friendly error code.
1028 */
1029 assert(ret);
1030 done_something = true;
1031 }
1032 }
1033
1034 if (done_something)
1035 continue;
1036
1037 if (difficulty < DIFF_NORMAL)
1038 break; /* can't do anything harder */
1039
1040 /*
1041 * Failing that, go up one level. Look for pairs of regions
1042 * which (a) both have the same pair of possible colours,
1043 * (b) are adjacent to one another, (c) are adjacent to the
1044 * same region, and (d) that region still thinks it has one
1045 * or both of those possible colours.
1046 *
1047 * Simplest way to do this is by going through the graph
1048 * edge by edge, so that we start with property (b) and
1049 * then look for (a) and finally (c) and (d).
1050 */
1051 for (i = 0; i < ngraph; i++) {
1052 int j1 = graph[i] / n, j2 = graph[i] % n;
1053 int j, k, v, v2;
1054#ifdef SOLVER_DIAGNOSTICS
1055 bool started = false;
1056#endif
1057
1058 if (j1 > j2)
1059 continue; /* done it already, other way round */
1060
1061 if (colouring[j1] >= 0 || colouring[j2] >= 0)
1062 continue; /* they're not undecided */
1063
1064 if (sc->possible[j1] != sc->possible[j2])
1065 continue; /* they don't have the same possibles */
1066
1067 v = sc->possible[j1];
1068 /*
1069 * See if v contains exactly two set bits.
1070 */
1071 v2 = v & -v; /* find lowest set bit */
1072 v2 = v & ~v2; /* clear it */
1073 if (v2 == 0 || (v2 & (v2-1)) != 0) /* not power of 2 */
1074 continue;
1075
1076 /*
1077 * We've found regions j1 and j2 satisfying properties
1078 * (a) and (b): they have two possible colours between
1079 * them, and since they're adjacent to one another they
1080 * must use _both_ those colours between them.
1081 * Therefore, if they are both adjacent to any other
1082 * region then that region cannot be either colour.
1083 *
1084 * Go through the neighbours of j1 and see if any are
1085 * shared with j2.
1086 */
1087 for (j = graph_vertex_start(graph, n, ngraph, j1);
1088 j < ngraph && graph[j] < n*(j1+1); j++) {
1089 k = graph[j] - j1*n;
1090 if (graph_adjacent(graph, n, ngraph, k, j2) &&
1091 (sc->possible[k] & v)) {
1092#ifdef SOLVER_DIAGNOSTICS
1093 if (verbose) {
1094 char buf[80];
1095 if (!started)
1096 printf("%*sadjacent regions %d,%d share colours"
1097 " %s\n", 2*sc->depth, "", j1, j2,
1098 colourset(buf, v));
1099 started = true;
1100 printf("%*s ruling out %s in region %d\n",2*sc->depth,
1101 "", colourset(buf, sc->possible[k] & v), k);
1102 }
1103#endif
1104 sc->possible[k] &= ~v;
1105 done_something = true;
1106 }
1107 }
1108 }
1109
1110 if (done_something)
1111 continue;
1112
1113 if (difficulty < DIFF_HARD)
1114 break; /* can't do anything harder */
1115
1116 /*
1117 * Right; now we get creative. Now we're going to look for
1118 * `forcing chains'. A forcing chain is a path through the
1119 * graph with the following properties:
1120 *
1121 * (a) Each vertex on the path has precisely two possible
1122 * colours.
1123 *
1124 * (b) Each pair of vertices which are adjacent on the
1125 * path share at least one possible colour in common.
1126 *
1127 * (c) Each vertex in the middle of the path shares _both_
1128 * of its colours with at least one of its neighbours
1129 * (not the same one with both neighbours).
1130 *
1131 * These together imply that at least one of the possible
1132 * colour choices at one end of the path forces _all_ the
1133 * rest of the colours along the path. In order to make
1134 * real use of this, we need further properties:
1135 *
1136 * (c) Ruling out some colour C from the vertex at one end
1137 * of the path forces the vertex at the other end to
1138 * take colour C.
1139 *
1140 * (d) The two end vertices are mutually adjacent to some
1141 * third vertex.
1142 *
1143 * (e) That third vertex currently has C as a possibility.
1144 *
1145 * If we can find all of that lot, we can deduce that at
1146 * least one of the two ends of the forcing chain has
1147 * colour C, and that therefore the mutually adjacent third
1148 * vertex does not.
1149 *
1150 * To find forcing chains, we're going to start a bfs at
1151 * each suitable vertex of the graph, once for each of its
1152 * two possible colours.
1153 */
1154 for (i = 0; i < n; i++) {
1155 int c;
1156
1157 if (colouring[i] >= 0 || bitcount(sc->possible[i]) != 2)
1158 continue;
1159
1160 for (c = 0; c < FOUR; c++)
1161 if (sc->possible[i] & (1 << c)) {
1162 int j, k, gi, origc, currc, head, tail;
1163 /*
1164 * Try a bfs from this vertex, ruling out
1165 * colour c.
1166 *
1167 * Within this loop, we work in colour bitmaps
1168 * rather than actual colours, because
1169 * converting back and forth is a needless
1170 * computational expense.
1171 */
1172
1173 origc = 1 << c;
1174
1175 for (j = 0; j < n; j++) {
1176 sc->bfscolour[j] = -1;
1177#ifdef SOLVER_DIAGNOSTICS
1178 sc->bfsprev[j] = -1;
1179#endif
1180 }
1181 head = tail = 0;
1182 sc->bfsqueue[tail++] = i;
1183 sc->bfscolour[i] = sc->possible[i] &~ origc;
1184
1185 while (head < tail) {
1186 j = sc->bfsqueue[head++];
1187 currc = sc->bfscolour[j];
1188
1189 /*
1190 * Try neighbours of j.
1191 */
1192 for (gi = graph_vertex_start(graph, n, ngraph, j);
1193 gi < ngraph && graph[gi] < n*(j+1); gi++) {
1194 k = graph[gi] - j*n;
1195
1196 /*
1197 * To continue with the bfs in vertex
1198 * k, we need k to be
1199 * (a) not already visited
1200 * (b) have two possible colours
1201 * (c) those colours include currc.
1202 */
1203
1204 if (sc->bfscolour[k] < 0 &&
1205 colouring[k] < 0 &&
1206 bitcount(sc->possible[k]) == 2 &&
1207 (sc->possible[k] & currc)) {
1208 sc->bfsqueue[tail++] = k;
1209 sc->bfscolour[k] =
1210 sc->possible[k] &~ currc;
1211#ifdef SOLVER_DIAGNOSTICS
1212 sc->bfsprev[k] = j;
1213#endif
1214 }
1215
1216 /*
1217 * One other possibility is that k
1218 * might be the region in which we can
1219 * make a real deduction: if it's
1220 * adjacent to i, contains currc as a
1221 * possibility, and currc is equal to
1222 * the original colour we ruled out.
1223 */
1224 if (currc == origc &&
1225 graph_adjacent(graph, n, ngraph, k, i) &&
1226 (sc->possible[k] & currc)) {
1227#ifdef SOLVER_DIAGNOSTICS
1228 if (verbose) {
1229 char buf[80];
1230 const char *sep = "";
1231 int r;
1232
1233 printf("%*sforcing chain, colour %s, ",
1234 2*sc->depth, "",
1235 colourset(buf, origc));
1236 for (r = j; r != -1; r = sc->bfsprev[r]) {
1237 printf("%s%d", sep, r);
1238 sep = "-";
1239 }
1240 printf("\n%*s ruling out %s in region"
1241 " %d\n", 2*sc->depth, "",
1242 colourset(buf, origc), k);
1243 }
1244#endif
1245 sc->possible[k] &= ~origc;
1246 done_something = true;
1247 }
1248 }
1249 }
1250
1251 assert(tail <= n);
1252 }
1253 }
1254
1255 if (!done_something)
1256 break;
1257 }
1258
1259 /*
1260 * See if we've got a complete solution, and return if so.
1261 */
1262 for (i = 0; i < n; i++)
1263 if (colouring[i] < 0)
1264 break;
1265 if (i == n) {
1266#ifdef SOLVER_DIAGNOSTICS
1267 if (verbose)
1268 printf("%*sone solution found\n", 2*sc->depth, "");
1269#endif
1270 return 1; /* success! */
1271 }
1272
1273 /*
1274 * If recursion is not permissible, we now give up.
1275 */
1276 if (difficulty < DIFF_RECURSE) {
1277#ifdef SOLVER_DIAGNOSTICS
1278 if (verbose)
1279 printf("%*sunable to proceed further without recursion\n",
1280 2*sc->depth, "");
1281#endif
1282 return 2; /* unable to complete */
1283 }
1284
1285 /*
1286 * Now we've got to do something recursive. So first hunt for a
1287 * currently-most-constrained region.
1288 */
1289 {
1290 int best, bestc;
1291 struct solver_scratch *rsc;
1292 int *subcolouring, *origcolouring;
1293 int ret, subret;
1294 bool we_already_got_one;
1295
1296 best = -1;
1297 bestc = FIVE;
1298
1299 for (i = 0; i < n; i++) if (colouring[i] < 0) {
1300 int p = sc->possible[i];
1301 enum { compile_time_assertion = 1 / (FOUR <= 4) };
1302 int c;
1303
1304 /* Count the set bits. */
1305 c = (p & 5) + ((p >> 1) & 5);
1306 c = (c & 3) + ((c >> 2) & 3);
1307 assert(c > 1); /* or colouring[i] would be >= 0 */
1308
1309 if (c < bestc) {
1310 best = i;
1311 bestc = c;
1312 }
1313 }
1314
1315 assert(best >= 0); /* or we'd be solved already */
1316
1317#ifdef SOLVER_DIAGNOSTICS
1318 if (verbose)
1319 printf("%*srecursing on region %d\n", 2*sc->depth, "", best);
1320#endif
1321
1322 /*
1323 * Now iterate over the possible colours for this region.
1324 */
1325 rsc = new_scratch(graph, n, ngraph);
1326 rsc->depth = sc->depth + 1;
1327 origcolouring = snewn(n, int);
1328 memcpy(origcolouring, colouring, n * sizeof(int));
1329 subcolouring = snewn(n, int);
1330 we_already_got_one = false;
1331 ret = 0;
1332
1333 for (i = 0; i < FOUR; i++) {
1334 if (!(sc->possible[best] & (1 << i)))
1335 continue;
1336
1337 memcpy(rsc->possible, sc->possible, n);
1338 memcpy(subcolouring, origcolouring, n * sizeof(int));
1339
1340 place_colour(rsc, subcolouring, best, i
1341#ifdef SOLVER_DIAGNOSTICS
1342 , "trying"
1343#endif
1344 );
1345
1346 subret = map_solver(rsc, graph, n, ngraph,
1347 subcolouring, difficulty);
1348
1349#ifdef SOLVER_DIAGNOSTICS
1350 if (verbose) {
1351 printf("%*sretracting %c in region %d; found %s\n",
1352 2*sc->depth, "", colnames[i], best,
1353 subret == 0 ? "no solutions" :
1354 subret == 1 ? "one solution" : "multiple solutions");
1355 }
1356#endif
1357
1358 /*
1359 * If this possibility turned up more than one valid
1360 * solution, or if it turned up one and we already had
1361 * one, we're definitely ambiguous.
1362 */
1363 if (subret == 2 || (subret == 1 && we_already_got_one)) {
1364 ret = 2;
1365 break;
1366 }
1367
1368 /*
1369 * If this possibility turned up one valid solution and
1370 * it's the first we've seen, copy it into the output.
1371 */
1372 if (subret == 1) {
1373 memcpy(colouring, subcolouring, n * sizeof(int));
1374 we_already_got_one = true;
1375 ret = 1;
1376 }
1377
1378 /*
1379 * Otherwise, this guess led to a contradiction, so we
1380 * do nothing.
1381 */
1382 }
1383
1384 sfree(origcolouring);
1385 sfree(subcolouring);
1386 free_scratch(rsc);
1387
1388#ifdef SOLVER_DIAGNOSTICS
1389 if (verbose && sc->depth == 0) {
1390 printf("%*s%s found\n",
1391 2*sc->depth, "",
1392 ret == 0 ? "no solutions" :
1393 ret == 1 ? "one solution" : "multiple solutions");
1394 }
1395#endif
1396 return ret;
1397 }
1398}
1399
1400/* ----------------------------------------------------------------------
1401 * Game generation main function.
1402 */
1403
1404static char *new_game_desc(const game_params *params, random_state *rs,
1405 char **aux, bool interactive)
1406{
1407 struct solver_scratch *sc = NULL;
1408 int *map, *graph, ngraph, *colouring, *colouring2, *regions;
1409 int i, j, w, h, n, solveret, cfreq[FOUR];
1410 int wh;
1411 int mindiff, tries;
1412#ifdef GENERATION_DIAGNOSTICS
1413 int x, y;
1414#endif
1415 char *ret, buf[80];
1416 int retlen, retsize;
1417
1418 w = params->w;
1419 h = params->h;
1420 n = params->n;
1421 wh = w*h;
1422
1423 *aux = NULL;
1424
1425 map = snewn(wh, int);
1426 graph = snewn(n*n, int);
1427 colouring = snewn(n, int);
1428 colouring2 = snewn(n, int);
1429 regions = snewn(n, int);
1430
1431 /*
1432 * This is the minimum difficulty below which we'll completely
1433 * reject a map design. Normally we set this to one below the
1434 * requested difficulty, ensuring that we have the right
1435 * result. However, for particularly dense maps or maps with
1436 * particularly few regions it might not be possible to get the
1437 * desired difficulty, so we will eventually drop this down to
1438 * -1 to indicate that any old map will do.
1439 */
1440 mindiff = params->diff;
1441 tries = 50;
1442
1443 while (1) {
1444
1445 /*
1446 * Create the map.
1447 */
1448 genmap(w, h, n, map, rs);
1449
1450#ifdef GENERATION_DIAGNOSTICS
1451 for (y = 0; y < h; y++) {
1452 for (x = 0; x < w; x++) {
1453 int v = map[y*w+x];
1454 if (v >= 62)
1455 putchar('!');
1456 else if (v >= 36)
1457 putchar('a' + v-36);
1458 else if (v >= 10)
1459 putchar('A' + v-10);
1460 else
1461 putchar('0' + v);
1462 }
1463 putchar('\n');
1464 }
1465#endif
1466
1467 /*
1468 * Convert the map into a graph.
1469 */
1470 ngraph = gengraph(w, h, n, map, graph);
1471
1472#ifdef GENERATION_DIAGNOSTICS
1473 for (i = 0; i < ngraph; i++)
1474 printf("%d-%d\n", graph[i]/n, graph[i]%n);
1475#endif
1476
1477 /*
1478 * Colour the map.
1479 */
1480 fourcolour(graph, n, ngraph, colouring, rs);
1481
1482#ifdef GENERATION_DIAGNOSTICS
1483 for (i = 0; i < n; i++)
1484 printf("%d: %d\n", i, colouring[i]);
1485
1486 for (y = 0; y < h; y++) {
1487 for (x = 0; x < w; x++) {
1488 int v = colouring[map[y*w+x]];
1489 if (v >= 36)
1490 putchar('a' + v-36);
1491 else if (v >= 10)
1492 putchar('A' + v-10);
1493 else
1494 putchar('0' + v);
1495 }
1496 putchar('\n');
1497 }
1498#endif
1499
1500 /*
1501 * Encode the solution as an aux string.
1502 */
1503 if (*aux) /* in case we've come round again */
1504 sfree(*aux);
1505 retlen = retsize = 0;
1506 ret = NULL;
1507 for (i = 0; i < n; i++) {
1508 int len;
1509
1510 if (colouring[i] < 0)
1511 continue;
1512
1513 len = sprintf(buf, "%s%d:%d", i ? ";" : "S;", colouring[i], i);
1514 if (retlen + len >= retsize) {
1515 retsize = retlen + len + 256;
1516 ret = sresize(ret, retsize, char);
1517 }
1518 strcpy(ret + retlen, buf);
1519 retlen += len;
1520 }
1521 *aux = ret;
1522
1523 /*
1524 * Remove the region colours one by one, keeping
1525 * solubility. Also ensure that there always remains at
1526 * least one region of every colour, so that the user can
1527 * drag from somewhere.
1528 */
1529 for (i = 0; i < FOUR; i++)
1530 cfreq[i] = 0;
1531 for (i = 0; i < n; i++) {
1532 regions[i] = i;
1533 cfreq[colouring[i]]++;
1534 }
1535 for (i = 0; i < FOUR; i++)
1536 if (cfreq[i] == 0)
1537 continue;
1538
1539 shuffle(regions, n, sizeof(*regions), rs);
1540
1541 if (sc) free_scratch(sc);
1542 sc = new_scratch(graph, n, ngraph);
1543
1544 for (i = 0; i < n; i++) {
1545 j = regions[i];
1546
1547 if (cfreq[colouring[j]] == 1)
1548 continue; /* can't remove last region of colour */
1549
1550 memcpy(colouring2, colouring, n*sizeof(int));
1551 colouring2[j] = -1;
1552 solveret = map_solver(sc, graph, n, ngraph, colouring2,
1553 params->diff);
1554 assert(solveret >= 0); /* mustn't be impossible! */
1555 if (solveret == 1) {
1556 cfreq[colouring[j]]--;
1557 colouring[j] = -1;
1558 }
1559 }
1560
1561#ifdef GENERATION_DIAGNOSTICS
1562 for (i = 0; i < n; i++)
1563 if (colouring[i] >= 0) {
1564 if (i >= 62)
1565 putchar('!');
1566 else if (i >= 36)
1567 putchar('a' + i-36);
1568 else if (i >= 10)
1569 putchar('A' + i-10);
1570 else
1571 putchar('0' + i);
1572 printf(": %d\n", colouring[i]);
1573 }
1574#endif
1575
1576 /*
1577 * Finally, check that the puzzle is _at least_ as hard as
1578 * required, and indeed that it isn't already solved.
1579 * (Calling map_solver with negative difficulty ensures the
1580 * latter - if a solver which _does nothing_ can solve it,
1581 * it's too easy!)
1582 */
1583 memcpy(colouring2, colouring, n*sizeof(int));
1584 if (map_solver(sc, graph, n, ngraph, colouring2,
1585 mindiff - 1) == 1) {
1586 /*
1587 * Drop minimum difficulty if necessary.
1588 */
1589 if (mindiff > 0 && (n < 9 || n > 2*wh/3)) {
1590 if (tries-- <= 0)
1591 mindiff = 0; /* give up and go for Easy */
1592 }
1593 continue;
1594 }
1595
1596 break;
1597 }
1598
1599 /*
1600 * Encode as a game ID. We do this by:
1601 *
1602 * - first going along the horizontal edges row by row, and
1603 * then the vertical edges column by column
1604 * - encoding the lengths of runs of edges and runs of
1605 * non-edges
1606 * - the decoder will reconstitute the region boundaries from
1607 * this and automatically number them the same way we did
1608 * - then we encode the initial region colours in a Slant-like
1609 * fashion (digits 0-3 interspersed with letters giving
1610 * lengths of runs of empty spaces).
1611 */
1612 retlen = retsize = 0;
1613 ret = NULL;
1614
1615 {
1616 int run;
1617 bool pv;
1618
1619 /*
1620 * Start with a notional non-edge, so that there'll be an
1621 * explicit `a' to distinguish the case where we start with
1622 * an edge.
1623 */
1624 run = 1;
1625 pv = false;
1626
1627 for (i = 0; i < w*(h-1) + (w-1)*h; i++) {
1628 int x, y, dx, dy;
1629 bool v;
1630
1631 if (i < w*(h-1)) {
1632 /* Horizontal edge. */
1633 y = i / w;
1634 x = i % w;
1635 dx = 0;
1636 dy = 1;
1637 } else {
1638 /* Vertical edge. */
1639 x = (i - w*(h-1)) / h;
1640 y = (i - w*(h-1)) % h;
1641 dx = 1;
1642 dy = 0;
1643 }
1644
1645 if (retlen + 10 >= retsize) {
1646 retsize = retlen + 256;
1647 ret = sresize(ret, retsize, char);
1648 }
1649
1650 v = (map[y*w+x] != map[(y+dy)*w+(x+dx)]);
1651
1652 if (pv != v) {
1653 ret[retlen++] = 'a'-1 + run;
1654 run = 1;
1655 pv = v;
1656 } else {
1657 /*
1658 * 'z' is a special case in this encoding. Rather
1659 * than meaning a run of 26 and a state switch, it
1660 * means a run of 25 and _no_ state switch, because
1661 * otherwise there'd be no way to encode runs of
1662 * more than 26.
1663 */
1664 if (run == 25) {
1665 ret[retlen++] = 'z';
1666 run = 0;
1667 }
1668 run++;
1669 }
1670 }
1671
1672 if (retlen + 10 >= retsize) {
1673 retsize = retlen + 256;
1674 ret = sresize(ret, retsize, char);
1675 }
1676 ret[retlen++] = 'a'-1 + run;
1677 ret[retlen++] = ',';
1678
1679 run = 0;
1680 for (i = 0; i < n; i++) {
1681 if (retlen + 10 >= retsize) {
1682 retsize = retlen + 256;
1683 ret = sresize(ret, retsize, char);
1684 }
1685
1686 if (colouring[i] < 0) {
1687 /*
1688 * In _this_ encoding, 'z' is a run of 26, since
1689 * there's no implicit state switch after each run.
1690 * Confusingly different, but more compact.
1691 */
1692 if (run == 26) {
1693 ret[retlen++] = 'z';
1694 run = 0;
1695 }
1696 run++;
1697 } else {
1698 if (run > 0)
1699 ret[retlen++] = 'a'-1 + run;
1700 ret[retlen++] = '0' + colouring[i];
1701 run = 0;
1702 }
1703 }
1704 if (run > 0)
1705 ret[retlen++] = 'a'-1 + run;
1706 ret[retlen] = '\0';
1707
1708 assert(retlen < retsize);
1709 }
1710
1711 free_scratch(sc);
1712 sfree(regions);
1713 sfree(colouring2);
1714 sfree(colouring);
1715 sfree(graph);
1716 sfree(map);
1717
1718 return ret;
1719}
1720
1721static const char *parse_edge_list(const game_params *params,
1722 const char **desc, int *map)
1723{
1724 int w = params->w, h = params->h, wh = w*h, n = params->n;
1725 int i, k, pos;
1726 bool state;
1727 const char *p = *desc;
1728 const char *err = NULL;
1729 DSF *dsf = dsf_new(wh);
1730
1731 pos = -1;
1732 state = false;
1733
1734 /*
1735 * Parse the game description to get the list of edges, and
1736 * build up a disjoint set forest as we go (by identifying
1737 * pairs of squares whenever the edge list shows a non-edge).
1738 */
1739 while (*p && *p != ',') {
1740 if (*p < 'a' || *p > 'z') {
1741 err = "Unexpected character in edge list";
1742 goto out;
1743 }
1744 if (*p == 'z')
1745 k = 25;
1746 else
1747 k = *p - 'a' + 1;
1748 while (k-- > 0) {
1749 int x, y, dx, dy;
1750
1751 if (pos < 0) {
1752 pos++;
1753 continue;
1754 } else if (pos < w*(h-1)) {
1755 /* Horizontal edge. */
1756 y = pos / w;
1757 x = pos % w;
1758 dx = 0;
1759 dy = 1;
1760 } else if (pos < 2*wh-w-h) {
1761 /* Vertical edge. */
1762 x = (pos - w*(h-1)) / h;
1763 y = (pos - w*(h-1)) % h;
1764 dx = 1;
1765 dy = 0;
1766 } else {
1767 err = "Too much data in edge list";
1768 goto out;
1769 }
1770 if (!state)
1771 dsf_merge(dsf, y*w+x, (y+dy)*w+(x+dx));
1772
1773 pos++;
1774 }
1775 if (*p != 'z')
1776 state = !state;
1777 p++;
1778 }
1779 assert(pos <= 2*wh-w-h);
1780 if (pos < 2*wh-w-h) {
1781 err = "Too little data in edge list";
1782 goto out;
1783 }
1784
1785 /*
1786 * Now go through again and allocate region numbers.
1787 */
1788 pos = 0;
1789 for (i = 0; i < wh; i++)
1790 map[i] = -1;
1791 for (i = 0; i < wh; i++) {
1792 k = dsf_canonify(dsf, i);
1793 if (map[k] < 0)
1794 map[k] = pos++;
1795 map[i] = map[k];
1796 }
1797 if (pos != n) {
1798 err = "Edge list defines the wrong number of regions";
1799 goto out;
1800 }
1801
1802 *desc = p;
1803 err = NULL; /* no error */
1804
1805 out:
1806 dsf_free(dsf);
1807 return err;
1808}
1809
1810static const char *validate_desc(const game_params *params, const char *desc)
1811{
1812 int w = params->w, h = params->h, wh = w*h, n = params->n;
1813 int area;
1814 int *map;
1815 const char *ret;
1816
1817 map = snewn(wh, int);
1818 ret = parse_edge_list(params, &desc, map);
1819 sfree(map);
1820 if (ret)
1821 return ret;
1822
1823 if (*desc != ',')
1824 return "Expected comma before clue list";
1825 desc++; /* eat comma */
1826
1827 area = 0;
1828 while (*desc) {
1829 if (*desc >= '0' && *desc < '0'+FOUR)
1830 area++;
1831 else if (*desc >= 'a' && *desc <= 'z')
1832 area += *desc - 'a' + 1;
1833 else
1834 return "Unexpected character in clue list";
1835 desc++;
1836 }
1837 if (area < n)
1838 return "Too little data in clue list";
1839 else if (area > n)
1840 return "Too much data in clue list";
1841
1842 return NULL;
1843}
1844
1845static game_state *new_game(midend *me, const game_params *params,
1846 const char *desc)
1847{
1848 int w = params->w, h = params->h, wh = w*h, n = params->n;
1849 int i, pos;
1850 const char *p;
1851 game_state *state = snew(game_state);
1852
1853 state->p = *params;
1854 state->colouring = snewn(n, int);
1855 for (i = 0; i < n; i++)
1856 state->colouring[i] = -1;
1857 state->pencil = snewn(n, int);
1858 for (i = 0; i < n; i++)
1859 state->pencil[i] = 0;
1860
1861 state->completed = false;
1862 state->cheated = false;
1863
1864 state->map = snew(struct map);
1865 state->map->refcount = 1;
1866 state->map->map = snewn(wh*4, int);
1867 state->map->graph = snewn(n*n, int);
1868 state->map->n = n;
1869 state->map->immutable = snewn(n, bool);
1870 for (i = 0; i < n; i++)
1871 state->map->immutable[i] = false;
1872
1873 p = desc;
1874
1875 {
1876 const char *ret;
1877 ret = parse_edge_list(params, &p, state->map->map);
1878 assert(!ret);
1879 }
1880
1881 /*
1882 * Set up the other three quadrants in `map'.
1883 */
1884 for (i = wh; i < 4*wh; i++)
1885 state->map->map[i] = state->map->map[i % wh];
1886
1887 assert(*p == ',');
1888 p++;
1889
1890 /*
1891 * Now process the clue list.
1892 */
1893 pos = 0;
1894 while (*p) {
1895 if (*p >= '0' && *p < '0'+FOUR) {
1896 state->colouring[pos] = *p - '0';
1897 state->map->immutable[pos] = true;
1898 pos++;
1899 } else {
1900 assert(*p >= 'a' && *p <= 'z');
1901 pos += *p - 'a' + 1;
1902 }
1903 p++;
1904 }
1905 assert(pos == n);
1906
1907 state->map->ngraph = gengraph(w, h, n, state->map->map, state->map->graph);
1908
1909 /*
1910 * Attempt to smooth out some of the more jagged region
1911 * outlines by the judicious use of diagonally divided squares.
1912 */
1913 {
1914 random_state *rs = random_new(desc, strlen(desc));
1915 int *squares = snewn(wh, int);
1916 bool done_something;
1917
1918 for (i = 0; i < wh; i++)
1919 squares[i] = i;
1920 shuffle(squares, wh, sizeof(*squares), rs);
1921
1922 do {
1923 done_something = false;
1924 for (i = 0; i < wh; i++) {
1925 int y = squares[i] / w, x = squares[i] % w;
1926 int c = state->map->map[y*w+x];
1927 int tc, bc, lc, rc;
1928
1929 if (x == 0 || x == w-1 || y == 0 || y == h-1)
1930 continue;
1931
1932 if (state->map->map[TE * wh + y*w+x] !=
1933 state->map->map[BE * wh + y*w+x])
1934 continue;
1935
1936 tc = state->map->map[BE * wh + (y-1)*w+x];
1937 bc = state->map->map[TE * wh + (y+1)*w+x];
1938 lc = state->map->map[RE * wh + y*w+(x-1)];
1939 rc = state->map->map[LE * wh + y*w+(x+1)];
1940
1941 /*
1942 * If this square is adjacent on two sides to one
1943 * region and on the other two sides to the other
1944 * region, and is itself one of the two regions, we can
1945 * adjust it so that it's a diagonal.
1946 */
1947 if (tc != bc && (tc == c || bc == c)) {
1948 if ((lc == tc && rc == bc) ||
1949 (lc == bc && rc == tc)) {
1950 state->map->map[TE * wh + y*w+x] = tc;
1951 state->map->map[BE * wh + y*w+x] = bc;
1952 state->map->map[LE * wh + y*w+x] = lc;
1953 state->map->map[RE * wh + y*w+x] = rc;
1954 done_something = true;
1955 }
1956 }
1957 }
1958 } while (done_something);
1959 sfree(squares);
1960 random_free(rs);
1961 }
1962
1963 /*
1964 * Analyse the map to find a canonical line segment
1965 * corresponding to each edge, and a canonical point
1966 * corresponding to each region. The former are where we'll
1967 * eventually put error markers; the latter are where we'll put
1968 * per-region flags such as numbers (when in diagnostic mode).
1969 */
1970 {
1971 int *bestx, *besty, *an, pass;
1972 float *ax, *ay, *best;
1973
1974 ax = snewn(state->map->ngraph + n, float);
1975 ay = snewn(state->map->ngraph + n, float);
1976 an = snewn(state->map->ngraph + n, int);
1977 bestx = snewn(state->map->ngraph + n, int);
1978 besty = snewn(state->map->ngraph + n, int);
1979 best = snewn(state->map->ngraph + n, float);
1980
1981 for (i = 0; i < state->map->ngraph + n; i++) {
1982 bestx[i] = besty[i] = -1;
1983 best[i] = (float)(2*(w+h)+1);
1984 ax[i] = ay[i] = 0.0F;
1985 an[i] = 0;
1986 }
1987
1988 /*
1989 * We make two passes over the map, finding all the line
1990 * segments separating regions and all the suitable points
1991 * within regions. In the first pass, we compute the
1992 * _average_ x and y coordinate of all the points in a
1993 * given class; in the second pass, for each such average
1994 * point, we find the candidate closest to it and call that
1995 * canonical.
1996 *
1997 * Line segments are considered to have coordinates in
1998 * their centre. Thus, at least one coordinate for any line
1999 * segment is always something-and-a-half; so we store our
2000 * coordinates as twice their normal value.
2001 */
2002 for (pass = 0; pass < 2; pass++) {
2003 int x, y;
2004
2005 for (y = 0; y < h; y++)
2006 for (x = 0; x < w; x++) {
2007 int ex[4], ey[4], ea[4], eb[4], en = 0;
2008
2009 /*
2010 * Look for an edge to the right of this
2011 * square, an edge below it, and an edge in the
2012 * middle of it. Also look to see if the point
2013 * at the bottom right of this square is on an
2014 * edge (and isn't a place where more than two
2015 * regions meet).
2016 */
2017 if (x+1 < w) {
2018 /* right edge */
2019 ea[en] = state->map->map[RE * wh + y*w+x];
2020 eb[en] = state->map->map[LE * wh + y*w+(x+1)];
2021 ex[en] = (x+1)*2;
2022 ey[en] = y*2+1;
2023 en++;
2024 }
2025 if (y+1 < h) {
2026 /* bottom edge */
2027 ea[en] = state->map->map[BE * wh + y*w+x];
2028 eb[en] = state->map->map[TE * wh + (y+1)*w+x];
2029 ex[en] = x*2+1;
2030 ey[en] = (y+1)*2;
2031 en++;
2032 }
2033 /* diagonal edge */
2034 ea[en] = state->map->map[TE * wh + y*w+x];
2035 eb[en] = state->map->map[BE * wh + y*w+x];
2036 ex[en] = x*2+1;
2037 ey[en] = y*2+1;
2038 en++;
2039
2040 if (x+1 < w && y+1 < h) {
2041 /* bottom right corner */
2042 int oct[8], othercol, nchanges;
2043 oct[0] = state->map->map[RE * wh + y*w+x];
2044 oct[1] = state->map->map[LE * wh + y*w+(x+1)];
2045 oct[2] = state->map->map[BE * wh + y*w+(x+1)];
2046 oct[3] = state->map->map[TE * wh + (y+1)*w+(x+1)];
2047 oct[4] = state->map->map[LE * wh + (y+1)*w+(x+1)];
2048 oct[5] = state->map->map[RE * wh + (y+1)*w+x];
2049 oct[6] = state->map->map[TE * wh + (y+1)*w+x];
2050 oct[7] = state->map->map[BE * wh + y*w+x];
2051
2052 othercol = -1;
2053 nchanges = 0;
2054 for (i = 0; i < 8; i++) {
2055 if (oct[i] != oct[0]) {
2056 if (othercol < 0)
2057 othercol = oct[i];
2058 else if (othercol != oct[i])
2059 break; /* three colours at this point */
2060 }
2061 if (oct[i] != oct[(i+1) & 7])
2062 nchanges++;
2063 }
2064
2065 /*
2066 * Now if there are exactly two regions at
2067 * this point (not one, and not three or
2068 * more), and only two changes around the
2069 * loop, then this is a valid place to put
2070 * an error marker.
2071 */
2072 if (i == 8 && othercol >= 0 && nchanges == 2) {
2073 ea[en] = oct[0];
2074 eb[en] = othercol;
2075 ex[en] = (x+1)*2;
2076 ey[en] = (y+1)*2;
2077 en++;
2078 }
2079
2080 /*
2081 * If there's exactly _one_ region at this
2082 * point, on the other hand, it's a valid
2083 * place to put a region centre.
2084 */
2085 if (othercol < 0) {
2086 ea[en] = eb[en] = oct[0];
2087 ex[en] = (x+1)*2;
2088 ey[en] = (y+1)*2;
2089 en++;
2090 }
2091 }
2092
2093 /*
2094 * Now process the points we've found, one by
2095 * one.
2096 */
2097 for (i = 0; i < en; i++) {
2098 int emin = min(ea[i], eb[i]);
2099 int emax = max(ea[i], eb[i]);
2100 int gindex;
2101
2102 if (emin != emax) {
2103 /* Graph edge */
2104 gindex =
2105 graph_edge_index(state->map->graph, n,
2106 state->map->ngraph, emin,
2107 emax);
2108 } else {
2109 /* Region number */
2110 gindex = state->map->ngraph + emin;
2111 }
2112
2113 assert(gindex >= 0);
2114
2115 if (pass == 0) {
2116 /*
2117 * In pass 0, accumulate the values
2118 * we'll use to compute the average
2119 * positions.
2120 */
2121 ax[gindex] += ex[i];
2122 ay[gindex] += ey[i];
2123 an[gindex] += 1;
2124 } else {
2125 /*
2126 * In pass 1, work out whether this
2127 * point is closer to the average than
2128 * the last one we've seen.
2129 */
2130 float dx, dy, d;
2131
2132 assert(an[gindex] > 0);
2133 dx = ex[i] - ax[gindex];
2134 dy = ey[i] - ay[gindex];
2135 d = (float)sqrt(dx*dx + dy*dy);
2136 if (d < best[gindex]) {
2137 best[gindex] = d;
2138 bestx[gindex] = ex[i];
2139 besty[gindex] = ey[i];
2140 }
2141 }
2142 }
2143 }
2144
2145 if (pass == 0) {
2146 for (i = 0; i < state->map->ngraph + n; i++)
2147 if (an[i] > 0) {
2148 ax[i] /= an[i];
2149 ay[i] /= an[i];
2150 }
2151 }
2152 }
2153
2154 state->map->edgex = snewn(state->map->ngraph, int);
2155 state->map->edgey = snewn(state->map->ngraph, int);
2156 memcpy(state->map->edgex, bestx, state->map->ngraph * sizeof(int));
2157 memcpy(state->map->edgey, besty, state->map->ngraph * sizeof(int));
2158
2159 state->map->regionx = snewn(n, int);
2160 state->map->regiony = snewn(n, int);
2161 memcpy(state->map->regionx, bestx + state->map->ngraph, n*sizeof(int));
2162 memcpy(state->map->regiony, besty + state->map->ngraph, n*sizeof(int));
2163
2164 for (i = 0; i < state->map->ngraph; i++)
2165 if (state->map->edgex[i] < 0) {
2166 /* Find the other representation of this edge. */
2167 int e = state->map->graph[i];
2168 int iprime = graph_edge_index(state->map->graph, n,
2169 state->map->ngraph, e%n, e/n);
2170 assert(state->map->edgex[iprime] >= 0);
2171 state->map->edgex[i] = state->map->edgex[iprime];
2172 state->map->edgey[i] = state->map->edgey[iprime];
2173 }
2174
2175 sfree(ax);
2176 sfree(ay);
2177 sfree(an);
2178 sfree(best);
2179 sfree(bestx);
2180 sfree(besty);
2181 }
2182
2183 return state;
2184}
2185
2186static game_state *dup_game(const game_state *state)
2187{
2188 game_state *ret = snew(game_state);
2189
2190 ret->p = state->p;
2191 ret->colouring = snewn(state->p.n, int);
2192 memcpy(ret->colouring, state->colouring, state->p.n * sizeof(int));
2193 ret->pencil = snewn(state->p.n, int);
2194 memcpy(ret->pencil, state->pencil, state->p.n * sizeof(int));
2195 ret->map = state->map;
2196 ret->map->refcount++;
2197 ret->completed = state->completed;
2198 ret->cheated = state->cheated;
2199
2200 return ret;
2201}
2202
2203static void free_game(game_state *state)
2204{
2205 if (--state->map->refcount <= 0) {
2206 sfree(state->map->map);
2207 sfree(state->map->graph);
2208 sfree(state->map->immutable);
2209 sfree(state->map->edgex);
2210 sfree(state->map->edgey);
2211 sfree(state->map->regionx);
2212 sfree(state->map->regiony);
2213 sfree(state->map);
2214 }
2215 sfree(state->pencil);
2216 sfree(state->colouring);
2217 sfree(state);
2218}
2219
2220static char *solve_game(const game_state *state, const game_state *currstate,
2221 const char *aux, const char **error)
2222{
2223 if (!aux) {
2224 /*
2225 * Use the solver.
2226 */
2227 int *colouring;
2228 struct solver_scratch *sc;
2229 int sret;
2230 int i;
2231 char *ret, buf[80];
2232 int retlen, retsize;
2233
2234 colouring = snewn(state->map->n, int);
2235 memcpy(colouring, state->colouring, state->map->n * sizeof(int));
2236
2237 sc = new_scratch(state->map->graph, state->map->n, state->map->ngraph);
2238 sret = map_solver(sc, state->map->graph, state->map->n,
2239 state->map->ngraph, colouring, DIFFCOUNT-1);
2240 free_scratch(sc);
2241
2242 if (sret != 1) {
2243 sfree(colouring);
2244 if (sret == 0)
2245 *error = "Puzzle is inconsistent";
2246 else
2247 *error = "Unable to find a unique solution for this puzzle";
2248 return NULL;
2249 }
2250
2251 retsize = 64;
2252 ret = snewn(retsize, char);
2253 strcpy(ret, "S");
2254 retlen = 1;
2255
2256 for (i = 0; i < state->map->n; i++) {
2257 int len;
2258
2259 assert(colouring[i] >= 0);
2260 if (colouring[i] == currstate->colouring[i])
2261 continue;
2262 assert(!state->map->immutable[i]);
2263
2264 len = sprintf(buf, ";%d:%d", colouring[i], i);
2265 if (retlen + len >= retsize) {
2266 retsize = retlen + len + 256;
2267 ret = sresize(ret, retsize, char);
2268 }
2269 strcpy(ret + retlen, buf);
2270 retlen += len;
2271 }
2272
2273 sfree(colouring);
2274
2275 return ret;
2276 }
2277 return dupstr(aux);
2278}
2279
2280struct game_ui {
2281 /*
2282 * drag_colour:
2283 *
2284 * - -2 means no drag currently active.
2285 * - >=0 means we're dragging a solid colour.
2286 * - -1 means we're dragging a blank space, and drag_pencil
2287 * might or might not add some pencil-mark stipples to that.
2288 */
2289 int drag_colour;
2290 int drag_pencil;
2291 int dragx, dragy;
2292 bool show_numbers;
2293 bool large_stipples;
2294
2295 int cur_x, cur_y, cur_lastmove;
2296 bool cur_visible, cur_moved;
2297
2298 /*
2299 * User preference to enable alternative versions of the
2300 * completion flash. Some users have found the colour-cycling
2301 * default version to be a bit eye-twisting.
2302 */
2303 enum {
2304 FLASH_CYCLIC, /* cycle the four colours of the map */
2305 FLASH_EACH_TO_WHITE, /* turn each colour white in turn */
2306 FLASH_ALL_TO_WHITE /* flash the whole map to white in one go */
2307 } flash_type;
2308};
2309
2310static void legacy_prefs_override(struct game_ui *ui_out)
2311{
2312 static bool initialised = false;
2313 static int flash_type = -1;
2314
2315 if (!initialised) {
2316 char *env;
2317
2318 initialised = true;
2319
2320 if ((env = getenv("MAP_ALTERNATIVE_FLASH")) != NULL)
2321 flash_type = FLASH_EACH_TO_WHITE;
2322 }
2323
2324 if (flash_type != -1)
2325 ui_out->flash_type = flash_type;
2326}
2327
2328static game_ui *new_ui(const game_state *state)
2329{
2330 game_ui *ui = snew(game_ui);
2331 ui->dragx = ui->dragy = -1;
2332 ui->drag_colour = -2;
2333 ui->drag_pencil = 0;
2334 ui->show_numbers = false;
2335 ui->cur_x = ui->cur_y = 0;
2336 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
2337 ui->cur_moved = false;
2338 ui->cur_lastmove = 0;
2339 ui->flash_type = FLASH_CYCLIC;
2340 ui->large_stipples = false;
2341 legacy_prefs_override(ui);
2342 return ui;
2343}
2344
2345static config_item *get_prefs(game_ui *ui)
2346{
2347 config_item *ret;
2348
2349 ret = snewn(N_PREF_ITEMS+1, config_item);
2350
2351 ret[PREF_FLASH_TYPE].name = "Victory flash effect";
2352 ret[PREF_FLASH_TYPE].kw = "flash-type";
2353 ret[PREF_FLASH_TYPE].type = C_CHOICES;
2354 ret[PREF_FLASH_TYPE].u.choices.choicenames =
2355 ":Cyclic:Each to white:All to white";
2356 ret[PREF_FLASH_TYPE].u.choices.choicekws = ":cyclic:each-white:all-white";
2357 ret[PREF_FLASH_TYPE].u.choices.selected = ui->flash_type;
2358
2359 ret[PREF_SHOW_NUMBERS].name = "Number regions";
2360 ret[PREF_SHOW_NUMBERS].kw = "show-numbers";
2361 ret[PREF_SHOW_NUMBERS].type = C_BOOLEAN;
2362 ret[PREF_SHOW_NUMBERS].u.boolean.bval = ui->show_numbers;
2363
2364 ret[PREF_STIPPLE_STYLE].name = "Display style for stipple marks";
2365 ret[PREF_STIPPLE_STYLE].kw = "stipple-style";
2366 ret[PREF_STIPPLE_STYLE].type = C_CHOICES;
2367 ret[PREF_STIPPLE_STYLE].u.choices.choicenames = ":Small:Large";
2368 ret[PREF_STIPPLE_STYLE].u.choices.choicekws = ":small:large";
2369 ret[PREF_STIPPLE_STYLE].u.choices.selected = ui->large_stipples;
2370
2371 ret[N_PREF_ITEMS].name = NULL;
2372 ret[N_PREF_ITEMS].type = C_END;
2373
2374 return ret;
2375}
2376
2377static void set_prefs(game_ui *ui, const config_item *cfg)
2378{
2379 ui->flash_type = cfg[PREF_FLASH_TYPE].u.choices.selected;
2380 ui->show_numbers = cfg[PREF_SHOW_NUMBERS].u.boolean.bval;
2381 ui->large_stipples = cfg[PREF_STIPPLE_STYLE].u.choices.selected;
2382}
2383
2384static void free_ui(game_ui *ui)
2385{
2386 sfree(ui);
2387}
2388
2389static void game_changed_state(game_ui *ui, const game_state *oldstate,
2390 const game_state *newstate)
2391{
2392}
2393
2394struct game_drawstate {
2395 int tilesize;
2396 unsigned long *drawn, *todraw;
2397 bool started;
2398 int dragx, dragy;
2399 bool drag_visible;
2400 blitter *bl;
2401};
2402
2403/* Flags in `drawn'. */
2404#define ERR_BASE 0x00800000L
2405#define ERR_MASK 0xFF800000L
2406#define PENCIL_T_BASE 0x00080000L
2407#define PENCIL_T_MASK 0x00780000L
2408#define PENCIL_B_BASE 0x00008000L
2409#define PENCIL_B_MASK 0x00078000L
2410#define PENCIL_MASK 0x007F8000L
2411#define SHOW_NUMBERS 0x00004000L
2412
2413#define TILESIZE (ds->tilesize)
2414#define BORDER (TILESIZE)
2415#define COORD(x) ( (x) * TILESIZE + BORDER )
2416#define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 )
2417
2418 /*
2419 * EPSILON_FOO are epsilons added to absolute cursor position by
2420 * cursor movement, such that in pathological cases (e.g. a very
2421 * small diamond-shaped area) it's relatively easy to select the
2422 * region you wanted.
2423 */
2424
2425#define EPSILON_X(button) (((button) == CURSOR_RIGHT) ? +1 : \
2426 ((button) == CURSOR_LEFT) ? -1 : 0)
2427#define EPSILON_Y(button) (((button) == CURSOR_DOWN) ? +1 : \
2428 ((button) == CURSOR_UP) ? -1 : 0)
2429
2430
2431/*
2432 * Return the map region containing a point in tile (tx,ty), offset by
2433 * (x_eps,y_eps) from the centre of the tile.
2434 */
2435static int region_from_logical_coords(const game_state *state, int tx, int ty,
2436 int x_eps, int y_eps)
2437{
2438 int w = state->p.w, h = state->p.h, wh = w*h /*, n = state->p.n */;
2439
2440 int quadrant;
2441
2442 if (tx < 0 || tx >= w || ty < 0 || ty >= h)
2443 return -1; /* border */
2444
2445 quadrant = 2 * (x_eps > y_eps) + (-x_eps > y_eps);
2446 quadrant = (quadrant == 0 ? BE :
2447 quadrant == 1 ? LE :
2448 quadrant == 2 ? RE : TE);
2449
2450 return state->map->map[quadrant * wh + ty*w+tx];
2451}
2452
2453static int region_from_coords(const game_state *state,
2454 const game_drawstate *ds, int x, int y)
2455{
2456 int tx = FROMCOORD(x), ty = FROMCOORD(y);
2457 return region_from_logical_coords(
2458 state, tx, ty, x - COORD(tx) - TILESIZE/2, y - COORD(ty) - TILESIZE/2);
2459}
2460
2461static int region_from_ui_cursor(const game_state *state, const game_ui *ui)
2462{
2463 assert(ui->cur_visible);
2464 return region_from_logical_coords(state, ui->cur_x, ui->cur_y,
2465 EPSILON_X(ui->cur_lastmove),
2466 EPSILON_Y(ui->cur_lastmove));
2467}
2468
2469static const char *current_key_label(const game_ui *ui,
2470 const game_state *state, int button)
2471{
2472 int r;
2473
2474 if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
2475 if (ui->drag_colour == -2) return "Pick";
2476 r = region_from_ui_cursor(state, ui);
2477 if (state->map->immutable[r]) return "Cancel";
2478 if (!ui->cur_moved) return ui->drag_pencil ? "Cancel" : "Clear";
2479 if (button == CURSOR_SELECT2) {
2480 if (state->colouring[r] >= 0) return "Cancel";
2481 if (ui->drag_colour >= 0) return "Stipple";
2482 }
2483 if (ui->drag_pencil) return "Stipple";
2484 return ui->drag_colour >= 0 ? "Fill" : "Clear";
2485 }
2486 return "";
2487}
2488
2489static char *interpret_move(const game_state *state, game_ui *ui,
2490 const game_drawstate *ds,
2491 int x, int y, int button)
2492{
2493 char *bufp, buf[256];
2494 bool alt_button;
2495 int drop_region;
2496
2497 /*
2498 * Enable or disable numeric labels on regions.
2499 */
2500 if (button == 'l' || button == 'L') {
2501 ui->show_numbers = !ui->show_numbers;
2502 return MOVE_UI_UPDATE;
2503 }
2504
2505 if (IS_CURSOR_MOVE(button)) {
2506 move_cursor(button, &ui->cur_x, &ui->cur_y, state->p.w, state->p.h,
2507 false, NULL);
2508 ui->cur_visible = true;
2509 ui->cur_moved = true;
2510 ui->cur_lastmove = button;
2511 return MOVE_UI_UPDATE;
2512 }
2513 if (IS_CURSOR_SELECT(button)) {
2514 if (!ui->cur_visible) {
2515 ui->cur_visible = true;
2516 return MOVE_UI_UPDATE;
2517 }
2518 if (ui->drag_colour == -2) { /* not currently cursor-dragging, start. */
2519 int r = region_from_ui_cursor(state, ui);
2520 if (r >= 0) {
2521 ui->drag_colour = state->colouring[r];
2522 ui->drag_pencil = (ui->drag_colour >= 0) ? 0 : state->pencil[r];
2523 } else {
2524 ui->drag_colour = -1;
2525 ui->drag_pencil = 0;
2526 }
2527 ui->cur_moved = false;
2528 return MOVE_UI_UPDATE;
2529 } else { /* currently cursor-dragging; drop the colour in the new region. */
2530 alt_button = (button == CURSOR_SELECT2);
2531 /* Double-select removes current colour. */
2532 if (!ui->cur_moved) ui->drag_colour = -1;
2533 drop_region = region_from_ui_cursor(state, ui);
2534 goto drag_dropped;
2535 }
2536 }
2537
2538 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
2539 int r = region_from_coords(state, ds, x, y);
2540
2541 if (r >= 0) {
2542 ui->drag_colour = state->colouring[r];
2543 ui->drag_pencil = state->pencil[r];
2544 if (ui->drag_colour >= 0)
2545 ui->drag_pencil = 0; /* should be already, but double-check */
2546 } else {
2547 ui->drag_colour = -1;
2548 ui->drag_pencil = 0;
2549 }
2550 ui->dragx = x;
2551 ui->dragy = y;
2552 ui->cur_visible = false;
2553 return MOVE_UI_UPDATE;
2554 }
2555
2556 if ((button == LEFT_DRAG || button == RIGHT_DRAG) &&
2557 ui->drag_colour > -2) {
2558 ui->dragx = x;
2559 ui->dragy = y;
2560 return MOVE_UI_UPDATE;
2561 }
2562
2563 if ((button == LEFT_RELEASE || button == RIGHT_RELEASE) &&
2564 ui->drag_colour > -2) {
2565 alt_button = (button == RIGHT_RELEASE);
2566 drop_region = region_from_coords(state, ds, x, y);
2567 goto drag_dropped;
2568 }
2569
2570 return NULL;
2571
2572drag_dropped:
2573 {
2574 int r = drop_region;
2575 int c = ui->drag_colour;
2576 int p = ui->drag_pencil;
2577 int oldp;
2578
2579 /*
2580 * Cancel the drag, whatever happens.
2581 */
2582 ui->drag_colour = -2;
2583
2584 if (r < 0)
2585 return MOVE_UI_UPDATE; /* drag into border; do nothing else */
2586
2587 if (state->map->immutable[r])
2588 return MOVE_UI_UPDATE; /* can't change this region */
2589
2590 if (state->colouring[r] == c && state->pencil[r] == p)
2591 return MOVE_UI_UPDATE; /* don't _need_ to change this region */
2592
2593 if (alt_button) {
2594 if (state->colouring[r] >= 0) {
2595 /* Can't pencil on a coloured region */
2596 return MOVE_UI_UPDATE;
2597 } else if (c >= 0) {
2598 /* Right-dragging from colour to blank toggles one pencil */
2599 p = state->pencil[r] ^ (1 << c);
2600 c = -1;
2601 }
2602 /* Otherwise, right-dragging from blank to blank is equivalent
2603 * to left-dragging. */
2604 }
2605
2606 bufp = buf;
2607 oldp = state->pencil[r];
2608 if (c != state->colouring[r]) {
2609 bufp += sprintf(bufp, ";%c:%d", (int)(c < 0 ? 'C' : '0' + c), r);
2610 if (c >= 0)
2611 oldp = 0;
2612 }
2613 if (p != oldp) {
2614 int i;
2615 for (i = 0; i < FOUR; i++)
2616 if ((oldp ^ p) & (1 << i))
2617 bufp += sprintf(bufp, ";p%c:%d", (int)('0' + i), r);
2618 }
2619
2620 return dupstr(buf+1); /* ignore first semicolon */
2621 }
2622}
2623
2624static game_state *execute_move(const game_state *state, const char *move)
2625{
2626 int n = state->p.n;
2627 game_state *ret = dup_game(state);
2628 int c, k, adv, i;
2629
2630 while (*move) {
2631 bool pencil = false;
2632
2633 c = *move;
2634 if (c == 'p') {
2635 pencil = true;
2636 c = *++move;
2637 }
2638 if ((c == 'C' || (c >= '0' && c < '0'+FOUR)) &&
2639 sscanf(move+1, ":%d%n", &k, &adv) == 1 &&
2640 k >= 0 && k < state->p.n) {
2641 move += 1 + adv;
2642 if (pencil) {
2643 if (ret->colouring[k] >= 0) {
2644 free_game(ret);
2645 return NULL;
2646 }
2647 if (c == 'C')
2648 ret->pencil[k] = 0;
2649 else
2650 ret->pencil[k] ^= 1 << (c - '0');
2651 } else {
2652 ret->colouring[k] = (c == 'C' ? -1 : c - '0');
2653 ret->pencil[k] = 0;
2654 }
2655 } else if (*move == 'S') {
2656 move++;
2657 ret->cheated = true;
2658 } else {
2659 free_game(ret);
2660 return NULL;
2661 }
2662
2663 if (*move && *move != ';') {
2664 free_game(ret);
2665 return NULL;
2666 }
2667 if (*move)
2668 move++;
2669 }
2670
2671 /*
2672 * Check for completion.
2673 */
2674 if (!ret->completed) {
2675 bool ok = true;
2676
2677 for (i = 0; i < n; i++)
2678 if (ret->colouring[i] < 0) {
2679 ok = false;
2680 break;
2681 }
2682
2683 if (ok) {
2684 for (i = 0; i < ret->map->ngraph; i++) {
2685 int j = ret->map->graph[i] / n;
2686 int k = ret->map->graph[i] % n;
2687 if (ret->colouring[j] == ret->colouring[k]) {
2688 ok = false;
2689 break;
2690 }
2691 }
2692 }
2693
2694 if (ok)
2695 ret->completed = true;
2696 }
2697
2698 return ret;
2699}
2700
2701/* ----------------------------------------------------------------------
2702 * Drawing routines.
2703 */
2704
2705static void game_compute_size(const game_params *params, int tilesize,
2706 const game_ui *ui, int *x, int *y)
2707{
2708 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2709 struct { int tilesize; } ads, *ds = &ads;
2710 ads.tilesize = tilesize;
2711
2712 *x = params->w * TILESIZE + 2 * BORDER + 1;
2713 *y = params->h * TILESIZE + 2 * BORDER + 1;
2714}
2715
2716static void game_set_size(drawing *dr, game_drawstate *ds,
2717 const game_params *params, int tilesize)
2718{
2719 ds->tilesize = tilesize;
2720
2721 assert(!ds->bl); /* set_size is never called twice */
2722 ds->bl = blitter_new(dr, TILESIZE+3, TILESIZE+3);
2723}
2724
2725static const float map_colours[FOUR][3] = {
2726#ifdef VIVID_COLOURS
2727 /* Use more vivid colours (e.g. on the Pocket PC) */
2728 {0.75F, 0.25F, 0.25F},
2729 {0.3F, 0.7F, 0.3F},
2730 {0.3F, 0.3F, 0.7F},
2731 {0.85F, 0.85F, 0.1F},
2732#else
2733 {0.7F, 0.5F, 0.4F},
2734 {0.8F, 0.7F, 0.4F},
2735 {0.5F, 0.6F, 0.4F},
2736 {0.55F, 0.45F, 0.35F},
2737#endif
2738};
2739static const int map_hatching[FOUR] = {
2740 HATCH_VERT, HATCH_SLASH, HATCH_HORIZ, HATCH_BACKSLASH
2741};
2742
2743static float *game_colours(frontend *fe, int *ncolours)
2744{
2745 float *ret = snewn(3 * NCOLOURS, float);
2746
2747 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
2748
2749 ret[COL_GRID * 3 + 0] = 0.0F;
2750 ret[COL_GRID * 3 + 1] = 0.0F;
2751 ret[COL_GRID * 3 + 2] = 0.0F;
2752
2753 memcpy(ret + COL_0 * 3, map_colours[0], 3 * sizeof(float));
2754 memcpy(ret + COL_1 * 3, map_colours[1], 3 * sizeof(float));
2755 memcpy(ret + COL_2 * 3, map_colours[2], 3 * sizeof(float));
2756 memcpy(ret + COL_3 * 3, map_colours[3], 3 * sizeof(float));
2757
2758 ret[COL_ERROR * 3 + 0] = 1.0F;
2759 ret[COL_ERROR * 3 + 1] = 0.0F;
2760 ret[COL_ERROR * 3 + 2] = 0.0F;
2761
2762 ret[COL_ERRTEXT * 3 + 0] = 1.0F;
2763 ret[COL_ERRTEXT * 3 + 1] = 1.0F;
2764 ret[COL_ERRTEXT * 3 + 2] = 1.0F;
2765
2766 *ncolours = NCOLOURS;
2767 return ret;
2768}
2769
2770static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
2771{
2772 struct game_drawstate *ds = snew(struct game_drawstate);
2773 int i;
2774
2775 ds->tilesize = 0;
2776 ds->drawn = snewn(state->p.w * state->p.h, unsigned long);
2777 for (i = 0; i < state->p.w * state->p.h; i++)
2778 ds->drawn[i] = 0xFFFFL;
2779 ds->todraw = snewn(state->p.w * state->p.h, unsigned long);
2780 ds->started = false;
2781 ds->bl = NULL;
2782 ds->drag_visible = false;
2783 ds->dragx = ds->dragy = -1;
2784
2785 return ds;
2786}
2787
2788static void game_free_drawstate(drawing *dr, game_drawstate *ds)
2789{
2790 sfree(ds->drawn);
2791 sfree(ds->todraw);
2792 if (ds->bl)
2793 blitter_free(dr, ds->bl);
2794 sfree(ds);
2795}
2796
2797static void draw_error(drawing *dr, game_drawstate *ds, int x, int y)
2798{
2799 int coords[8];
2800 int yext, xext;
2801
2802 /*
2803 * Draw a diamond.
2804 */
2805 coords[0] = x - TILESIZE*2/5;
2806 coords[1] = y;
2807 coords[2] = x;
2808 coords[3] = y - TILESIZE*2/5;
2809 coords[4] = x + TILESIZE*2/5;
2810 coords[5] = y;
2811 coords[6] = x;
2812 coords[7] = y + TILESIZE*2/5;
2813 draw_polygon(dr, coords, 4, COL_ERROR, COL_GRID);
2814
2815 /*
2816 * Draw an exclamation mark in the diamond. This turns out to
2817 * look unpleasantly off-centre if done via draw_text, so I do
2818 * it by hand on the basis that exclamation marks aren't that
2819 * difficult to draw...
2820 */
2821 xext = TILESIZE/16;
2822 yext = TILESIZE*2/5 - (xext*2+2);
2823 draw_rect(dr, x-xext, y-yext, xext*2+1, yext*2+1 - (xext*3),
2824 COL_ERRTEXT);
2825 draw_rect(dr, x-xext, y+yext-xext*2+1, xext*2+1, xext*2, COL_ERRTEXT);
2826}
2827
2828static void draw_square(drawing *dr, game_drawstate *ds,
2829 const game_params *params, struct map *map,
2830 int x, int y, unsigned long v, bool large_stipples)
2831{
2832 int w = params->w, h = params->h, wh = w*h;
2833 int tv, bv, xo, yo, i, j, oldj;
2834 unsigned long errs, pencil, show_numbers;
2835
2836 errs = v & ERR_MASK;
2837 v &= ~ERR_MASK;
2838 pencil = v & PENCIL_MASK;
2839 v &= ~PENCIL_MASK;
2840 show_numbers = v & SHOW_NUMBERS;
2841 v &= ~SHOW_NUMBERS;
2842 tv = v / FIVE;
2843 bv = v % FIVE;
2844
2845 clip(dr, COORD(x), COORD(y), TILESIZE, TILESIZE);
2846
2847 /*
2848 * Draw the region colour.
2849 */
2850 draw_rect(dr, COORD(x), COORD(y), TILESIZE, TILESIZE,
2851 (tv == FOUR ? COL_BACKGROUND : COL_0 + tv));
2852 /*
2853 * Draw the second region colour, if this is a diagonally
2854 * divided square.
2855 */
2856 if (map->map[TE * wh + y*w+x] != map->map[BE * wh + y*w+x]) {
2857 int coords[6];
2858 coords[0] = COORD(x)-1;
2859 coords[1] = COORD(y+1)+1;
2860 if (map->map[LE * wh + y*w+x] == map->map[TE * wh + y*w+x])
2861 coords[2] = COORD(x+1)+1;
2862 else
2863 coords[2] = COORD(x)-1;
2864 coords[3] = COORD(y)-1;
2865 coords[4] = COORD(x+1)+1;
2866 coords[5] = COORD(y+1)+1;
2867 draw_polygon(dr, coords, 3,
2868 (bv == FOUR ? COL_BACKGROUND : COL_0 + bv), COL_GRID);
2869 }
2870
2871 /*
2872 * Draw `pencil marks'. Currently we arrange these in a square
2873 * formation, which means we may be in trouble if the value of
2874 * FOUR changes later...
2875 */
2876 assert(FOUR == 4);
2877 for (yo = 0; yo < 4; yo++)
2878 for (xo = 0; xo < 4; xo++) {
2879 int te = map->map[TE * wh + y*w+x];
2880 int e, ee, c;
2881
2882 e = (yo < xo && yo < 3-xo ? TE :
2883 yo > xo && yo > 3-xo ? BE :
2884 xo < 2 ? LE : RE);
2885 ee = map->map[e * wh + y*w+x];
2886
2887 if (xo != (yo * 2 + 1) % 5)
2888 continue;
2889 c = yo;
2890
2891 if (!(pencil & ((ee == te ? PENCIL_T_BASE : PENCIL_B_BASE) << c)))
2892 continue;
2893
2894 if (yo == xo &&
2895 (map->map[TE * wh + y*w+x] != map->map[LE * wh + y*w+x]))
2896 continue; /* avoid TL-BR diagonal line */
2897 if (yo == 3-xo &&
2898 (map->map[TE * wh + y*w+x] != map->map[RE * wh + y*w+x]))
2899 continue; /* avoid BL-TR diagonal line */
2900
2901 draw_circle(dr, COORD(x) + (xo+1)*TILESIZE/5,
2902 COORD(y) + (yo+1)*TILESIZE/5,
2903 large_stipples ? TILESIZE/4 : TILESIZE/7,
2904 COL_0 + c, COL_0 + c);
2905 }
2906
2907 /*
2908 * Draw the grid lines, if required.
2909 */
2910 if (x <= 0 || map->map[RE*wh+y*w+(x-1)] != map->map[LE*wh+y*w+x])
2911 draw_rect(dr, COORD(x), COORD(y), 1, TILESIZE, COL_GRID);
2912 if (y <= 0 || map->map[BE*wh+(y-1)*w+x] != map->map[TE*wh+y*w+x])
2913 draw_rect(dr, COORD(x), COORD(y), TILESIZE, 1, COL_GRID);
2914 if (x <= 0 || y <= 0 ||
2915 map->map[RE*wh+(y-1)*w+(x-1)] != map->map[TE*wh+y*w+x] ||
2916 map->map[BE*wh+(y-1)*w+(x-1)] != map->map[LE*wh+y*w+x])
2917 draw_rect(dr, COORD(x), COORD(y), 1, 1, COL_GRID);
2918
2919 /*
2920 * Draw error markers.
2921 */
2922 for (yo = 0; yo < 3; yo++)
2923 for (xo = 0; xo < 3; xo++)
2924 if (errs & (ERR_BASE << (yo*3+xo)))
2925 draw_error(dr, ds,
2926 (COORD(x)*2+TILESIZE*xo)/2,
2927 (COORD(y)*2+TILESIZE*yo)/2);
2928
2929 /*
2930 * Draw region numbers, if desired.
2931 */
2932 if (show_numbers) {
2933 oldj = -1;
2934 for (i = 0; i < 2; i++) {
2935 j = map->map[(i?BE:TE)*wh+y*w+x];
2936 if (oldj == j)
2937 continue;
2938 oldj = j;
2939
2940 xo = map->regionx[j] - 2*x;
2941 yo = map->regiony[j] - 2*y;
2942 if (xo >= 0 && xo <= 2 && yo >= 0 && yo <= 2) {
2943 char buf[80];
2944 sprintf(buf, "%d", j);
2945 draw_text(dr, (COORD(x)*2+TILESIZE*xo)/2,
2946 (COORD(y)*2+TILESIZE*yo)/2,
2947 FONT_VARIABLE, 3*TILESIZE/5,
2948 ALIGN_HCENTRE|ALIGN_VCENTRE,
2949 COL_GRID, buf);
2950 }
2951 }
2952 }
2953
2954 unclip(dr);
2955
2956 draw_update(dr, COORD(x), COORD(y), TILESIZE, TILESIZE);
2957}
2958
2959static float flash_length(const game_ui *ui)
2960{
2961 return (ui->flash_type == FLASH_EACH_TO_WHITE ? 0.50F : 0.30F);
2962}
2963
2964static void game_redraw(drawing *dr, game_drawstate *ds,
2965 const game_state *oldstate, const game_state *state,
2966 int dir, const game_ui *ui,
2967 float animtime, float flashtime)
2968{
2969 int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n;
2970 int x, y, i;
2971 int flash;
2972
2973 if (ds->drag_visible) {
2974 blitter_load(dr, ds->bl, ds->dragx, ds->dragy);
2975 draw_update(dr, ds->dragx, ds->dragy, TILESIZE + 3, TILESIZE + 3);
2976 ds->drag_visible = false;
2977 }
2978
2979 if (!ds->started) {
2980 draw_rect(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1,
2981 COL_GRID);
2982 draw_update(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1);
2983 ds->started = true;
2984 }
2985
2986 if (flashtime) {
2987 if (ui->flash_type == FLASH_EACH_TO_WHITE)
2988 flash = (int)(flashtime * FOUR / flash_length(ui));
2989 else
2990 flash = 1 + (int)(flashtime * THREE / flash_length(ui));
2991 } else
2992 flash = -1;
2993
2994 /*
2995 * Set up the `todraw' array.
2996 */
2997 for (y = 0; y < h; y++)
2998 for (x = 0; x < w; x++) {
2999 int tv = state->colouring[state->map->map[TE * wh + y*w+x]];
3000 int bv = state->colouring[state->map->map[BE * wh + y*w+x]];
3001 unsigned long v;
3002
3003 if (tv < 0)
3004 tv = FOUR;
3005 if (bv < 0)
3006 bv = FOUR;
3007
3008 if (flash >= 0) {
3009 if (ui->flash_type == FLASH_EACH_TO_WHITE) {
3010 if (tv == flash)
3011 tv = FOUR;
3012 if (bv == flash)
3013 bv = FOUR;
3014 } else if (ui->flash_type == FLASH_ALL_TO_WHITE) {
3015 if (flash % 2)
3016 tv = bv = FOUR;
3017 } else {
3018 if (tv != FOUR)
3019 tv = (tv + flash) % FOUR;
3020 if (bv != FOUR)
3021 bv = (bv + flash) % FOUR;
3022 }
3023 }
3024
3025 v = tv * FIVE + bv;
3026
3027 /*
3028 * Add pencil marks.
3029 */
3030 for (i = 0; i < FOUR; i++) {
3031 if (state->colouring[state->map->map[TE * wh + y*w+x]] < 0 &&
3032 (state->pencil[state->map->map[TE * wh + y*w+x]] & (1<<i)))
3033 v |= PENCIL_T_BASE << i;
3034 if (state->colouring[state->map->map[BE * wh + y*w+x]] < 0 &&
3035 (state->pencil[state->map->map[BE * wh + y*w+x]] & (1<<i)))
3036 v |= PENCIL_B_BASE << i;
3037 }
3038
3039 if (ui->show_numbers)
3040 v |= SHOW_NUMBERS;
3041
3042 ds->todraw[y*w+x] = v;
3043 }
3044
3045 /*
3046 * Add error markers to the `todraw' array.
3047 */
3048 for (i = 0; i < state->map->ngraph; i++) {
3049 int v1 = state->map->graph[i] / n;
3050 int v2 = state->map->graph[i] % n;
3051 int xo, yo;
3052
3053 if (state->colouring[v1] < 0 || state->colouring[v2] < 0)
3054 continue;
3055 if (state->colouring[v1] != state->colouring[v2])
3056 continue;
3057
3058 x = state->map->edgex[i];
3059 y = state->map->edgey[i];
3060
3061 xo = x % 2; x /= 2;
3062 yo = y % 2; y /= 2;
3063
3064 ds->todraw[y*w+x] |= ERR_BASE << (yo*3+xo);
3065 if (xo == 0) {
3066 assert(x > 0);
3067 ds->todraw[y*w+(x-1)] |= ERR_BASE << (yo*3+2);
3068 }
3069 if (yo == 0) {
3070 assert(y > 0);
3071 ds->todraw[(y-1)*w+x] |= ERR_BASE << (2*3+xo);
3072 }
3073 if (xo == 0 && yo == 0) {
3074 assert(x > 0 && y > 0);
3075 ds->todraw[(y-1)*w+(x-1)] |= ERR_BASE << (2*3+2);
3076 }
3077 }
3078
3079 /*
3080 * Now actually draw everything.
3081 */
3082 for (y = 0; y < h; y++)
3083 for (x = 0; x < w; x++) {
3084 unsigned long v = ds->todraw[y*w+x];
3085 if (ds->drawn[y*w+x] != v) {
3086 draw_square(dr, ds, &state->p, state->map, x, y, v, ui->large_stipples);
3087 ds->drawn[y*w+x] = v;
3088 }
3089 }
3090
3091 /*
3092 * Draw the dragged colour blob if any.
3093 */
3094 if ((ui->drag_colour > -2) || ui->cur_visible) {
3095 int bg, cursor_x, cursor_y;
3096 bool iscur = false;
3097 if (ui->drag_colour >= 0)
3098 bg = COL_0 + ui->drag_colour;
3099 else if (ui->drag_colour == -1) {
3100 bg = COL_BACKGROUND;
3101 } else {
3102 int r = region_from_ui_cursor(state, ui);
3103 int c = (r < 0) ? -1 : state->colouring[r];
3104 /*bg = COL_GRID;*/
3105 bg = (c < 0) ? COL_BACKGROUND : COL_0 + c;
3106 iscur = true;
3107 }
3108
3109 if (ui->cur_visible) {
3110 cursor_x = COORD(ui->cur_x) + TILESIZE/2 +
3111 EPSILON_X(ui->cur_lastmove);
3112 cursor_y = COORD(ui->cur_y) + TILESIZE/2 +
3113 EPSILON_Y(ui->cur_lastmove);
3114 } else {
3115 cursor_x = ui->dragx;
3116 cursor_y = ui->dragy;
3117 }
3118 ds->dragx = cursor_x - TILESIZE/2 - 2;
3119 ds->dragy = cursor_y - TILESIZE/2 - 2;
3120 blitter_save(dr, ds->bl, ds->dragx, ds->dragy);
3121 draw_circle(dr, cursor_x, cursor_y,
3122 iscur ? TILESIZE/4 : TILESIZE/2, bg, COL_GRID);
3123 for (i = 0; i < FOUR; i++)
3124 if (ui->drag_pencil & (1 << i))
3125 draw_circle(dr, cursor_x + ((i*4+2)%10-3) * TILESIZE/10,
3126 cursor_y + (i*2-3) * TILESIZE/10,
3127 TILESIZE/8, COL_0 + i, COL_0 + i);
3128 draw_update(dr, ds->dragx, ds->dragy, TILESIZE + 3, TILESIZE + 3);
3129 ds->drag_visible = true;
3130 }
3131}
3132
3133static float game_anim_length(const game_state *oldstate,
3134 const game_state *newstate, int dir, game_ui *ui)
3135{
3136 return 0.0F;
3137}
3138
3139static float game_flash_length(const game_state *oldstate,
3140 const game_state *newstate, int dir, game_ui *ui)
3141{
3142 if (!oldstate->completed && newstate->completed &&
3143 !oldstate->cheated && !newstate->cheated) {
3144 return flash_length(ui);
3145 } else
3146 return 0.0F;
3147}
3148
3149static void game_get_cursor_location(const game_ui *ui,
3150 const game_drawstate *ds,
3151 const game_state *state,
3152 const game_params *params,
3153 int *x, int *y, int *w, int *h)
3154{
3155 if(ui->cur_visible) {
3156 *x = COORD(ui->cur_x);
3157 *y = COORD(ui->cur_y);
3158 *w = *h = TILESIZE;
3159 }
3160}
3161
3162static int game_status(const game_state *state)
3163{
3164 return state->completed ? +1 : 0;
3165}
3166
3167static void game_print_size(const game_params *params, const game_ui *ui,
3168 float *x, float *y)
3169{
3170 int pw, ph;
3171
3172 /*
3173 * I'll use 4mm squares by default, I think. Simplest way to
3174 * compute this size is to compute the pixel puzzle size at a
3175 * given tile size and then scale.
3176 */
3177 game_compute_size(params, 400, ui, &pw, &ph);
3178 *x = pw / 100.0F;
3179 *y = ph / 100.0F;
3180}
3181
3182static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
3183 int tilesize)
3184{
3185 int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n;
3186 int ink, c[FOUR], i;
3187 int x, y, r;
3188 int *coords, ncoords, coordsize;
3189
3190 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
3191 struct { int tilesize; } ads, *ds = &ads;
3192 /* We can't call game_set_size() here because we don't want a blitter */
3193 ads.tilesize = tilesize;
3194
3195 ink = print_mono_colour(dr, 0);
3196 for (i = 0; i < FOUR; i++)
3197 c[i] = print_rgb_hatched_colour(dr, map_colours[i][0],
3198 map_colours[i][1], map_colours[i][2],
3199 map_hatching[i]);
3200
3201 coordsize = 0;
3202 coords = NULL;
3203
3204 print_line_width(dr, TILESIZE / 16);
3205
3206 /*
3207 * Draw a single filled polygon around each region.
3208 */
3209 for (r = 0; r < n; r++) {
3210 int octants[8], lastdir, d1, d2, ox, oy;
3211
3212 /*
3213 * Start by finding a point on the region boundary. Any
3214 * point will do. To do this, we'll search for a square
3215 * containing the region and then decide which corner of it
3216 * to use.
3217 */
3218 x = w;
3219 for (y = 0; y < h; y++) {
3220 for (x = 0; x < w; x++) {
3221 if (state->map->map[wh*0+y*w+x] == r ||
3222 state->map->map[wh*1+y*w+x] == r ||
3223 state->map->map[wh*2+y*w+x] == r ||
3224 state->map->map[wh*3+y*w+x] == r)
3225 break;
3226 }
3227 if (x < w)
3228 break;
3229 }
3230 assert(y < h && x < w); /* we must have found one somewhere */
3231 /*
3232 * This is the first square in lexicographic order which
3233 * contains part of this region. Therefore, one of the top
3234 * two corners of the square must be what we're after. The
3235 * only case in which it isn't the top left one is if the
3236 * square is diagonally divided and the region is in the
3237 * bottom right half.
3238 */
3239 if (state->map->map[wh*TE+y*w+x] != r &&
3240 state->map->map[wh*LE+y*w+x] != r)
3241 x++; /* could just as well have done y++ */
3242
3243 /*
3244 * Now we have a point on the region boundary. Trace around
3245 * the region until we come back to this point,
3246 * accumulating coordinates for a polygon draw operation as
3247 * we go.
3248 */
3249 lastdir = -1;
3250 ox = x;
3251 oy = y;
3252 ncoords = 0;
3253
3254 do {
3255 /*
3256 * There are eight possible directions we could head in
3257 * from here. We identify them by octant numbers, and
3258 * we also use octant numbers to identify the spaces
3259 * between them:
3260 *
3261 * 6 7 0
3262 * \ 7|0 /
3263 * \ | /
3264 * 6 \|/ 1
3265 * 5-----+-----1
3266 * 5 /|\ 2
3267 * / | \
3268 * / 4|3 \
3269 * 4 3 2
3270 */
3271 octants[0] = x<w && y>0 ? state->map->map[wh*LE+(y-1)*w+x] : -1;
3272 octants[1] = x<w && y>0 ? state->map->map[wh*BE+(y-1)*w+x] : -1;
3273 octants[2] = x<w && y<h ? state->map->map[wh*TE+y*w+x] : -1;
3274 octants[3] = x<w && y<h ? state->map->map[wh*LE+y*w+x] : -1;
3275 octants[4] = x>0 && y<h ? state->map->map[wh*RE+y*w+(x-1)] : -1;
3276 octants[5] = x>0 && y<h ? state->map->map[wh*TE+y*w+(x-1)] : -1;
3277 octants[6] = x>0 && y>0 ? state->map->map[wh*BE+(y-1)*w+(x-1)] :-1;
3278 octants[7] = x>0 && y>0 ? state->map->map[wh*RE+(y-1)*w+(x-1)] :-1;
3279
3280 d1 = d2 = -1;
3281 for (i = 0; i < 8; i++)
3282 if ((octants[i] == r) ^ (octants[(i+1)%8] == r)) {
3283 assert(d2 == -1);
3284 if (d1 == -1)
3285 d1 = i;
3286 else
3287 d2 = i;
3288 }
3289
3290 assert(d1 != -1 && d2 != -1);
3291 if (d1 == lastdir)
3292 d1 = d2;
3293
3294 /*
3295 * Now we're heading in direction d1. Save the current
3296 * coordinates.
3297 */
3298 if (ncoords + 2 > coordsize) {
3299 coordsize += 128;
3300 coords = sresize(coords, coordsize, int);
3301 }
3302 coords[ncoords++] = COORD(x);
3303 coords[ncoords++] = COORD(y);
3304
3305 /*
3306 * Compute the new coordinates.
3307 */
3308 x += (d1 % 4 == 3 ? 0 : d1 < 4 ? +1 : -1);
3309 y += (d1 % 4 == 1 ? 0 : d1 > 1 && d1 < 5 ? +1 : -1);
3310 assert(x >= 0 && x <= w && y >= 0 && y <= h);
3311
3312 lastdir = d1 ^ 4;
3313 } while (x != ox || y != oy);
3314
3315 draw_polygon(dr, coords, ncoords/2,
3316 state->colouring[r] >= 0 ?
3317 c[state->colouring[r]] : -1, ink);
3318 }
3319 sfree(coords);
3320}
3321
3322#ifdef COMBINED
3323#define thegame map
3324#endif
3325
3326const struct game thegame = {
3327 "Map", "games.map", "map",
3328 default_params,
3329 game_fetch_preset, NULL,
3330 decode_params,
3331 encode_params,
3332 free_params,
3333 dup_params,
3334 true, game_configure, custom_params,
3335 validate_params,
3336 new_game_desc,
3337 validate_desc,
3338 new_game,
3339 dup_game,
3340 free_game,
3341 true, solve_game,
3342 false, NULL, NULL, /* can_format_as_text_now, text_format */
3343 get_prefs, set_prefs,
3344 new_ui,
3345 free_ui,
3346 NULL, /* encode_ui */
3347 NULL, /* decode_ui */
3348 NULL, /* game_request_keys */
3349 game_changed_state,
3350 current_key_label,
3351 interpret_move,
3352 execute_move,
3353 20, game_compute_size, game_set_size,
3354 game_colours,
3355 game_new_drawstate,
3356 game_free_drawstate,
3357 game_redraw,
3358 game_anim_length,
3359 game_flash_length,
3360 game_get_cursor_location,
3361 game_status,
3362 true, true, game_print_size, game_print,
3363 false, /* wants_statusbar */
3364 false, NULL, /* timing_state */
3365 0, /* flags */
3366};
3367
3368#ifdef STANDALONE_SOLVER
3369
3370int main(int argc, char **argv)
3371{
3372 game_params *p;
3373 game_state *s;
3374 char *id = NULL, *desc;
3375 const char *err;
3376 bool grade = false;
3377 int ret, diff;
3378 bool really_verbose = false;
3379 struct solver_scratch *sc;
3380 int i;
3381
3382 while (--argc > 0) {
3383 char *p = *++argv;
3384 if (!strcmp(p, "-v")) {
3385 really_verbose = true;
3386 } else if (!strcmp(p, "-g")) {
3387 grade = true;
3388 } else if (*p == '-') {
3389 fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
3390 return 1;
3391 } else {
3392 id = p;
3393 }
3394 }
3395
3396 if (!id) {
3397 fprintf(stderr, "usage: %s [-g | -v] <game_id>\n", argv[0]);
3398 return 1;
3399 }
3400
3401 desc = strchr(id, ':');
3402 if (!desc) {
3403 fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
3404 return 1;
3405 }
3406 *desc++ = '\0';
3407
3408 p = default_params();
3409 decode_params(p, id);
3410 err = validate_desc(p, desc);
3411 if (err) {
3412 fprintf(stderr, "%s: %s\n", argv[0], err);
3413 return 1;
3414 }
3415 s = new_game(NULL, p, desc);
3416
3417 sc = new_scratch(s->map->graph, s->map->n, s->map->ngraph);
3418
3419 /*
3420 * When solving an Easy puzzle, we don't want to bother the
3421 * user with Hard-level deductions. For this reason, we grade
3422 * the puzzle internally before doing anything else.
3423 */
3424 ret = -1; /* placate optimiser */
3425 for (diff = 0; diff < DIFFCOUNT; diff++) {
3426 for (i = 0; i < s->map->n; i++)
3427 if (!s->map->immutable[i])
3428 s->colouring[i] = -1;
3429 ret = map_solver(sc, s->map->graph, s->map->n, s->map->ngraph,
3430 s->colouring, diff);
3431 if (ret < 2)
3432 break;
3433 }
3434
3435 if (diff == DIFFCOUNT) {
3436 if (grade)
3437 printf("Difficulty rating: harder than Hard, or ambiguous\n");
3438 else
3439 printf("Unable to find a unique solution\n");
3440 } else {
3441 if (grade) {
3442 if (ret == 0)
3443 printf("Difficulty rating: impossible (no solution exists)\n");
3444 else if (ret == 1)
3445 printf("Difficulty rating: %s\n", map_diffnames[diff]);
3446 } else {
3447 verbose = really_verbose;
3448 for (i = 0; i < s->map->n; i++)
3449 if (!s->map->immutable[i])
3450 s->colouring[i] = -1;
3451 ret = map_solver(sc, s->map->graph, s->map->n, s->map->ngraph,
3452 s->colouring, diff);
3453 if (ret == 0)
3454 printf("Puzzle is inconsistent\n");
3455 else {
3456 int col = 0;
3457
3458 for (i = 0; i < s->map->n; i++) {
3459 printf("%5d <- %c%c", i, colnames[s->colouring[i]],
3460 (col < 6 && i+1 < s->map->n ? ' ' : '\n'));
3461 if (++col == 7)
3462 col = 0;
3463 }
3464 }
3465 }
3466 }
3467
3468 return 0;
3469}
3470
3471#endif
3472
3473/* vim: set shiftwidth=4 tabstop=8: */