A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 2264 lines 58 kB view raw
1/* 2 * towers.c: the puzzle also known as 'Skyscrapers'. 3 * 4 * Possible future work: 5 * 6 * - Relax the upper bound on grid size at 9? 7 * + I'd need TOCHAR and FROMCHAR macros a bit like group's, to 8 * be used wherever this code has +'0' or -'0' 9 * + the pencil marks in the drawstate would need a separate 10 * word to live in 11 * + the clues outside the grid would have to cope with being 12 * multi-digit, meaning in particular that the text formatting 13 * would become more unpleasant 14 * + most importantly, though, the solver just isn't fast 15 * enough. Even at size 9 it can't really do the solver_hard 16 * factorial-time enumeration at a sensible rate. Easy puzzles 17 * higher than that would be possible, but more latin-squarey 18 * than skyscrapery, as it were. 19 */ 20 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include <assert.h> 25#include <ctype.h> 26#ifdef NO_TGMATH_H 27# include <math.h> 28#else 29# include <tgmath.h> 30#endif 31 32#include "puzzles.h" 33#include "latin.h" 34 35/* 36 * Difficulty levels. I do some macro ickery here to ensure that my 37 * enum and the various forms of my name list always match up. 38 */ 39#define DIFFLIST(A) \ 40 A(EASY,Easy,solver_easy,e) \ 41 A(HARD,Hard,solver_hard,h) \ 42 A(EXTREME,Extreme,NULL,x) \ 43 A(UNREASONABLE,Unreasonable,NULL,u) 44#define ENUM(upper,title,func,lower) DIFF_ ## upper, 45#define TITLE(upper,title,func,lower) #title, 46#define ENCODE(upper,title,func,lower) #lower 47#define CONFIG(upper,title,func,lower) ":" #title 48enum { DIFFLIST(ENUM) DIFFCOUNT }; 49static char const *const towers_diffnames[] = { DIFFLIST(TITLE) }; 50static char const towers_diffchars[] = DIFFLIST(ENCODE); 51#define DIFFCONFIG DIFFLIST(CONFIG) 52 53enum { 54 COL_BACKGROUND, 55 COL_GRID, 56 COL_USER, 57 COL_HIGHLIGHT, 58 COL_ERROR, 59 COL_PENCIL, 60 COL_DONE, 61 NCOLOURS 62}; 63 64enum { 65 PREF_PENCIL_KEEP_HIGHLIGHT, 66 PREF_APPEARANCE, 67 N_PREF_ITEMS 68}; 69 70struct game_params { 71 int w, diff; 72}; 73 74struct clues { 75 int refcount; 76 int w; 77 /* 78 * An array of 4w integers, of which: 79 * - the first w run across the top 80 * - the next w across the bottom 81 * - the third w down the left 82 * - the last w down the right. 83 */ 84 int *clues; 85 86 /* 87 * An array of w*w digits. 88 */ 89 digit *immutable; 90}; 91 92/* 93 * Macros to compute clue indices and coordinates. 94 */ 95#define STARTSTEP(start, step, index, w) do { \ 96 if (index < w) \ 97 start = index, step = w; \ 98 else if (index < 2*w) \ 99 start = (w-1)*w+(index-w), step = -w; \ 100 else if (index < 3*w) \ 101 start = w*(index-2*w), step = 1; \ 102 else \ 103 start = w*(index-3*w)+(w-1), step = -1; \ 104} while (0) 105#define CSTARTSTEP(start, step, index, w) \ 106 STARTSTEP(start, step, (((index)+2*w)%(4*w)), w) 107#define CLUEPOS(x, y, index, w) do { \ 108 if (index < w) \ 109 x = index, y = -1; \ 110 else if (index < 2*w) \ 111 x = index-w, y = w; \ 112 else if (index < 3*w) \ 113 x = -1, y = index-2*w; \ 114 else \ 115 x = w, y = index-3*w; \ 116} while (0) 117 118#ifdef STANDALONE_SOLVER 119static const char *const cluepos[] = { 120 "above column", "below column", "left of row", "right of row" 121}; 122#endif 123 124struct game_state { 125 game_params par; 126 struct clues *clues; 127 bool *clues_done; 128 digit *grid; 129 int *pencil; /* bitmaps using bits 1<<1..1<<n */ 130 bool completed, cheated; 131}; 132 133static game_params *default_params(void) 134{ 135 game_params *ret = snew(game_params); 136 137 ret->w = 5; 138 ret->diff = DIFF_EASY; 139 140 return ret; 141} 142 143static const struct game_params towers_presets[] = { 144 { 4, DIFF_EASY }, 145 { 5, DIFF_EASY }, 146 { 5, DIFF_HARD }, 147 { 6, DIFF_EASY }, 148 { 6, DIFF_HARD }, 149 { 6, DIFF_EXTREME }, 150 { 6, DIFF_UNREASONABLE }, 151}; 152 153static bool game_fetch_preset(int i, char **name, game_params **params) 154{ 155 game_params *ret; 156 char buf[80]; 157 158 if (i < 0 || i >= lenof(towers_presets)) 159 return false; 160 161 ret = snew(game_params); 162 *ret = towers_presets[i]; /* structure copy */ 163 164 sprintf(buf, "%dx%d %s", ret->w, ret->w, towers_diffnames[ret->diff]); 165 166 *name = dupstr(buf); 167 *params = ret; 168 return true; 169} 170 171static void free_params(game_params *params) 172{ 173 sfree(params); 174} 175 176static game_params *dup_params(const game_params *params) 177{ 178 game_params *ret = snew(game_params); 179 *ret = *params; /* structure copy */ 180 return ret; 181} 182 183static void decode_params(game_params *params, char const *string) 184{ 185 char const *p = string; 186 187 params->w = atoi(p); 188 while (*p && isdigit((unsigned char)*p)) p++; 189 190 if (*p == 'd') { 191 int i; 192 p++; 193 params->diff = DIFFCOUNT+1; /* ...which is invalid */ 194 if (*p) { 195 for (i = 0; i < DIFFCOUNT; i++) { 196 if (*p == towers_diffchars[i]) 197 params->diff = i; 198 } 199 p++; 200 } 201 } 202} 203 204static char *encode_params(const game_params *params, bool full) 205{ 206 char ret[80]; 207 208 sprintf(ret, "%d", params->w); 209 if (full) 210 sprintf(ret + strlen(ret), "d%c", towers_diffchars[params->diff]); 211 212 return dupstr(ret); 213} 214 215static config_item *game_configure(const game_params *params) 216{ 217 config_item *ret; 218 char buf[80]; 219 220 ret = snewn(3, config_item); 221 222 ret[0].name = "Grid size"; 223 ret[0].type = C_STRING; 224 sprintf(buf, "%d", params->w); 225 ret[0].u.string.sval = dupstr(buf); 226 227 ret[1].name = "Difficulty"; 228 ret[1].type = C_CHOICES; 229 ret[1].u.choices.choicenames = DIFFCONFIG; 230 ret[1].u.choices.selected = params->diff; 231 232 ret[2].name = NULL; 233 ret[2].type = C_END; 234 235 return ret; 236} 237 238static game_params *custom_params(const config_item *cfg) 239{ 240 game_params *ret = snew(game_params); 241 242 ret->w = atoi(cfg[0].u.string.sval); 243 ret->diff = cfg[1].u.choices.selected; 244 245 return ret; 246} 247 248static const char *validate_params(const game_params *params, bool full) 249{ 250 if (params->w < 3 || params->w > 9) 251 return "Grid size must be between 3 and 9"; 252 if (params->diff >= DIFFCOUNT) 253 return "Unknown difficulty rating"; 254 return NULL; 255} 256 257/* ---------------------------------------------------------------------- 258 * Solver. 259 */ 260 261struct solver_ctx { 262 int w, diff; 263 bool started; 264 int *clues; 265 long *iscratch; 266 int *dscratch; 267}; 268 269static int solver_easy(struct latin_solver *solver, void *vctx) 270{ 271 struct solver_ctx *ctx = (struct solver_ctx *)vctx; 272 int w = ctx->w; 273 int c, i, j, n, m, furthest; 274 int start, step, cstart, cstep, clue, pos, cpos; 275 int ret = 0; 276#ifdef STANDALONE_SOLVER 277 char prefix[256]; 278#endif 279 280 if (!ctx->started) { 281 ctx->started = true; 282 /* 283 * One-off loop to help get started: when a pair of facing 284 * clues sum to w+1, it must mean that the row consists of 285 * two increasing sequences back to back, so we can 286 * immediately place the highest digit by knowing the 287 * lengths of those two sequences. 288 */ 289 for (c = 0; c < 3*w; c = (c == w-1 ? 2*w : c+1)) { 290 int c2 = c + w; 291 292 if (ctx->clues[c] && ctx->clues[c2] && 293 ctx->clues[c] + ctx->clues[c2] == w+1) { 294 STARTSTEP(start, step, c, w); 295 CSTARTSTEP(cstart, cstep, c, w); 296 pos = start + (ctx->clues[c]-1)*step; 297 cpos = cstart + (ctx->clues[c]-1)*cstep; 298 if (solver->cube[cpos*w+w-1]) { 299#ifdef STANDALONE_SOLVER 300 if (solver_show_working) { 301 printf("%*sfacing clues on %s %d are maximal:\n", 302 solver_recurse_depth*4, "", 303 c>=2*w ? "row" : "column", c % w + 1); 304 printf("%*s placing %d at (%d,%d)\n", 305 solver_recurse_depth*4, "", 306 w, pos%w+1, pos/w+1); 307 } 308#endif 309 latin_solver_place(solver, pos%w, pos/w, w); 310 ret = 1; 311 } else { 312 ret = -1; 313 } 314 } 315 } 316 317 if (ret) 318 return ret; 319 } 320 321 /* 322 * Go over every clue doing reasonably simple heuristic 323 * deductions. 324 */ 325 for (c = 0; c < 4*w; c++) { 326 clue = ctx->clues[c]; 327 if (!clue) 328 continue; 329 STARTSTEP(start, step, c, w); 330 CSTARTSTEP(cstart, cstep, c, w); 331 332 /* Find the location of each number in the row. */ 333 for (i = 0; i < w; i++) 334 ctx->dscratch[i] = w; 335 for (i = 0; i < w; i++) 336 if (solver->grid[start+i*step]) 337 ctx->dscratch[solver->grid[start+i*step]-1] = i; 338 339 n = m = 0; 340 furthest = w; 341 for (i = w; i >= 1; i--) { 342 if (ctx->dscratch[i-1] == w) { 343 break; 344 } else if (ctx->dscratch[i-1] < furthest) { 345 furthest = ctx->dscratch[i-1]; 346 m = i; 347 n++; 348 } 349 } 350 if (clue == n+1 && furthest > 1) { 351#ifdef STANDALONE_SOLVER 352 if (solver_show_working) 353 sprintf(prefix, "%*sclue %s %d is nearly filled:\n", 354 solver_recurse_depth*4, "", 355 cluepos[c/w], c%w+1); 356 else 357 prefix[0] = '\0'; /* placate optimiser */ 358#endif 359 /* 360 * We can already see an increasing sequence of the very 361 * highest numbers, of length one less than that 362 * specified in the clue. All of those numbers _must_ be 363 * part of the clue sequence, so the number right next 364 * to the clue must be the final one - i.e. it must be 365 * bigger than any of the numbers between it and m. This 366 * allows us to rule out small numbers in that square. 367 * 368 * (This is a generalisation of the obvious deduction 369 * that when you see a clue saying 1, it must be right 370 * next to the largest possible number; and similarly, 371 * when you see a clue saying 2 opposite that, it must 372 * be right next to the second-largest.) 373 */ 374 j = furthest-1; /* number of small numbers we can rule out */ 375 for (i = 1; i <= w && j > 0; i++) { 376 if (ctx->dscratch[i-1] < w && ctx->dscratch[i-1] >= furthest) 377 continue; /* skip this number, it's elsewhere */ 378 j--; 379 if (solver->cube[cstart*w+i-1]) { 380#ifdef STANDALONE_SOLVER 381 if (solver_show_working) { 382 printf("%s%*s ruling out %d at (%d,%d)\n", 383 prefix, solver_recurse_depth*4, "", 384 i, start%w+1, start/w+1); 385 prefix[0] = '\0'; 386 } 387#endif 388 solver->cube[cstart*w+i-1] = 0; 389 ret = 1; 390 } 391 } 392 } 393 394 if (ret) 395 return ret; 396 397#ifdef STANDALONE_SOLVER 398 if (solver_show_working) 399 sprintf(prefix, "%*slower bounds for clue %s %d:\n", 400 solver_recurse_depth*4, "", 401 cluepos[c/w], c%w+1); 402 else 403 prefix[0] = '\0'; /* placate optimiser */ 404#endif 405 406 i = 0; 407 for (n = w; n > 0; n--) { 408 /* 409 * The largest number cannot occur in the first (clue-1) 410 * squares of the row, or else there wouldn't be space 411 * for a sufficiently long increasing sequence which it 412 * terminated. The second-largest number (not counting 413 * any that are known to be on the far side of a larger 414 * number and hence excluded from this sequence) cannot 415 * occur in the first (clue-2) squares, similarly, and 416 * so on. 417 */ 418 419 if (ctx->dscratch[n-1] < w) { 420 for (m = n+1; m < w; m++) 421 if (ctx->dscratch[m] < ctx->dscratch[n-1]) 422 break; 423 if (m < w) 424 continue; /* this number doesn't count */ 425 } 426 427 for (j = 0; j < clue - i - 1; j++) 428 if (solver->cube[(cstart + j*cstep)*w+n-1]) { 429#ifdef STANDALONE_SOLVER 430 if (solver_show_working) { 431 int pos = start+j*step; 432 printf("%s%*s ruling out %d at (%d,%d)\n", 433 prefix, solver_recurse_depth*4, "", 434 n, pos%w+1, pos/w+1); 435 prefix[0] = '\0'; 436 } 437#endif 438 solver->cube[(cstart + j*cstep)*w+n-1] = 0; 439 ret = 1; 440 } 441 i++; 442 } 443 } 444 445 if (ret) 446 return ret; 447 448 return 0; 449} 450 451static int solver_hard(struct latin_solver *solver, void *vctx) 452{ 453 struct solver_ctx *ctx = (struct solver_ctx *)vctx; 454 int w = ctx->w; 455 int c, i, j, n, best, clue, start, step, ret; 456 long bitmap; 457#ifdef STANDALONE_SOLVER 458 char prefix[256]; 459#endif 460 461 /* 462 * Go over every clue analysing all possibilities. 463 */ 464 for (c = 0; c < 4*w; c++) { 465 clue = ctx->clues[c]; 466 if (!clue) 467 continue; 468 CSTARTSTEP(start, step, c, w); 469 470 for (i = 0; i < w; i++) 471 ctx->iscratch[i] = 0; 472 473 /* 474 * Instead of a tedious physical recursion, I iterate in the 475 * scratch array through all possibilities. At any given 476 * moment, i indexes the element of the box that will next 477 * be incremented. 478 */ 479 i = 0; 480 ctx->dscratch[i] = 0; 481 best = n = 0; 482 bitmap = 0; 483 484 while (1) { 485 if (i < w) { 486 /* 487 * Find the next valid value for cell i. 488 */ 489 int limit = (n == clue ? best : w); 490 int pos = start + step * i; 491 for (j = ctx->dscratch[i] + 1; j <= limit; j++) { 492 if (bitmap & (1L << j)) 493 continue; /* used this one already */ 494 if (!solver->cube[pos*w+j-1]) 495 continue; /* ruled out already */ 496 497 /* Found one. */ 498 break; 499 } 500 501 if (j > limit) { 502 /* No valid values left; drop back. */ 503 i--; 504 if (i < 0) 505 break; /* overall iteration is finished */ 506 bitmap &= ~(1L << ctx->dscratch[i]); 507 if (ctx->dscratch[i] == best) { 508 n--; 509 best = 0; 510 for (j = 0; j < i; j++) 511 if (best < ctx->dscratch[j]) 512 best = ctx->dscratch[j]; 513 } 514 } else { 515 /* Got a valid value; store it and move on. */ 516 bitmap |= 1L << j; 517 ctx->dscratch[i++] = j; 518 if (j > best) { 519 best = j; 520 n++; 521 } 522 ctx->dscratch[i] = 0; 523 } 524 } else { 525 if (n == clue) { 526 for (j = 0; j < w; j++) 527 ctx->iscratch[j] |= 1L << ctx->dscratch[j]; 528 } 529 i--; 530 bitmap &= ~(1L << ctx->dscratch[i]); 531 if (ctx->dscratch[i] == best) { 532 n--; 533 best = 0; 534 for (j = 0; j < i; j++) 535 if (best < ctx->dscratch[j]) 536 best = ctx->dscratch[j]; 537 } 538 } 539 } 540 541#ifdef STANDALONE_SOLVER 542 if (solver_show_working) 543 sprintf(prefix, "%*sexhaustive analysis of clue %s %d:\n", 544 solver_recurse_depth*4, "", 545 cluepos[c/w], c%w+1); 546 else 547 prefix[0] = '\0'; /* placate optimiser */ 548#endif 549 550 ret = 0; 551 552 for (i = 0; i < w; i++) { 553 int pos = start + step * i; 554 for (j = 1; j <= w; j++) { 555 if (solver->cube[pos*w+j-1] && 556 !(ctx->iscratch[i] & (1L << j))) { 557#ifdef STANDALONE_SOLVER 558 if (solver_show_working) { 559 printf("%s%*s ruling out %d at (%d,%d)\n", 560 prefix, solver_recurse_depth*4, "", 561 j, pos/w+1, pos%w+1); 562 prefix[0] = '\0'; 563 } 564#endif 565 solver->cube[pos*w+j-1] = 0; 566 ret = 1; 567 } 568 } 569 570 /* 571 * Once we find one clue we can do something with in 572 * this way, revert to trying easier deductions, so as 573 * not to generate solver diagnostics that make the 574 * problem look harder than it is. 575 */ 576 if (ret) 577 return ret; 578 } 579 } 580 581 return 0; 582} 583 584#define SOLVER(upper,title,func,lower) func, 585static usersolver_t const towers_solvers[] = { DIFFLIST(SOLVER) }; 586 587static bool towers_valid(struct latin_solver *solver, void *vctx) 588{ 589 struct solver_ctx *ctx = (struct solver_ctx *)vctx; 590 int w = ctx->w; 591 int c, i, n, best, clue, start, step; 592 for (c = 0; c < 4*w; c++) { 593 clue = ctx->clues[c]; 594 if (!clue) 595 continue; 596 597 STARTSTEP(start, step, c, w); 598 n = best = 0; 599 for (i = 0; i < w; i++) { 600 if (solver->grid[start+i*step] > best) { 601 best = solver->grid[start+i*step]; 602 n++; 603 } 604 } 605 606 if (n != clue) { 607#ifdef STANDALONE_SOLVER 608 if (solver_show_working) 609 printf("%*sclue %s %d is violated\n", 610 solver_recurse_depth*4, "", 611 cluepos[c/w], c%w+1); 612#endif 613 return false; 614 } 615 } 616 return true; 617} 618 619static int solver(int w, int *clues, digit *soln, int maxdiff) 620{ 621 int ret; 622 struct solver_ctx ctx; 623 624 ctx.w = w; 625 ctx.diff = maxdiff; 626 ctx.clues = clues; 627 ctx.started = false; 628 ctx.iscratch = snewn(w, long); 629 ctx.dscratch = snewn(w+1, int); 630 631 ret = latin_solver(soln, w, maxdiff, 632 DIFF_EASY, DIFF_HARD, DIFF_EXTREME, 633 DIFF_EXTREME, DIFF_UNREASONABLE, 634 towers_solvers, towers_valid, &ctx, NULL, NULL); 635 636 sfree(ctx.iscratch); 637 sfree(ctx.dscratch); 638 639 return ret; 640} 641 642/* ---------------------------------------------------------------------- 643 * Grid generation. 644 */ 645 646static char *new_game_desc(const game_params *params, random_state *rs, 647 char **aux, bool interactive) 648{ 649 int w = params->w, a = w*w; 650 digit *grid, *soln, *soln2; 651 int *clues, *order; 652 int i, ret; 653 int diff = params->diff; 654 char *desc, *p; 655 656 /* 657 * Difficulty exceptions: some combinations of size and 658 * difficulty cannot be satisfied, because all puzzles of at 659 * most that difficulty are actually even easier. 660 * 661 * Remember to re-test this whenever a change is made to the 662 * solver logic! 663 * 664 * I tested it using the following shell command: 665 666for d in e h x u; do 667 for i in {3..9}; do 668 echo -n "./towers --generate 1 ${i}d${d}: " 669 perl -e 'alarm 30; exec @ARGV' ./towers --generate 1 ${i}d${d} >/dev/null \ 670 && echo ok 671 done 672done 673 674 * Of course, it's better to do that after taking the exceptions 675 * _out_, so as to detect exceptions that should be removed as 676 * well as those which should be added. 677 */ 678 if (diff > DIFF_HARD && w <= 3) 679 diff = DIFF_HARD; 680 681 grid = NULL; 682 clues = snewn(4*w, int); 683 soln = snewn(a, digit); 684 soln2 = snewn(a, digit); 685 order = snewn(max(4*w,a), int); 686 687 while (1) { 688 /* 689 * Construct a latin square to be the solution. 690 */ 691 sfree(grid); 692 grid = latin_generate(w, rs); 693 694 /* 695 * Fill in the clues. 696 */ 697 for (i = 0; i < 4*w; i++) { 698 int start, step, j, k, best; 699 STARTSTEP(start, step, i, w); 700 k = best = 0; 701 for (j = 0; j < w; j++) { 702 if (grid[start+j*step] > best) { 703 best = grid[start+j*step]; 704 k++; 705 } 706 } 707 clues[i] = k; 708 } 709 710 /* 711 * Remove the grid numbers and then the clues, one by one, 712 * for as long as the game remains soluble at the given 713 * difficulty. 714 */ 715 memcpy(soln, grid, a); 716 717 if (diff == DIFF_EASY && w <= 5) { 718 /* 719 * Special case: for Easy-mode grids that are small 720 * enough, it's nice to be able to find completely empty 721 * grids. 722 */ 723 memset(soln2, 0, a); 724 ret = solver(w, clues, soln2, diff); 725 if (ret > diff) 726 continue; 727 } 728 729 for (i = 0; i < a; i++) 730 order[i] = i; 731 shuffle(order, a, sizeof(*order), rs); 732 for (i = 0; i < a; i++) { 733 int j = order[i]; 734 735 memcpy(soln2, grid, a); 736 soln2[j] = 0; 737 ret = solver(w, clues, soln2, diff); 738 if (ret <= diff) 739 grid[j] = 0; 740 } 741 742 if (diff > DIFF_EASY) { /* leave all clues on Easy mode */ 743 for (i = 0; i < 4*w; i++) 744 order[i] = i; 745 shuffle(order, 4*w, sizeof(*order), rs); 746 for (i = 0; i < 4*w; i++) { 747 int j = order[i]; 748 int clue = clues[j]; 749 750 memcpy(soln2, grid, a); 751 clues[j] = 0; 752 ret = solver(w, clues, soln2, diff); 753 if (ret > diff) 754 clues[j] = clue; 755 } 756 } 757 758 /* 759 * See if the game can be solved at the specified difficulty 760 * level, but not at the one below. 761 */ 762 memcpy(soln2, grid, a); 763 ret = solver(w, clues, soln2, diff); 764 if (ret != diff) 765 continue; /* go round again */ 766 767 /* 768 * We've got a usable puzzle! 769 */ 770 break; 771 } 772 773 /* 774 * Encode the puzzle description. 775 */ 776 desc = snewn(40*a, char); 777 p = desc; 778 for (i = 0; i < 4*w; i++) { 779 if (i) 780 *p++ = '/'; 781 if (clues[i]) 782 p += sprintf(p, "%d", clues[i]); 783 } 784 for (i = 0; i < a; i++) 785 if (grid[i]) 786 break; 787 if (i < a) { 788 int run = 0; 789 790 *p++ = ','; 791 792 for (i = 0; i <= a; i++) { 793 int n = (i < a ? grid[i] : -1); 794 795 if (!n) 796 run++; 797 else { 798 if (run) { 799 while (run > 0) { 800 int thisrun = min(run, 26); 801 *p++ = thisrun - 1 + 'a'; 802 run -= thisrun; 803 } 804 } else { 805 /* 806 * If there's a number in the very top left or 807 * bottom right, there's no point putting an 808 * unnecessary _ before or after it. 809 */ 810 if (i > 0 && n > 0) 811 *p++ = '_'; 812 } 813 if (n > 0) 814 p += sprintf(p, "%d", n); 815 run = 0; 816 } 817 } 818 } 819 *p++ = '\0'; 820 desc = sresize(desc, p - desc, char); 821 822 /* 823 * Encode the solution. 824 */ 825 *aux = snewn(a+2, char); 826 (*aux)[0] = 'S'; 827 for (i = 0; i < a; i++) 828 (*aux)[i+1] = '0' + soln[i]; 829 (*aux)[a+1] = '\0'; 830 831 sfree(grid); 832 sfree(clues); 833 sfree(soln); 834 sfree(soln2); 835 sfree(order); 836 837 return desc; 838} 839 840/* ---------------------------------------------------------------------- 841 * Gameplay. 842 */ 843 844static const char *validate_desc(const game_params *params, const char *desc) 845{ 846 int w = params->w, a = w*w; 847 const char *p = desc; 848 int i, clue; 849 850 /* 851 * Verify that the right number of clues are given, and that 852 * they're in range. 853 */ 854 for (i = 0; i < 4*w; i++) { 855 if (!*p) 856 return "Too few clues for grid size"; 857 858 if (i > 0) { 859 if (*p != '/') 860 return "Expected commas between clues"; 861 p++; 862 } 863 864 if (isdigit((unsigned char)*p)) { 865 clue = atoi(p); 866 while (*p && isdigit((unsigned char)*p)) p++; 867 868 if (clue <= 0 || clue > w) 869 return "Clue number out of range"; 870 } 871 } 872 if (*p == '/') 873 return "Too many clues for grid size"; 874 875 if (*p == ',') { 876 /* 877 * Verify that the right amount of grid data is given, and 878 * that any grid elements provided are in range. 879 */ 880 int squares = 0; 881 882 p++; 883 while (*p) { 884 int c = *p++; 885 if (c >= 'a' && c <= 'z') { 886 squares += c - 'a' + 1; 887 } else if (c == '_') { 888 /* do nothing */; 889 } else if (c > '0' && c <= '9') { 890 int val = atoi(p-1); 891 if (val < 1 || val > w) 892 return "Out-of-range number in grid description"; 893 squares++; 894 while (*p && isdigit((unsigned char)*p)) p++; 895 } else 896 return "Invalid character in game description"; 897 } 898 899 if (squares < a) 900 return "Not enough data to fill grid"; 901 902 if (squares > a) 903 return "Too much data to fit in grid"; 904 } 905 906 if (*p) return "Rubbish at end of game description"; 907 return NULL; 908} 909 910static key_label *game_request_keys(const game_params *params, int *nkeys) 911{ 912 int i; 913 int w = params->w; 914 key_label *keys = snewn(w+1, key_label); 915 *nkeys = w + 1; 916 917 for (i = 0; i < w; i++) { 918 if (i<9) keys[i].button = '1' + i; 919 else keys[i].button = 'a' + i - 9; 920 921 keys[i].label = NULL; 922 } 923 keys[w].button = '\b'; 924 keys[w].label = NULL; 925 926 return keys; 927} 928 929static game_state *new_game(midend *me, const game_params *params, 930 const char *desc) 931{ 932 int w = params->w, a = w*w; 933 game_state *state = snew(game_state); 934 const char *p = desc; 935 int i; 936 937 state->par = *params; /* structure copy */ 938 state->clues = snew(struct clues); 939 state->clues->refcount = 1; 940 state->clues->w = w; 941 state->clues->clues = snewn(4*w, int); 942 state->clues->immutable = snewn(a, digit); 943 state->grid = snewn(a, digit); 944 state->clues_done = snewn(4*w, bool); 945 state->pencil = snewn(a, int); 946 947 for (i = 0; i < a; i++) { 948 state->grid[i] = 0; 949 state->pencil[i] = 0; 950 } 951 952 memset(state->clues->immutable, 0, a); 953 memset(state->clues_done, 0, 4*w*sizeof(bool)); 954 955 for (i = 0; i < 4*w; i++) { 956 if (i > 0) { 957 assert(*p == '/'); 958 p++; 959 } 960 if (*p && isdigit((unsigned char)*p)) { 961 state->clues->clues[i] = atoi(p); 962 while (*p && isdigit((unsigned char)*p)) p++; 963 } else 964 state->clues->clues[i] = 0; 965 } 966 967 if (*p == ',') { 968 int pos = 0; 969 p++; 970 while (*p) { 971 int c = *p++; 972 if (c >= 'a' && c <= 'z') { 973 pos += c - 'a' + 1; 974 } else if (c == '_') { 975 /* do nothing */; 976 } else if (c > '0' && c <= '9') { 977 int val = atoi(p-1); 978 assert(val >= 1 && val <= w); 979 assert(pos < a); 980 state->grid[pos] = state->clues->immutable[pos] = val; 981 pos++; 982 while (*p && isdigit((unsigned char)*p)) p++; 983 } else 984 assert(!"Corrupt game description"); 985 } 986 assert(pos == a); 987 } 988 assert(!*p); 989 990 state->completed = false; 991 state->cheated = false; 992 993 return state; 994} 995 996static game_state *dup_game(const game_state *state) 997{ 998 int w = state->par.w, a = w*w; 999 game_state *ret = snew(game_state); 1000 1001 ret->par = state->par; /* structure copy */ 1002 1003 ret->clues = state->clues; 1004 ret->clues->refcount++; 1005 1006 ret->grid = snewn(a, digit); 1007 ret->pencil = snewn(a, int); 1008 ret->clues_done = snewn(4*w, bool); 1009 memcpy(ret->grid, state->grid, a*sizeof(digit)); 1010 memcpy(ret->pencil, state->pencil, a*sizeof(int)); 1011 memcpy(ret->clues_done, state->clues_done, 4*w*sizeof(bool)); 1012 1013 ret->completed = state->completed; 1014 ret->cheated = state->cheated; 1015 1016 return ret; 1017} 1018 1019static void free_game(game_state *state) 1020{ 1021 sfree(state->grid); 1022 sfree(state->pencil); 1023 sfree(state->clues_done); 1024 if (--state->clues->refcount <= 0) { 1025 sfree(state->clues->immutable); 1026 sfree(state->clues->clues); 1027 sfree(state->clues); 1028 } 1029 sfree(state); 1030} 1031 1032static char *solve_game(const game_state *state, const game_state *currstate, 1033 const char *aux, const char **error) 1034{ 1035 int w = state->par.w, a = w*w; 1036 int i, ret; 1037 digit *soln; 1038 char *out; 1039 1040 if (aux) 1041 return dupstr(aux); 1042 1043 soln = snewn(a, digit); 1044 memcpy(soln, state->clues->immutable, a); 1045 1046 ret = solver(w, state->clues->clues, soln, DIFFCOUNT-1); 1047 1048 if (ret == diff_impossible) { 1049 *error = "No solution exists for this puzzle"; 1050 out = NULL; 1051 } else if (ret == diff_ambiguous) { 1052 *error = "Multiple solutions exist for this puzzle"; 1053 out = NULL; 1054 } else { 1055 out = snewn(a+2, char); 1056 out[0] = 'S'; 1057 for (i = 0; i < a; i++) 1058 out[i+1] = '0' + soln[i]; 1059 out[a+1] = '\0'; 1060 } 1061 1062 sfree(soln); 1063 return out; 1064} 1065 1066static bool game_can_format_as_text_now(const game_params *params) 1067{ 1068 return true; 1069} 1070 1071static char *game_text_format(const game_state *state) 1072{ 1073 int w = state->par.w /* , a = w*w */; 1074 char *ret; 1075 char *p; 1076 int x, y; 1077 int total; 1078 1079 /* 1080 * We have: 1081 * - a top clue row, consisting of three spaces, then w clue 1082 * digits with spaces between (total 2*w+3 chars including 1083 * newline) 1084 * - a blank line (one newline) 1085 * - w main rows, consisting of a left clue digit, two spaces, 1086 * w grid digits with spaces between, two spaces and a right 1087 * clue digit (total 2*w+6 chars each including newline) 1088 * - a blank line (one newline) 1089 * - a bottom clue row (same as top clue row) 1090 * - terminating NUL. 1091 * 1092 * Total size is therefore 2*(2*w+3) + 2 + w*(2*w+6) + 1 1093 * = 2w^2+10w+9. 1094 */ 1095 total = 2*w*w + 10*w + 9; 1096 ret = snewn(total, char); 1097 p = ret; 1098 1099 /* Top clue row. */ 1100 *p++ = ' '; *p++ = ' '; 1101 for (x = 0; x < w; x++) { 1102 *p++ = ' '; 1103 *p++ = (state->clues->clues[x] ? '0' + state->clues->clues[x] : ' '); 1104 } 1105 *p++ = '\n'; 1106 1107 /* Blank line. */ 1108 *p++ = '\n'; 1109 1110 /* Main grid. */ 1111 for (y = 0; y < w; y++) { 1112 *p++ = (state->clues->clues[y+2*w] ? '0' + state->clues->clues[y+2*w] : 1113 ' '); 1114 *p++ = ' '; 1115 for (x = 0; x < w; x++) { 1116 *p++ = ' '; 1117 *p++ = (state->grid[y*w+x] ? '0' + state->grid[y*w+x] : ' '); 1118 } 1119 *p++ = ' '; *p++ = ' '; 1120 *p++ = (state->clues->clues[y+3*w] ? '0' + state->clues->clues[y+3*w] : 1121 ' '); 1122 *p++ = '\n'; 1123 } 1124 1125 /* Blank line. */ 1126 *p++ = '\n'; 1127 1128 /* Bottom clue row. */ 1129 *p++ = ' '; *p++ = ' '; 1130 for (x = 0; x < w; x++) { 1131 *p++ = ' '; 1132 *p++ = (state->clues->clues[x+w] ? '0' + state->clues->clues[x+w] : 1133 ' '); 1134 } 1135 *p++ = '\n'; 1136 1137 *p++ = '\0'; 1138 assert(p == ret + total); 1139 1140 return ret; 1141} 1142 1143struct game_ui { 1144 /* 1145 * These are the coordinates of the currently highlighted 1146 * square on the grid, if hshow = 1. 1147 */ 1148 int hx, hy; 1149 /* 1150 * This indicates whether the current highlight is a 1151 * pencil-mark one or a real one. 1152 */ 1153 bool hpencil; 1154 /* 1155 * This indicates whether or not we're showing the highlight 1156 * (used to be hx = hy = -1); important so that when we're 1157 * using the cursor keys it doesn't keep coming back at a 1158 * fixed position. When hshow = 1, pressing a valid number 1159 * or letter key or Space will enter that number or letter in the grid. 1160 */ 1161 bool hshow; 1162 /* 1163 * This indicates whether we're using the highlight as a cursor; 1164 * it means that it doesn't vanish on a keypress, and that it is 1165 * allowed on immutable squares. 1166 */ 1167 bool hcursor; 1168 1169 /* 1170 * User preference option which can be set to FALSE to disable the 1171 * 3D graphical style, and instead just display the puzzle as if 1172 * it was a Sudoku variant, i.e. each square just has a digit in 1173 * it. 1174 * 1175 * I was initially a bit uncertain about whether the 3D style 1176 * would be the right thing, on the basis that it uses up space in 1177 * the cells and makes it hard to use many pencil marks. Actually 1178 * nobody seems to have complained, but having put in the option 1179 * while I was still being uncertain, it seems silly not to leave 1180 * it in just in case. 1181 */ 1182 int three_d; 1183 1184 /* 1185 * User preference option: if the user right-clicks in a square 1186 * and presses a number key to add/remove a pencil mark, do we 1187 * hide the mouse highlight again afterwards? 1188 * 1189 * Historically our answer was yes. The Android port prefers no. 1190 * There are advantages both ways, depending how much you dislike 1191 * the highlight cluttering your view. So it's a preference. 1192 */ 1193 bool pencil_keep_highlight; 1194}; 1195 1196static void legacy_prefs_override(struct game_ui *ui_out) 1197{ 1198 static bool initialised = false; 1199 static int three_d = -1; 1200 1201 if (!initialised) { 1202 initialised = true; 1203 three_d = getenv_bool("TOWERS_2D", -1); 1204 } 1205 1206 if (three_d != -1) 1207 ui_out->three_d = three_d; 1208} 1209 1210static game_ui *new_ui(const game_state *state) 1211{ 1212 game_ui *ui = snew(game_ui); 1213 1214 ui->hx = ui->hy = 0; 1215 ui->hpencil = false; 1216 ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false); 1217 1218 ui->three_d = true; 1219 ui->pencil_keep_highlight = false; 1220 legacy_prefs_override(ui); 1221 1222 return ui; 1223} 1224 1225static void free_ui(game_ui *ui) 1226{ 1227 sfree(ui); 1228} 1229 1230static config_item *get_prefs(game_ui *ui) 1231{ 1232 config_item *ret; 1233 1234 ret = snewn(N_PREF_ITEMS+1, config_item); 1235 1236 ret[PREF_PENCIL_KEEP_HIGHLIGHT].name = 1237 "Keep mouse highlight after changing a pencil mark"; 1238 ret[PREF_PENCIL_KEEP_HIGHLIGHT].kw = "pencil-keep-highlight"; 1239 ret[PREF_PENCIL_KEEP_HIGHLIGHT].type = C_BOOLEAN; 1240 ret[PREF_PENCIL_KEEP_HIGHLIGHT].u.boolean.bval = ui->pencil_keep_highlight; 1241 1242 ret[PREF_APPEARANCE].name = "Puzzle appearance"; 1243 ret[PREF_APPEARANCE].kw = "appearance"; 1244 ret[PREF_APPEARANCE].type = C_CHOICES; 1245 ret[PREF_APPEARANCE].u.choices.choicenames = ":2D:3D"; 1246 ret[PREF_APPEARANCE].u.choices.choicekws = ":2d:3d"; 1247 ret[PREF_APPEARANCE].u.choices.selected = ui->three_d; 1248 1249 ret[N_PREF_ITEMS].name = NULL; 1250 ret[N_PREF_ITEMS].type = C_END; 1251 1252 return ret; 1253} 1254 1255static void set_prefs(game_ui *ui, const config_item *cfg) 1256{ 1257 ui->pencil_keep_highlight = cfg[PREF_PENCIL_KEEP_HIGHLIGHT].u.boolean.bval; 1258 ui->three_d = cfg[PREF_APPEARANCE].u.choices.selected; 1259} 1260 1261static void game_changed_state(game_ui *ui, const game_state *oldstate, 1262 const game_state *newstate) 1263{ 1264 int w = newstate->par.w; 1265 /* 1266 * We prevent pencil-mode highlighting of a filled square, unless 1267 * we're using the cursor keys. So if the user has just filled in 1268 * a square which we had a pencil-mode highlight in (by Undo, or 1269 * by Redo, or by Solve), then we cancel the highlight. 1270 */ 1271 if (ui->hshow && ui->hpencil && !ui->hcursor && 1272 newstate->grid[ui->hy * w + ui->hx] != 0) { 1273 ui->hshow = false; 1274 } 1275} 1276 1277static const char *current_key_label(const game_ui *ui, 1278 const game_state *state, int button) 1279{ 1280 if (ui->hshow && (button == CURSOR_SELECT)) 1281 return ui->hpencil ? "Ink" : "Pencil"; 1282 return ""; 1283} 1284 1285#define PREFERRED_TILESIZE 48 1286#define TILESIZE (ds->tilesize) 1287#define BORDER (TILESIZE * 9 / 8) 1288#define COORD(x) ((x)*TILESIZE + BORDER) 1289#define FROMCOORD(x) (((x)+(TILESIZE-BORDER)) / TILESIZE - 1) 1290 1291/* These always return positive values, though y offsets are actually -ve */ 1292#define X_3D_DISP(height, w) ((height) * TILESIZE / (8 * (w))) 1293#define Y_3D_DISP(height, w) ((height) * TILESIZE / (4 * (w))) 1294 1295#define FLASH_TIME 0.4F 1296 1297#define DF_PENCIL_SHIFT 16 1298#define DF_CLUE_DONE 0x10000 1299#define DF_ERROR 0x8000 1300#define DF_HIGHLIGHT 0x4000 1301#define DF_HIGHLIGHT_PENCIL 0x2000 1302#define DF_IMMUTABLE 0x1000 1303#define DF_PLAYAREA 0x0800 1304#define DF_DIGIT_MASK 0x00FF 1305 1306struct game_drawstate { 1307 int tilesize; 1308 long *tiles; /* (w+2)*(w+2) temp space */ 1309 long *drawn; /* (w+2)*(w+2)*4: current drawn data */ 1310 bool *errtmp; 1311}; 1312 1313static bool check_errors(const game_state *state, bool *errors) 1314{ 1315 int w = state->par.w /*, a = w*w */; 1316 int W = w+2, A = W*W; /* the errors array is (w+2) square */ 1317 int *clues = state->clues->clues; 1318 digit *grid = state->grid; 1319 int i, x, y; 1320 bool errs = false; 1321 int tmp[32]; 1322 1323 assert(w < lenof(tmp)); 1324 1325 if (errors) 1326 for (i = 0; i < A; i++) 1327 errors[i] = false; 1328 1329 for (y = 0; y < w; y++) { 1330 unsigned long mask = 0, errmask = 0; 1331 for (x = 0; x < w; x++) { 1332 unsigned long bit = 1UL << grid[y*w+x]; 1333 errmask |= (mask & bit); 1334 mask |= bit; 1335 } 1336 1337 if (mask != (1L << (w+1)) - (1L << 1)) { 1338 errs = true; 1339 errmask &= ~1UL; 1340 if (errors) { 1341 for (x = 0; x < w; x++) 1342 if (errmask & (1UL << grid[y*w+x])) 1343 errors[(y+1)*W+(x+1)] = true; 1344 } 1345 } 1346 } 1347 1348 for (x = 0; x < w; x++) { 1349 unsigned long mask = 0, errmask = 0; 1350 for (y = 0; y < w; y++) { 1351 unsigned long bit = 1UL << grid[y*w+x]; 1352 errmask |= (mask & bit); 1353 mask |= bit; 1354 } 1355 1356 if (mask != (1 << (w+1)) - (1 << 1)) { 1357 errs = true; 1358 errmask &= ~1UL; 1359 if (errors) { 1360 for (y = 0; y < w; y++) 1361 if (errmask & (1UL << grid[y*w+x])) 1362 errors[(y+1)*W+(x+1)] = true; 1363 } 1364 } 1365 } 1366 1367 for (i = 0; i < 4*w; i++) { 1368 int start, step, j, n, best; 1369 STARTSTEP(start, step, i, w); 1370 1371 if (!clues[i]) 1372 continue; 1373 1374 best = n = 0; 1375 for (j = 0; j < w; j++) { 1376 int number = grid[start+j*step]; 1377 if (!number) 1378 break; /* can't tell what happens next */ 1379 if (number > best) { 1380 best = number; 1381 n++; 1382 } 1383 } 1384 1385 if (n > clues[i] || (best == w && n < clues[i]) || 1386 (best < w && n == clues[i])) { 1387 if (errors) { 1388 int x, y; 1389 CLUEPOS(x, y, i, w); 1390 errors[(y+1)*W+(x+1)] = true; 1391 } 1392 errs = true; 1393 } 1394 } 1395 1396 return errs; 1397} 1398 1399static int clue_index(const game_state *state, int x, int y) 1400{ 1401 int w = state->par.w; 1402 1403 if (x == -1 || x == w) 1404 return w * (x == -1 ? 2 : 3) + y; 1405 else if (y == -1 || y == w) 1406 return (y == -1 ? 0 : w) + x; 1407 1408 return -1; 1409} 1410 1411static bool is_clue(const game_state *state, int x, int y) 1412{ 1413 int w = state->par.w; 1414 1415 if (((x == -1 || x == w) && y >= 0 && y < w) || 1416 ((y == -1 || y == w) && x >= 0 && x < w)) 1417 { 1418 if (state->clues->clues[clue_index(state, x, y)] & DF_DIGIT_MASK) 1419 return true; 1420 } 1421 1422 return false; 1423} 1424 1425static char *interpret_move(const game_state *state, game_ui *ui, 1426 const game_drawstate *ds, 1427 int x, int y, int button) 1428{ 1429 int w = state->par.w; 1430 bool shift_or_control = button & (MOD_SHFT | MOD_CTRL); 1431 int tx, ty; 1432 char buf[80]; 1433 1434 button = STRIP_BUTTON_MODIFIERS(button); 1435 1436 tx = FROMCOORD(x); 1437 ty = FROMCOORD(y); 1438 1439 if (ui->three_d) { 1440 /* 1441 * In 3D mode, just locating the mouse click in the natural 1442 * square grid may not be sufficient to tell which tower the 1443 * user clicked on. Investigate the _tops_ of the nearby 1444 * towers to see if a click on one grid square was actually 1445 * a click on a tower protruding into that region from 1446 * another. 1447 */ 1448 int dx, dy; 1449 for (dy = 0; dy <= 1; dy++) 1450 for (dx = 0; dx >= -1; dx--) { 1451 int cx = tx + dx, cy = ty + dy; 1452 if (cx >= 0 && cx < w && cy >= 0 && cy < w) { 1453 int height = state->grid[cy*w+cx]; 1454 int bx = COORD(cx), by = COORD(cy); 1455 int ox = bx + X_3D_DISP(height, w); 1456 int oy = by - Y_3D_DISP(height, w); 1457 if (/* on top face? */ 1458 (x - ox >= 0 && x - ox < TILESIZE && 1459 y - oy >= 0 && y - oy < TILESIZE) || 1460 /* in triangle between top-left corners? */ 1461 (ox > bx && x >= bx && x <= ox && y <= by && 1462 (by-y) * (ox-bx) <= (by-oy) * (x-bx)) || 1463 /* in triangle between bottom-right corners? */ 1464 (ox > bx && x >= bx+TILESIZE && x <= ox+TILESIZE && 1465 y >= oy+TILESIZE && 1466 (by-y+TILESIZE)*(ox-bx) >= (by-oy)*(x-bx-TILESIZE))) { 1467 tx = cx; 1468 ty = cy; 1469 } 1470 } 1471 } 1472 } 1473 1474 if (tx >= 0 && tx < w && ty >= 0 && ty < w) { 1475 if (button == LEFT_BUTTON) { 1476 if (tx == ui->hx && ty == ui->hy && 1477 ui->hshow && !ui->hpencil) { 1478 ui->hshow = false; 1479 } else { 1480 ui->hx = tx; 1481 ui->hy = ty; 1482 ui->hshow = !state->clues->immutable[ty*w+tx]; 1483 ui->hpencil = false; 1484 } 1485 ui->hcursor = false; 1486 return MOVE_UI_UPDATE; 1487 } 1488 if (button == RIGHT_BUTTON) { 1489 /* 1490 * Pencil-mode highlighting for non filled squares. 1491 */ 1492 if (state->grid[ty*w+tx] == 0) { 1493 if (tx == ui->hx && ty == ui->hy && 1494 ui->hshow && ui->hpencil) { 1495 ui->hshow = false; 1496 } else { 1497 ui->hpencil = true; 1498 ui->hx = tx; 1499 ui->hy = ty; 1500 ui->hshow = true; 1501 } 1502 } else { 1503 ui->hshow = false; 1504 } 1505 ui->hcursor = false; 1506 return MOVE_UI_UPDATE; 1507 } 1508 } else if (button == LEFT_BUTTON) { 1509 if (is_clue(state, tx, ty)) { 1510 sprintf(buf, "%c%d,%d", 'D', tx, ty); 1511 return dupstr(buf); 1512 } 1513 } 1514 if (IS_CURSOR_MOVE(button)) { 1515 if (shift_or_control) { 1516 int x = ui->hx, y = ui->hy; 1517 switch (button) { 1518 case CURSOR_LEFT: x = -1; break; 1519 case CURSOR_RIGHT: x = w; break; 1520 case CURSOR_UP: y = -1; break; 1521 case CURSOR_DOWN: y = w; break; 1522 } 1523 if (is_clue(state, x, y)) { 1524 sprintf(buf, "%c%d,%d", 'D', x, y); 1525 return dupstr(buf); 1526 } 1527 return NULL; 1528 } 1529 ui->hcursor = true; 1530 return move_cursor(button, &ui->hx, &ui->hy, w, w, false, &ui->hshow); 1531 } 1532 if (ui->hshow && 1533 (button == CURSOR_SELECT)) { 1534 ui->hpencil = !ui->hpencil; 1535 ui->hcursor = true; 1536 return MOVE_UI_UPDATE; 1537 } 1538 1539 if (ui->hshow && 1540 ((button >= '0' && button <= '9' && button - '0' <= w) || 1541 button == CURSOR_SELECT2 || button == '\b')) { 1542 int n = button - '0'; 1543 if (button == CURSOR_SELECT2 || button == '\b') 1544 n = 0; 1545 1546 /* 1547 * Can't make pencil marks in a filled square. This can only 1548 * become highlighted if we're using cursor keys. 1549 */ 1550 if (ui->hpencil && state->grid[ui->hy*w+ui->hx]) 1551 return NULL; 1552 1553 /* 1554 * Can't do anything to an immutable square. 1555 */ 1556 if (state->clues->immutable[ui->hy*w+ui->hx]) 1557 return NULL; 1558 1559 /* 1560 * If you ask to fill a square with what it already contains, 1561 * or blank it when it's already empty, that has no effect... 1562 */ 1563 if ((!ui->hpencil || n == 0) && state->grid[ui->hy*w+ui->hx] == n && 1564 state->pencil[ui->hy*w+ui->hx] == 0) { 1565 /* ... expect to remove the cursor in mouse mode. */ 1566 if (!ui->hcursor) { 1567 ui->hshow = false; 1568 return MOVE_UI_UPDATE; 1569 } 1570 return NULL; 1571 } 1572 1573 sprintf(buf, "%c%d,%d,%d", 1574 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); 1575 1576 /* 1577 * Hide the highlight after a keypress, if it was mouse- 1578 * generated. Also, don't hide it if this move has changed 1579 * pencil marks and the user preference says not to hide the 1580 * highlight in that situation. 1581 */ 1582 if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight)) 1583 ui->hshow = false; 1584 1585 return dupstr(buf); 1586 } 1587 1588 if (button == 'M' || button == 'm') 1589 return dupstr("M"); 1590 1591 return NULL; 1592} 1593 1594static game_state *execute_move(const game_state *from, const char *move) 1595{ 1596 int w = from->par.w, a = w*w; 1597 game_state *ret = dup_game(from); 1598 int x, y, i, n; 1599 1600 if (move[0] == 'S') { 1601 ret->completed = ret->cheated = true; 1602 1603 for (i = 0; i < a; i++) { 1604 if (move[i+1] < '1' || move[i+1] > '0'+w) 1605 goto badmove; 1606 ret->grid[i] = move[i+1] - '0'; 1607 ret->pencil[i] = 0; 1608 } 1609 1610 if (move[a+1] != '\0') 1611 goto badmove; 1612 1613 return ret; 1614 } else if ((move[0] == 'P' || move[0] == 'R') && 1615 sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 && 1616 x >= 0 && x < w && y >= 0 && y < w && n >= 0 && n <= w) { 1617 if (from->clues->immutable[y*w+x]) 1618 goto badmove; 1619 1620 if (move[0] == 'P' && n > 0) { 1621 ret->pencil[y*w+x] ^= 1L << n; 1622 } else { 1623 ret->grid[y*w+x] = n; 1624 ret->pencil[y*w+x] = 0; 1625 1626 if (!ret->completed && !check_errors(ret, NULL)) 1627 ret->completed = true; 1628 } 1629 return ret; 1630 } else if (move[0] == 'M') { 1631 /* 1632 * Fill in absolutely all pencil marks everywhere. (I 1633 * wouldn't use this for actual play, but it's a handy 1634 * starting point when following through a set of 1635 * diagnostics output by the standalone solver.) 1636 */ 1637 for (i = 0; i < a; i++) { 1638 if (!ret->grid[i]) 1639 ret->pencil[i] = (1L << (w+1)) - (1L << 1); 1640 } 1641 return ret; 1642 } else if (move[0] == 'D' && sscanf(move+1, "%d,%d", &x, &y) == 2 && 1643 is_clue(from, x, y)) { 1644 int index = clue_index(from, x, y); 1645 ret->clues_done[index] = !ret->clues_done[index]; 1646 return ret; 1647 } 1648 1649 badmove: 1650 /* couldn't parse move string */ 1651 free_game(ret); 1652 return NULL; 1653} 1654 1655/* ---------------------------------------------------------------------- 1656 * Drawing routines. 1657 */ 1658 1659#define SIZE(w) ((w) * TILESIZE + 2*BORDER) 1660 1661static void game_compute_size(const game_params *params, int tilesize, 1662 const game_ui *ui, int *x, int *y) 1663{ 1664 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 1665 struct { int tilesize; } ads, *ds = &ads; 1666 ads.tilesize = tilesize; 1667 1668 *x = *y = SIZE(params->w); 1669} 1670 1671static void game_set_size(drawing *dr, game_drawstate *ds, 1672 const game_params *params, int tilesize) 1673{ 1674 ds->tilesize = tilesize; 1675} 1676 1677static float *game_colours(frontend *fe, int *ncolours) 1678{ 1679 float *ret = snewn(3 * NCOLOURS, float); 1680 1681 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); 1682 1683 ret[COL_GRID * 3 + 0] = 0.0F; 1684 ret[COL_GRID * 3 + 1] = 0.0F; 1685 ret[COL_GRID * 3 + 2] = 0.0F; 1686 1687 ret[COL_USER * 3 + 0] = 0.0F; 1688 ret[COL_USER * 3 + 1] = 0.6F * ret[COL_BACKGROUND * 3 + 1]; 1689 ret[COL_USER * 3 + 2] = 0.0F; 1690 1691 ret[COL_HIGHLIGHT * 3 + 0] = 0.78F * ret[COL_BACKGROUND * 3 + 0]; 1692 ret[COL_HIGHLIGHT * 3 + 1] = 0.78F * ret[COL_BACKGROUND * 3 + 1]; 1693 ret[COL_HIGHLIGHT * 3 + 2] = 0.78F * ret[COL_BACKGROUND * 3 + 2]; 1694 1695 ret[COL_ERROR * 3 + 0] = 1.0F; 1696 ret[COL_ERROR * 3 + 1] = 0.0F; 1697 ret[COL_ERROR * 3 + 2] = 0.0F; 1698 1699 ret[COL_PENCIL * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0]; 1700 ret[COL_PENCIL * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1]; 1701 ret[COL_PENCIL * 3 + 2] = ret[COL_BACKGROUND * 3 + 2]; 1702 1703 ret[COL_DONE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] / 1.5F; 1704 ret[COL_DONE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] / 1.5F; 1705 ret[COL_DONE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] / 1.5F; 1706 1707 *ncolours = NCOLOURS; 1708 return ret; 1709} 1710 1711static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) 1712{ 1713 int w = state->par.w /*, a = w*w */; 1714 struct game_drawstate *ds = snew(struct game_drawstate); 1715 int i; 1716 1717 ds->tilesize = 0; 1718 ds->tiles = snewn((w+2)*(w+2), long); 1719 ds->drawn = snewn((w+2)*(w+2)*4, long); 1720 for (i = 0; i < (w+2)*(w+2)*4; i++) 1721 ds->drawn[i] = -1; 1722 ds->errtmp = snewn((w+2)*(w+2), bool); 1723 1724 return ds; 1725} 1726 1727static void game_free_drawstate(drawing *dr, game_drawstate *ds) 1728{ 1729 sfree(ds->errtmp); 1730 sfree(ds->tiles); 1731 sfree(ds->drawn); 1732 sfree(ds); 1733} 1734 1735static void draw_tile(drawing *dr, game_drawstate *ds, const game_ui *ui, 1736 struct clues *clues, int x, int y, long tile) 1737{ 1738 int w = clues->w /* , a = w*w */; 1739 int tx, ty, bg; 1740 char str[64]; 1741 1742 tx = COORD(x); 1743 ty = COORD(y); 1744 1745 bg = (tile & DF_HIGHLIGHT) ? COL_HIGHLIGHT : COL_BACKGROUND; 1746 1747 /* draw tower */ 1748 if (ui->three_d && (tile & DF_PLAYAREA) && (tile & DF_DIGIT_MASK)) { 1749 int coords[8]; 1750 int xoff = X_3D_DISP(tile & DF_DIGIT_MASK, w); 1751 int yoff = Y_3D_DISP(tile & DF_DIGIT_MASK, w); 1752 1753 /* left face of tower */ 1754 coords[0] = tx; 1755 coords[1] = ty - 1; 1756 coords[2] = tx; 1757 coords[3] = ty + TILESIZE - 1; 1758 coords[4] = coords[2] + xoff; 1759 coords[5] = coords[3] - yoff; 1760 coords[6] = coords[0] + xoff; 1761 coords[7] = coords[1] - yoff; 1762 draw_polygon(dr, coords, 4, bg, COL_GRID); 1763 1764 /* bottom face of tower */ 1765 coords[0] = tx + TILESIZE; 1766 coords[1] = ty + TILESIZE - 1; 1767 coords[2] = tx; 1768 coords[3] = ty + TILESIZE - 1; 1769 coords[4] = coords[2] + xoff; 1770 coords[5] = coords[3] - yoff; 1771 coords[6] = coords[0] + xoff; 1772 coords[7] = coords[1] - yoff; 1773 draw_polygon(dr, coords, 4, bg, COL_GRID); 1774 1775 /* now offset all subsequent drawing to the top of the tower */ 1776 tx += xoff; 1777 ty -= yoff; 1778 } 1779 1780 /* erase background */ 1781 draw_rect(dr, tx, ty, TILESIZE, TILESIZE, bg); 1782 1783 /* pencil-mode highlight */ 1784 if (tile & DF_HIGHLIGHT_PENCIL) { 1785 int coords[6]; 1786 coords[0] = tx; 1787 coords[1] = ty; 1788 coords[2] = tx+TILESIZE/2; 1789 coords[3] = ty; 1790 coords[4] = tx; 1791 coords[5] = ty+TILESIZE/2; 1792 draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT); 1793 } 1794 1795 /* draw box outline */ 1796 if (tile & DF_PLAYAREA) { 1797 int coords[8]; 1798 coords[0] = tx; 1799 coords[1] = ty - 1; 1800 coords[2] = tx + TILESIZE; 1801 coords[3] = ty - 1; 1802 coords[4] = tx + TILESIZE; 1803 coords[5] = ty + TILESIZE - 1; 1804 coords[6] = tx; 1805 coords[7] = ty + TILESIZE - 1; 1806 draw_polygon(dr, coords, 4, -1, COL_GRID); 1807 } 1808 1809 /* new number needs drawing? */ 1810 if (tile & DF_DIGIT_MASK) { 1811 int color; 1812 1813 str[1] = '\0'; 1814 str[0] = (tile & DF_DIGIT_MASK) + '0'; 1815 1816 if (tile & DF_ERROR) 1817 color = COL_ERROR; 1818 else if (tile & DF_CLUE_DONE) 1819 color = COL_DONE; 1820 else if (x < 0 || y < 0 || x >= w || y >= w) 1821 color = COL_GRID; 1822 else if (tile & DF_IMMUTABLE) 1823 color = COL_GRID; 1824 else 1825 color = COL_USER; 1826 1827 draw_text(dr, tx + TILESIZE/2, ty + TILESIZE/2, FONT_VARIABLE, 1828 (tile & DF_PLAYAREA ? TILESIZE/2 : TILESIZE*2/5), 1829 ALIGN_VCENTRE | ALIGN_HCENTRE, color, str); 1830 } else { 1831 int i, j, npencil; 1832 int pl, pr, pt, pb; 1833 float bestsize; 1834 int pw, ph, minph, pbest, fontsize; 1835 1836 /* Count the pencil marks required. */ 1837 for (i = 1, npencil = 0; i <= w; i++) 1838 if (tile & (1L << (i + DF_PENCIL_SHIFT))) 1839 npencil++; 1840 if (npencil) { 1841 1842 minph = 2; 1843 1844 /* 1845 * Determine the bounding rectangle within which we're going 1846 * to put the pencil marks. 1847 */ 1848 /* Start with the whole square, minus space for impinging towers */ 1849 pl = tx + (ui->three_d ? X_3D_DISP(w,w) : 0); 1850 pr = tx + TILESIZE; 1851 pt = ty; 1852 pb = ty + TILESIZE - (ui->three_d ? Y_3D_DISP(w,w) : 0); 1853 1854 /* 1855 * We arrange our pencil marks in a grid layout, with 1856 * the number of rows and columns adjusted to allow the 1857 * maximum font size. 1858 * 1859 * So now we work out what the grid size ought to be. 1860 */ 1861 bestsize = 0.0; 1862 pbest = 0; 1863 /* Minimum */ 1864 for (pw = 3; pw < max(npencil,4); pw++) { 1865 float fw, fh, fs; 1866 1867 ph = (npencil + pw - 1) / pw; 1868 ph = max(ph, minph); 1869 fw = (pr - pl) / (float)pw; 1870 fh = (pb - pt) / (float)ph; 1871 fs = min(fw, fh); 1872 if (fs > bestsize) { 1873 bestsize = fs; 1874 pbest = pw; 1875 } 1876 } 1877 assert(pbest > 0); 1878 pw = pbest; 1879 ph = (npencil + pw - 1) / pw; 1880 ph = max(ph, minph); 1881 1882 /* 1883 * Now we've got our grid dimensions, work out the pixel 1884 * size of a grid element, and round it to the nearest 1885 * pixel. (We don't want rounding errors to make the 1886 * grid look uneven at low pixel sizes.) 1887 */ 1888 fontsize = min((pr - pl) / pw, (pb - pt) / ph); 1889 1890 /* 1891 * Centre the resulting figure in the square. 1892 */ 1893 pl = pl + (pr - pl - fontsize * pw) / 2; 1894 pt = pt + (pb - pt - fontsize * ph) / 2; 1895 1896 /* 1897 * Now actually draw the pencil marks. 1898 */ 1899 for (i = 1, j = 0; i <= w; i++) 1900 if (tile & (1L << (i + DF_PENCIL_SHIFT))) { 1901 int dx = j % pw, dy = j / pw; 1902 1903 str[1] = '\0'; 1904 str[0] = i + '0'; 1905 draw_text(dr, pl + fontsize * (2*dx+1) / 2, 1906 pt + fontsize * (2*dy+1) / 2, 1907 FONT_VARIABLE, fontsize, 1908 ALIGN_VCENTRE | ALIGN_HCENTRE, COL_PENCIL, str); 1909 j++; 1910 } 1911 } 1912 } 1913} 1914 1915static void game_redraw(drawing *dr, game_drawstate *ds, 1916 const game_state *oldstate, const game_state *state, 1917 int dir, const game_ui *ui, 1918 float animtime, float flashtime) 1919{ 1920 int w = state->par.w /*, a = w*w */; 1921 int i, x, y; 1922 1923 check_errors(state, ds->errtmp); 1924 1925 /* 1926 * Work out what data each tile should contain. 1927 */ 1928 for (i = 0; i < (w+2)*(w+2); i++) 1929 ds->tiles[i] = 0; /* completely blank square */ 1930 /* The clue squares... */ 1931 for (i = 0; i < 4*w; i++) { 1932 long tile = state->clues->clues[i]; 1933 1934 CLUEPOS(x, y, i, w); 1935 1936 if (ds->errtmp[(y+1)*(w+2)+(x+1)]) 1937 tile |= DF_ERROR; 1938 else if (state->clues_done[i]) 1939 tile |= DF_CLUE_DONE; 1940 1941 ds->tiles[(y+1)*(w+2)+(x+1)] = tile; 1942 } 1943 /* ... and the main grid. */ 1944 for (y = 0; y < w; y++) { 1945 for (x = 0; x < w; x++) { 1946 long tile = DF_PLAYAREA; 1947 1948 if (state->grid[y*w+x]) 1949 tile |= state->grid[y*w+x]; 1950 else 1951 tile |= (long)state->pencil[y*w+x] << DF_PENCIL_SHIFT; 1952 1953 if (ui->hshow && ui->hx == x && ui->hy == y) 1954 tile |= (ui->hpencil ? DF_HIGHLIGHT_PENCIL : DF_HIGHLIGHT); 1955 1956 if (state->clues->immutable[y*w+x]) 1957 tile |= DF_IMMUTABLE; 1958 1959 if (flashtime > 0 && 1960 (flashtime <= FLASH_TIME/3 || 1961 flashtime >= FLASH_TIME*2/3)) 1962 tile |= DF_HIGHLIGHT; /* completion flash */ 1963 1964 if (ds->errtmp[(y+1)*(w+2)+(x+1)]) 1965 tile |= DF_ERROR; 1966 1967 ds->tiles[(y+1)*(w+2)+(x+1)] = tile; 1968 } 1969 } 1970 1971 /* 1972 * Now actually draw anything that needs to be changed. 1973 */ 1974 for (y = 0; y < w+2; y++) { 1975 for (x = 0; x < w+2; x++) { 1976 long tl, tr, bl, br; 1977 int i = y*(w+2)+x; 1978 1979 tr = ds->tiles[y*(w+2)+x]; 1980 tl = (x == 0 ? 0 : ds->tiles[y*(w+2)+(x-1)]); 1981 br = (y == w+1 ? 0 : ds->tiles[(y+1)*(w+2)+x]); 1982 bl = (x == 0 || y == w+1 ? 0 : ds->tiles[(y+1)*(w+2)+(x-1)]); 1983 1984 if (ds->drawn[i*4] != tl || ds->drawn[i*4+1] != tr || 1985 ds->drawn[i*4+2] != bl || ds->drawn[i*4+3] != br) { 1986 clip(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE); 1987 1988 draw_tile(dr, ds, ui, state->clues, x-1, y-1, tr); 1989 if (x > 0) 1990 draw_tile(dr, ds, ui, state->clues, x-2, y-1, tl); 1991 if (y <= w) 1992 draw_tile(dr, ds, ui, state->clues, x-1, y, br); 1993 if (x > 0 && y <= w) 1994 draw_tile(dr, ds, ui, state->clues, x-2, y, bl); 1995 1996 unclip(dr); 1997 draw_update(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE); 1998 1999 ds->drawn[i*4] = tl; 2000 ds->drawn[i*4+1] = tr; 2001 ds->drawn[i*4+2] = bl; 2002 ds->drawn[i*4+3] = br; 2003 } 2004 } 2005 } 2006} 2007 2008static float game_anim_length(const game_state *oldstate, 2009 const game_state *newstate, int dir, game_ui *ui) 2010{ 2011 return 0.0F; 2012} 2013 2014static float game_flash_length(const game_state *oldstate, 2015 const game_state *newstate, int dir, game_ui *ui) 2016{ 2017 if (!oldstate->completed && newstate->completed && 2018 !oldstate->cheated && !newstate->cheated) 2019 return FLASH_TIME; 2020 return 0.0F; 2021} 2022 2023static void game_get_cursor_location(const game_ui *ui, 2024 const game_drawstate *ds, 2025 const game_state *state, 2026 const game_params *params, 2027 int *x, int *y, int *w, int *h) 2028{ 2029 if(ui->hshow) { 2030 *x = COORD(ui->hx); 2031 *y = COORD(ui->hy); 2032 *w = *h = TILESIZE; 2033 } 2034} 2035 2036static int game_status(const game_state *state) 2037{ 2038 return state->completed ? +1 : 0; 2039} 2040 2041static void game_print_size(const game_params *params, const game_ui *ui, 2042 float *x, float *y) 2043{ 2044 int pw, ph; 2045 2046 /* 2047 * We use 9mm squares by default, like Solo. 2048 */ 2049 game_compute_size(params, 900, ui, &pw, &ph); 2050 *x = pw / 100.0F; 2051 *y = ph / 100.0F; 2052} 2053 2054static void game_print(drawing *dr, const game_state *state, const game_ui *ui, 2055 int tilesize) 2056{ 2057 int w = state->par.w; 2058 int ink = print_mono_colour(dr, 0); 2059 int i, x, y; 2060 2061 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2062 game_drawstate ads, *ds = &ads; 2063 game_set_size(dr, ds, NULL, tilesize); 2064 2065 /* 2066 * Border. 2067 */ 2068 print_line_width(dr, 3 * TILESIZE / 40); 2069 draw_rect_outline(dr, BORDER, BORDER, w*TILESIZE, w*TILESIZE, ink); 2070 2071 /* 2072 * Main grid. 2073 */ 2074 for (x = 1; x < w; x++) { 2075 print_line_width(dr, TILESIZE / 40); 2076 draw_line(dr, BORDER+x*TILESIZE, BORDER, 2077 BORDER+x*TILESIZE, BORDER+w*TILESIZE, ink); 2078 } 2079 for (y = 1; y < w; y++) { 2080 print_line_width(dr, TILESIZE / 40); 2081 draw_line(dr, BORDER, BORDER+y*TILESIZE, 2082 BORDER+w*TILESIZE, BORDER+y*TILESIZE, ink); 2083 } 2084 2085 /* 2086 * Clues. 2087 */ 2088 for (i = 0; i < 4*w; i++) { 2089 char str[128]; 2090 2091 if (!state->clues->clues[i]) 2092 continue; 2093 2094 CLUEPOS(x, y, i, w); 2095 2096 sprintf (str, "%d", state->clues->clues[i]); 2097 2098 draw_text(dr, BORDER + x*TILESIZE + TILESIZE/2, 2099 BORDER + y*TILESIZE + TILESIZE/2, 2100 FONT_VARIABLE, TILESIZE/2, 2101 ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str); 2102 } 2103 2104 /* 2105 * Numbers for the solution, if any. 2106 */ 2107 for (y = 0; y < w; y++) 2108 for (x = 0; x < w; x++) 2109 if (state->grid[y*w+x]) { 2110 char str[2]; 2111 str[1] = '\0'; 2112 str[0] = state->grid[y*w+x] + '0'; 2113 draw_text(dr, BORDER + x*TILESIZE + TILESIZE/2, 2114 BORDER + y*TILESIZE + TILESIZE/2, 2115 FONT_VARIABLE, TILESIZE/2, 2116 ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str); 2117 } 2118} 2119 2120#ifdef COMBINED 2121#define thegame towers 2122#endif 2123 2124const struct game thegame = { 2125 "Towers", "games.towers", "towers", 2126 default_params, 2127 game_fetch_preset, NULL, 2128 decode_params, 2129 encode_params, 2130 free_params, 2131 dup_params, 2132 true, game_configure, custom_params, 2133 validate_params, 2134 new_game_desc, 2135 validate_desc, 2136 new_game, 2137 dup_game, 2138 free_game, 2139 true, solve_game, 2140 true, game_can_format_as_text_now, game_text_format, 2141 get_prefs, set_prefs, 2142 new_ui, 2143 free_ui, 2144 NULL, /* encode_ui */ 2145 NULL, /* decode_ui */ 2146 game_request_keys, 2147 game_changed_state, 2148 current_key_label, 2149 interpret_move, 2150 execute_move, 2151 PREFERRED_TILESIZE, game_compute_size, game_set_size, 2152 game_colours, 2153 game_new_drawstate, 2154 game_free_drawstate, 2155 game_redraw, 2156 game_anim_length, 2157 game_flash_length, 2158 game_get_cursor_location, 2159 game_status, 2160 true, false, game_print_size, game_print, 2161 false, /* wants_statusbar */ 2162 false, NULL, /* timing_state */ 2163 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ 2164}; 2165 2166#ifdef STANDALONE_SOLVER 2167 2168#include <stdarg.h> 2169 2170int main(int argc, char **argv) 2171{ 2172 game_params *p; 2173 game_state *s; 2174 char *id = NULL, *desc; 2175 const char *err; 2176 bool grade = false; 2177 int ret, diff; 2178 bool really_show_working = false; 2179 2180 while (--argc > 0) { 2181 char *p = *++argv; 2182 if (!strcmp(p, "-v")) { 2183 really_show_working = true; 2184 } else if (!strcmp(p, "-g")) { 2185 grade = true; 2186 } else if (*p == '-') { 2187 fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); 2188 return 1; 2189 } else { 2190 id = p; 2191 } 2192 } 2193 2194 if (!id) { 2195 fprintf(stderr, "usage: %s [-g | -v] <game_id>\n", argv[0]); 2196 return 1; 2197 } 2198 2199 desc = strchr(id, ':'); 2200 if (!desc) { 2201 fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); 2202 return 1; 2203 } 2204 *desc++ = '\0'; 2205 2206 p = default_params(); 2207 decode_params(p, id); 2208 err = validate_desc(p, desc); 2209 if (err) { 2210 fprintf(stderr, "%s: %s\n", argv[0], err); 2211 return 1; 2212 } 2213 s = new_game(NULL, p, desc); 2214 2215 /* 2216 * When solving an Easy puzzle, we don't want to bother the 2217 * user with Hard-level deductions. For this reason, we grade 2218 * the puzzle internally before doing anything else. 2219 */ 2220 ret = -1; /* placate optimiser */ 2221 solver_show_working = 0; 2222 for (diff = 0; diff < DIFFCOUNT; diff++) { 2223 memcpy(s->grid, s->clues->immutable, p->w * p->w); 2224 ret = solver(p->w, s->clues->clues, s->grid, diff); 2225 if (ret <= diff) 2226 break; 2227 } 2228 2229 if (really_show_working) { 2230 /* 2231 * Now run the solver again at the last difficulty level we 2232 * tried, but this time with diagnostics enabled. 2233 */ 2234 solver_show_working = really_show_working; 2235 memcpy(s->grid, s->clues->immutable, p->w * p->w); 2236 ret = solver(p->w, s->clues->clues, s->grid, 2237 diff < DIFFCOUNT ? diff : DIFFCOUNT-1); 2238 } 2239 2240 if (diff == DIFFCOUNT) { 2241 if (grade) 2242 printf("Difficulty rating: ambiguous\n"); 2243 else 2244 printf("Unable to find a unique solution\n"); 2245 } else { 2246 if (grade) { 2247 if (ret == diff_impossible) 2248 printf("Difficulty rating: impossible (no solution exists)\n"); 2249 else 2250 printf("Difficulty rating: %s\n", towers_diffnames[ret]); 2251 } else { 2252 if (ret != diff) 2253 printf("Puzzle is inconsistent\n"); 2254 else 2255 fputs(game_text_format(s), stdout); 2256 } 2257 } 2258 2259 return 0; 2260} 2261 2262#endif 2263 2264/* vim: set shiftwidth=4 tabstop=8: */