A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 3473 lines 96 kB view raw
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: */