A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 2185 lines 63 kB view raw
1/* 2 * unruly.c: Implementation for Binary Puzzles. 3 * (C) 2012 Lennard Sprong 4 * Created for Simon Tatham's Portable Puzzle Collection 5 * See LICENCE for licence details 6 * 7 * Objective of the game: Fill the grid with zeros and ones, with the 8 * following rules: 9 * - There can't be a run of three or more equal numbers. 10 * - Each row and column contains an equal amount of zeros and ones. 11 * 12 * This puzzle type is known under several names, including 13 * Tohu-Wa-Vohu, One and Two and Binairo. 14 * 15 * Some variants include an extra constraint, stating that no two rows or two 16 * columns may contain the same exact sequence of zeros and ones. 17 * This rule is rarely used, so it is not enabled in the default presets 18 * (but it can be selected via the Custom configurer). 19 * 20 * More information: 21 * http://www.janko.at/Raetsel/Tohu-Wa-Vohu/index.htm 22 */ 23 24/* 25 * Possible future improvements: 26 * 27 * More solver cleverness 28 * 29 * - a counting-based deduction in which you find groups of squares 30 * which must each contain at least one of a given colour, plus 31 * other squares which are already known to be that colour, and see 32 * if you have any squares left over when you've worked out where 33 * they all have to be. This is a generalisation of the current 34 * check_near_complete: where that only covers rows with three 35 * unfilled squares, this would handle more, such as 36 * 0 . . 1 0 1 . . 0 . 37 * in which each of the two-square gaps must contain a 0, and there 38 * are three 0s placed, and that means the rightmost square can't 39 * be a 0. 40 * 41 * - an 'Unreasonable' difficulty level, supporting recursion and 42 * backtracking. 43 */ 44 45#include <stdio.h> 46#include <stdlib.h> 47#include <string.h> 48#include <assert.h> 49#include <ctype.h> 50#ifdef NO_TGMATH_H 51# include <math.h> 52#else 53# include <tgmath.h> 54#endif 55 56#include "puzzles.h" 57 58#ifdef STANDALONE_SOLVER 59static bool solver_verbose = false; 60#endif 61 62enum { 63 COL_BACKGROUND, 64 COL_GRID, 65 COL_EMPTY, 66 /* 67 * When editing this enum, maintain the invariants 68 * COL_n_HIGHLIGHT = COL_n + 1 69 * COL_n_LOWLIGHT = COL_n + 2 70 */ 71 COL_0, 72 COL_0_HIGHLIGHT, 73 COL_0_LOWLIGHT, 74 COL_1, 75 COL_1_HIGHLIGHT, 76 COL_1_LOWLIGHT, 77 COL_CURSOR, 78 COL_ERROR, 79 NCOLOURS 80}; 81 82struct game_params { 83 int w2, h2; /* full grid width and height respectively */ 84 bool unique; /* should row and column patterns be unique? */ 85 int diff; 86}; 87#define DIFFLIST(A) \ 88 A(TRIVIAL,Trivial, t) \ 89 A(EASY,Easy, e) \ 90 A(NORMAL,Normal, n) \ 91 92#define ENUM(upper,title,lower) DIFF_ ## upper, 93#define TITLE(upper,title,lower) #title, 94#define ENCODE(upper,title,lower) #lower 95#define CONFIG(upper,title,lower) ":" #title 96enum { DIFFLIST(ENUM) DIFFCOUNT }; 97static char const *const unruly_diffnames[] = { DIFFLIST(TITLE) }; 98 99static char const unruly_diffchars[] = DIFFLIST(ENCODE); 100#define DIFFCONFIG DIFFLIST(CONFIG) 101 102static const struct game_params unruly_presets[] = { 103 { 8, 8, false, DIFF_TRIVIAL}, 104 { 8, 8, false, DIFF_EASY}, 105 { 8, 8, false, DIFF_NORMAL}, 106 {10, 10, false, DIFF_EASY}, 107 {10, 10, false, DIFF_NORMAL}, 108 {14, 14, false, DIFF_EASY}, 109 {14, 14, false, DIFF_NORMAL} 110}; 111 112#define DEFAULT_PRESET 0 113 114enum { 115 EMPTY, 116 N_ONE, 117 N_ZERO, 118 BOGUS 119}; 120 121#define FE_HOR_ROW_LEFT 0x0001 122#define FE_HOR_ROW_MID 0x0003 123#define FE_HOR_ROW_RIGHT 0x0002 124 125#define FE_VER_ROW_TOP 0x0004 126#define FE_VER_ROW_MID 0x000C 127#define FE_VER_ROW_BOTTOM 0x0008 128 129#define FE_COUNT 0x0010 130 131#define FE_ROW_MATCH 0x0020 132#define FE_COL_MATCH 0x0040 133 134#define FF_ONE 0x0080 135#define FF_ZERO 0x0100 136#define FF_CURSOR 0x0200 137 138#define FF_FLASH1 0x0400 139#define FF_FLASH2 0x0800 140#define FF_IMMUTABLE 0x1000 141 142typedef struct unruly_common { 143 int refcount; 144 bool *immutable; 145} unruly_common; 146 147struct game_state { 148 int w2, h2; 149 bool unique; 150 char *grid; 151 unruly_common *common; 152 153 bool completed, cheated; 154}; 155 156static game_params *default_params(void) 157{ 158 game_params *ret = snew(game_params); 159 160 *ret = unruly_presets[DEFAULT_PRESET]; /* structure copy */ 161 162 return ret; 163} 164 165static bool game_fetch_preset(int i, char **name, game_params **params) 166{ 167 game_params *ret; 168 char buf[80]; 169 170 if (i < 0 || i >= lenof(unruly_presets)) 171 return false; 172 173 ret = snew(game_params); 174 *ret = unruly_presets[i]; /* structure copy */ 175 176 sprintf(buf, "%dx%d %s", ret->w2, ret->h2, unruly_diffnames[ret->diff]); 177 178 *name = dupstr(buf); 179 *params = ret; 180 return true; 181} 182 183static void free_params(game_params *params) 184{ 185 sfree(params); 186} 187 188static game_params *dup_params(const game_params *params) 189{ 190 game_params *ret = snew(game_params); 191 *ret = *params; /* structure copy */ 192 return ret; 193} 194 195static void decode_params(game_params *params, char const *string) 196{ 197 char const *p = string; 198 199 params->unique = false; 200 201 params->w2 = atoi(p); 202 while (*p && isdigit((unsigned char)*p)) p++; 203 if (*p == 'x') { 204 p++; 205 params->h2 = atoi(p); 206 while (*p && isdigit((unsigned char)*p)) p++; 207 } else { 208 params->h2 = params->w2; 209 } 210 211 if (*p == 'u') { 212 p++; 213 params->unique = true; 214 } 215 216 if (*p == 'd') { 217 int i; 218 p++; 219 params->diff = DIFFCOUNT + 1; /* ...which is invalid */ 220 if (*p) { 221 for (i = 0; i < DIFFCOUNT; i++) { 222 if (*p == unruly_diffchars[i]) 223 params->diff = i; 224 } 225 p++; 226 } 227 } 228} 229 230static char *encode_params(const game_params *params, bool full) 231{ 232 char buf[80]; 233 234 sprintf(buf, "%dx%d", params->w2, params->h2); 235 if (params->unique) 236 strcat(buf, "u"); 237 if (full) 238 sprintf(buf + strlen(buf), "d%c", unruly_diffchars[params->diff]); 239 240 return dupstr(buf); 241} 242 243static config_item *game_configure(const game_params *params) 244{ 245 config_item *ret; 246 char buf[80]; 247 248 ret = snewn(5, config_item); 249 250 ret[0].name = "Width"; 251 ret[0].type = C_STRING; 252 sprintf(buf, "%d", params->w2); 253 ret[0].u.string.sval = dupstr(buf); 254 255 ret[1].name = "Height"; 256 ret[1].type = C_STRING; 257 sprintf(buf, "%d", params->h2); 258 ret[1].u.string.sval = dupstr(buf); 259 260 ret[2].name = "Unique rows and columns"; 261 ret[2].type = C_BOOLEAN; 262 ret[2].u.boolean.bval = params->unique; 263 264 ret[3].name = "Difficulty"; 265 ret[3].type = C_CHOICES; 266 ret[3].u.choices.choicenames = DIFFCONFIG; 267 ret[3].u.choices.selected = params->diff; 268 269 ret[4].name = NULL; 270 ret[4].type = C_END; 271 272 return ret; 273} 274 275static game_params *custom_params(const config_item *cfg) 276{ 277 game_params *ret = snew(game_params); 278 279 ret->w2 = atoi(cfg[0].u.string.sval); 280 ret->h2 = atoi(cfg[1].u.string.sval); 281 ret->unique = cfg[2].u.boolean.bval; 282 ret->diff = cfg[3].u.choices.selected; 283 284 return ret; 285} 286 287static const char *validate_params(const game_params *params, bool full) 288{ 289 if ((params->w2 & 1) || (params->h2 & 1)) 290 return "Width and height must both be even"; 291 if (params->w2 < 6 || params->h2 < 6) 292 return "Width and height must be at least 6"; 293 if (params->w2 > INT_MAX / params->h2) 294 return "Width times height must not be unreasonably large"; 295 if (params->unique) { 296 static const long A177790[] = { 297 /* 298 * The nth element of this array gives the number of 299 * distinct possible Unruly rows of length 2n (that is, 300 * containing exactly n 1s and n 0s and not containing 301 * three consecutive elements the same) for as long as 302 * those numbers fit in a 32-bit signed int. 303 * 304 * So in unique-rows mode, if the puzzle width is 2n, then 305 * the height must be at most (this array)[n], and vice 306 * versa. 307 * 308 * This is sequence A177790 in the Online Encyclopedia of 309 * Integer Sequences: http://oeis.org/A177790 310 */ 311 1L, 2L, 6L, 14L, 34L, 84L, 208L, 518L, 1296L, 3254L, 312 8196L, 20700L, 52404L, 132942L, 337878L, 860142L, 313 2192902L, 5598144L, 14308378L, 36610970L, 93770358L, 314 240390602L, 616787116L, 1583765724L 315 }; 316 if (params->w2 < 2*lenof(A177790) && 317 params->h2 > A177790[params->w2/2]) { 318 return "Puzzle is too tall for unique-rows mode"; 319 } 320 if (params->h2 < 2*lenof(A177790) && 321 params->w2 > A177790[params->h2/2]) { 322 return "Puzzle is too long for unique-rows mode"; 323 } 324 } 325 if (params->diff >= DIFFCOUNT) 326 return "Unknown difficulty rating"; 327 328 return NULL; 329} 330 331static const char *validate_desc(const game_params *params, const char *desc) 332{ 333 int w2 = params->w2, h2 = params->h2; 334 int s = w2 * h2; 335 336 const char *p = desc; 337 int pos = 0; 338 339 while (*p) { 340 if (*p >= 'a' && *p < 'z') 341 pos += 1 + (*p - 'a'); 342 else if (*p >= 'A' && *p < 'Z') 343 pos += 1 + (*p - 'A'); 344 else if (*p == 'Z' || *p == 'z') 345 pos += 25; 346 else 347 return "Description contains invalid characters"; 348 349 ++p; 350 } 351 352 if (pos < s+1) 353 return "Description too short"; 354 if (pos > s+1) 355 return "Description too long"; 356 357 return NULL; 358} 359 360static game_state *blank_state(int w2, int h2, bool unique, bool new_common) 361{ 362 game_state *state = snew(game_state); 363 int s = w2 * h2; 364 365 state->w2 = w2; 366 state->h2 = h2; 367 state->unique = unique; 368 state->grid = snewn(s, char); 369 memset(state->grid, EMPTY, s); 370 371 if (new_common) { 372 state->common = snew(unruly_common); 373 state->common->refcount = 1; 374 state->common->immutable = snewn(s, bool); 375 memset(state->common->immutable, 0, s*sizeof(bool)); 376 } 377 378 state->completed = state->cheated = false; 379 380 return state; 381} 382 383static game_state *new_game(midend *me, const game_params *params, 384 const char *desc) 385{ 386 int w2 = params->w2, h2 = params->h2; 387 int s = w2 * h2; 388 389 game_state *state = blank_state(w2, h2, params->unique, true); 390 391 const char *p = desc; 392 int pos = 0; 393 394 while (*p) { 395 if (*p >= 'a' && *p < 'z') { 396 pos += (*p - 'a'); 397 if (pos < s) { 398 state->grid[pos] = N_ZERO; 399 state->common->immutable[pos] = true; 400 } 401 pos++; 402 } else if (*p >= 'A' && *p < 'Z') { 403 pos += (*p - 'A'); 404 if (pos < s) { 405 state->grid[pos] = N_ONE; 406 state->common->immutable[pos] = true; 407 } 408 pos++; 409 } else if (*p == 'Z' || *p == 'z') { 410 pos += 25; 411 } else 412 assert(!"Description contains invalid characters"); 413 414 ++p; 415 } 416 assert(pos == s+1); 417 418 return state; 419} 420 421static game_state *dup_game(const game_state *state) 422{ 423 int w2 = state->w2, h2 = state->h2; 424 int s = w2 * h2; 425 426 game_state *ret = blank_state(w2, h2, state->unique, false); 427 428 memcpy(ret->grid, state->grid, s); 429 ret->common = state->common; 430 ret->common->refcount++; 431 432 ret->completed = state->completed; 433 ret->cheated = state->cheated; 434 435 return ret; 436} 437 438static void free_game(game_state *state) 439{ 440 sfree(state->grid); 441 if (--state->common->refcount == 0) { 442 sfree(state->common->immutable); 443 sfree(state->common); 444 } 445 446 sfree(state); 447} 448 449static bool game_can_format_as_text_now(const game_params *params) 450{ 451 return true; 452} 453 454static char *game_text_format(const game_state *state) 455{ 456 int w2 = state->w2, h2 = state->h2; 457 int lr = w2*2 + 1; 458 459 char *ret = snewn(lr * h2 + 1, char); 460 char *p = ret; 461 462 int x, y; 463 for (y = 0; y < h2; y++) { 464 for (x = 0; x < w2; x++) { 465 /* Place number */ 466 char c = state->grid[y * w2 + x]; 467 *p++ = (c == N_ONE ? '1' : c == N_ZERO ? '0' : '.'); 468 *p++ = ' '; 469 } 470 /* End line */ 471 *p++ = '\n'; 472 } 473 /* End with NUL */ 474 *p++ = '\0'; 475 476 return ret; 477} 478 479/* ****** * 480 * Solver * 481 * ****** */ 482 483struct unruly_scratch { 484 int *ones_rows; 485 int *ones_cols; 486 int *zeros_rows; 487 int *zeros_cols; 488}; 489 490static void unruly_solver_update_remaining(const game_state *state, 491 struct unruly_scratch *scratch) 492{ 493 int w2 = state->w2, h2 = state->h2; 494 int x, y; 495 496 /* Reset all scratch data */ 497 memset(scratch->ones_rows, 0, h2 * sizeof(int)); 498 memset(scratch->ones_cols, 0, w2 * sizeof(int)); 499 memset(scratch->zeros_rows, 0, h2 * sizeof(int)); 500 memset(scratch->zeros_cols, 0, w2 * sizeof(int)); 501 502 for (x = 0; x < w2; x++) 503 for (y = 0; y < h2; y++) { 504 if (state->grid[y * w2 + x] == N_ONE) { 505 scratch->ones_rows[y]++; 506 scratch->ones_cols[x]++; 507 } else if (state->grid[y * w2 + x] == N_ZERO) { 508 scratch->zeros_rows[y]++; 509 scratch->zeros_cols[x]++; 510 } 511 } 512} 513 514static struct unruly_scratch *unruly_new_scratch(const game_state *state) 515{ 516 int w2 = state->w2, h2 = state->h2; 517 518 struct unruly_scratch *ret = snew(struct unruly_scratch); 519 520 ret->ones_rows = snewn(h2, int); 521 ret->ones_cols = snewn(w2, int); 522 ret->zeros_rows = snewn(h2, int); 523 ret->zeros_cols = snewn(w2, int); 524 525 unruly_solver_update_remaining(state, ret); 526 527 return ret; 528} 529 530static void unruly_free_scratch(struct unruly_scratch *scratch) 531{ 532 sfree(scratch->ones_rows); 533 sfree(scratch->ones_cols); 534 sfree(scratch->zeros_rows); 535 sfree(scratch->zeros_cols); 536 537 sfree(scratch); 538} 539 540static int unruly_solver_check_threes(game_state *state, int *rowcount, 541 int *colcount, bool horizontal, 542 char check, char block) 543{ 544 int w2 = state->w2, h2 = state->h2; 545 546 int dx = horizontal ? 1 : 0, dy = 1 - dx; 547 int sx = dx, sy = dy; 548 int ex = w2 - dx, ey = h2 - dy; 549 550 int x, y; 551 int ret = 0; 552 553 /* Check for any three squares which almost form three in a row */ 554 for (y = sy; y < ey; y++) { 555 for (x = sx; x < ex; x++) { 556 int i1 = (y-dy) * w2 + (x-dx); 557 int i2 = y * w2 + x; 558 int i3 = (y+dy) * w2 + (x+dx); 559 560 if (state->grid[i1] == check && state->grid[i2] == check 561 && state->grid[i3] == EMPTY) { 562 ret++; 563#ifdef STANDALONE_SOLVER 564 if (solver_verbose) { 565 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n", 566 i1 % w2, i1 / w2, i2 % w2, i2 / w2, 567 (block == N_ONE ? '1' : '0'), i3 % w2, 568 i3 / w2); 569 } 570#endif 571 state->grid[i3] = block; 572 rowcount[i3 / w2]++; 573 colcount[i3 % w2]++; 574 } 575 if (state->grid[i1] == check && state->grid[i2] == EMPTY 576 && state->grid[i3] == check) { 577 ret++; 578#ifdef STANDALONE_SOLVER 579 if (solver_verbose) { 580 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n", 581 i1 % w2, i1 / w2, i3 % w2, i3 / w2, 582 (block == N_ONE ? '1' : '0'), i2 % w2, 583 i2 / w2); 584 } 585#endif 586 state->grid[i2] = block; 587 rowcount[i2 / w2]++; 588 colcount[i2 % w2]++; 589 } 590 if (state->grid[i1] == EMPTY && state->grid[i2] == check 591 && state->grid[i3] == check) { 592 ret++; 593#ifdef STANDALONE_SOLVER 594 if (solver_verbose) { 595 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n", 596 i2 % w2, i2 / w2, i3 % w2, i3 / w2, 597 (block == N_ONE ? '1' : '0'), i1 % w2, 598 i1 / w2); 599 } 600#endif 601 state->grid[i1] = block; 602 rowcount[i1 / w2]++; 603 colcount[i1 % w2]++; 604 } 605 } 606 } 607 608 return ret; 609} 610 611static int unruly_solver_check_all_threes(game_state *state, 612 struct unruly_scratch *scratch) 613{ 614 int ret = 0; 615 616 ret += 617 unruly_solver_check_threes(state, scratch->zeros_rows, 618 scratch->zeros_cols, true, N_ONE, N_ZERO); 619 ret += 620 unruly_solver_check_threes(state, scratch->ones_rows, 621 scratch->ones_cols, true, N_ZERO, N_ONE); 622 ret += 623 unruly_solver_check_threes(state, scratch->zeros_rows, 624 scratch->zeros_cols, false, N_ONE, 625 N_ZERO); 626 ret += 627 unruly_solver_check_threes(state, scratch->ones_rows, 628 scratch->ones_cols, false, N_ZERO, N_ONE); 629 630 return ret; 631} 632 633static int unruly_solver_check_uniques(game_state *state, int *rowcount, 634 bool horizontal, char check, char block, 635 struct unruly_scratch *scratch) 636{ 637 int w2 = state->w2, h2 = state->h2; 638 639 int rmult = (horizontal ? w2 : 1); 640 int cmult = (horizontal ? 1 : w2); 641 int nr = (horizontal ? h2 : w2); 642 int nc = (horizontal ? w2 : h2); 643 int max = nc / 2; 644 645 int r, r2, c; 646 int ret = 0; 647 648 /* 649 * Find each row that has max entries of type 'check', and see if 650 * all those entries match those in any row with max-1 entries. If 651 * so, set the last non-matching entry of the latter row to ensure 652 * that it's different. 653 */ 654 for (r = 0; r < nr; r++) { 655 if (rowcount[r] != max) 656 continue; 657 for (r2 = 0; r2 < nr; r2++) { 658 int nmatch = 0, nonmatch = -1; 659 if (rowcount[r2] != max-1) 660 continue; 661 for (c = 0; c < nc; c++) { 662 if (state->grid[r*rmult + c*cmult] == check) { 663 if (state->grid[r2*rmult + c*cmult] == check) 664 nmatch++; 665 else 666 nonmatch = c; 667 } 668 } 669 if (nmatch == max-1) { 670 int i1 = r2 * rmult + nonmatch * cmult; 671 assert(nonmatch != -1); 672 if (state->grid[i1] == block) 673 continue; 674 assert(state->grid[i1] == EMPTY); 675#ifdef STANDALONE_SOLVER 676 if (solver_verbose) { 677 printf("Solver: matching %s %i, %i gives %c at %i,%i\n", 678 horizontal ? "rows" : "cols", 679 r, r2, (block == N_ONE ? '1' : '0'), i1 % w2, 680 i1 / w2); 681 } 682#endif 683 state->grid[i1] = block; 684 if (block == N_ONE) { 685 scratch->ones_rows[i1 / w2]++; 686 scratch->ones_cols[i1 % w2]++; 687 } else { 688 scratch->zeros_rows[i1 / w2]++; 689 scratch->zeros_cols[i1 % w2]++; 690 } 691 ret++; 692 } 693 } 694 } 695 return ret; 696} 697 698static int unruly_solver_check_all_uniques(game_state *state, 699 struct unruly_scratch *scratch) 700{ 701 int ret = 0; 702 703 ret += unruly_solver_check_uniques(state, scratch->ones_rows, 704 true, N_ONE, N_ZERO, scratch); 705 ret += unruly_solver_check_uniques(state, scratch->zeros_rows, 706 true, N_ZERO, N_ONE, scratch); 707 ret += unruly_solver_check_uniques(state, scratch->ones_cols, 708 false, N_ONE, N_ZERO, scratch); 709 ret += unruly_solver_check_uniques(state, scratch->zeros_cols, 710 false, N_ZERO, N_ONE, scratch); 711 712 return ret; 713} 714 715static int unruly_solver_fill_row(game_state *state, int i, bool horizontal, 716 int *rowcount, int *colcount, char fill) 717{ 718 int ret = 0; 719 int w2 = state->w2, h2 = state->h2; 720 int j; 721 722#ifdef STANDALONE_SOLVER 723 if (solver_verbose) { 724 printf("Solver: Filling %s %i with %c:", 725 (horizontal ? "Row" : "Col"), i, 726 (fill == N_ZERO ? '0' : '1')); 727 } 728#endif 729 /* Place a number in every empty square in a row/column */ 730 for (j = 0; j < (horizontal ? w2 : h2); j++) { 731 int p = (horizontal ? i * w2 + j : j * w2 + i); 732 733 if (state->grid[p] == EMPTY) { 734#ifdef STANDALONE_SOLVER 735 if (solver_verbose) { 736 printf(" (%i,%i)", (horizontal ? j : i), 737 (horizontal ? i : j)); 738 } 739#endif 740 ret++; 741 state->grid[p] = fill; 742 rowcount[(horizontal ? i : j)]++; 743 colcount[(horizontal ? j : i)]++; 744 } 745 } 746 747#ifdef STANDALONE_SOLVER 748 if (solver_verbose) { 749 printf("\n"); 750 } 751#endif 752 753 return ret; 754} 755 756static int unruly_solver_check_single_gap(game_state *state, 757 int *complete, bool horizontal, 758 int *rowcount, int *colcount, 759 char fill) 760{ 761 int w2 = state->w2, h2 = state->h2; 762 int count = (horizontal ? h2 : w2); /* number of rows to check */ 763 int target = (horizontal ? w2 : h2) / 2; /* target number of 0s/1s */ 764 int *other = (horizontal ? rowcount : colcount); 765 766 int ret = 0; 767 768 int i; 769 /* Check for completed rows/cols for one number, then fill in the rest */ 770 for (i = 0; i < count; i++) { 771 if (complete[i] == target && other[i] == target - 1) { 772#ifdef STANDALONE_SOLVER 773 if (solver_verbose) { 774 printf("Solver: Row %i has only one square left which must be " 775 "%c\n", i, (fill == N_ZERO ? '0' : '1')); 776 } 777#endif 778 ret += unruly_solver_fill_row(state, i, horizontal, rowcount, 779 colcount, fill); 780 } 781 } 782 783 return ret; 784} 785 786static int unruly_solver_check_all_single_gap(game_state *state, 787 struct unruly_scratch *scratch) 788{ 789 int ret = 0; 790 791 ret += 792 unruly_solver_check_single_gap(state, scratch->ones_rows, true, 793 scratch->zeros_rows, 794 scratch->zeros_cols, N_ZERO); 795 ret += 796 unruly_solver_check_single_gap(state, scratch->ones_cols, false, 797 scratch->zeros_rows, 798 scratch->zeros_cols, N_ZERO); 799 ret += 800 unruly_solver_check_single_gap(state, scratch->zeros_rows, true, 801 scratch->ones_rows, 802 scratch->ones_cols, N_ONE); 803 ret += 804 unruly_solver_check_single_gap(state, scratch->zeros_cols, false, 805 scratch->ones_rows, 806 scratch->ones_cols, N_ONE); 807 808 return ret; 809} 810 811static int unruly_solver_check_complete_nums(game_state *state, 812 int *complete, bool horizontal, 813 int *rowcount, int *colcount, 814 char fill) 815{ 816 int w2 = state->w2, h2 = state->h2; 817 int count = (horizontal ? h2 : w2); /* number of rows to check */ 818 int target = (horizontal ? w2 : h2) / 2; /* target number of 0s/1s */ 819 int *other = (horizontal ? rowcount : colcount); 820 821 int ret = 0; 822 823 int i; 824 /* Check for completed rows/cols for one number, then fill in the rest */ 825 for (i = 0; i < count; i++) { 826 if (complete[i] == target && other[i] < target) { 827#ifdef STANDALONE_SOLVER 828 if (solver_verbose) { 829 printf("Solver: Row %i satisfied for %c\n", i, 830 (fill != N_ZERO ? '0' : '1')); 831 } 832#endif 833 ret += unruly_solver_fill_row(state, i, horizontal, rowcount, 834 colcount, fill); 835 } 836 } 837 838 return ret; 839} 840 841static int unruly_solver_check_all_complete_nums(game_state *state, 842 struct unruly_scratch *scratch) 843{ 844 int ret = 0; 845 846 ret += 847 unruly_solver_check_complete_nums(state, scratch->ones_rows, true, 848 scratch->zeros_rows, 849 scratch->zeros_cols, N_ZERO); 850 ret += 851 unruly_solver_check_complete_nums(state, scratch->ones_cols, false, 852 scratch->zeros_rows, 853 scratch->zeros_cols, N_ZERO); 854 ret += 855 unruly_solver_check_complete_nums(state, scratch->zeros_rows, true, 856 scratch->ones_rows, 857 scratch->ones_cols, N_ONE); 858 ret += 859 unruly_solver_check_complete_nums(state, scratch->zeros_cols, false, 860 scratch->ones_rows, 861 scratch->ones_cols, N_ONE); 862 863 return ret; 864} 865 866static int unruly_solver_check_near_complete(game_state *state, 867 int *complete, bool horizontal, 868 int *rowcount, int *colcount, 869 char fill) 870{ 871 int w2 = state->w2, h2 = state->h2; 872 int w = w2/2, h = h2/2; 873 874 int dx = horizontal ? 1 : 0, dy = 1 - dx; 875 876 int sx = dx, sy = dy; 877 int ex = w2 - dx, ey = h2 - dy; 878 879 int x, y; 880 int ret = 0; 881 882 /* 883 * This function checks for a row with one Y remaining, then looks 884 * for positions that could cause the remaining squares in the row 885 * to make 3 X's in a row. Example: 886 * 887 * Consider the following row: 888 * 1 1 0 . . . 889 * If the last 1 was placed in the last square, the remaining 890 * squares would be 0: 891 * 1 1 0 0 0 1 892 * This violates the 3 in a row rule. We now know that the last 1 893 * shouldn't be in the last cell. 894 * 1 1 0 . . 0 895 */ 896 897 /* Check for any two blank and one filled square */ 898 for (y = sy; y < ey; y++) { 899 /* One type must have 1 remaining, the other at least 2 */ 900 if (horizontal && (complete[y] < w - 1 || rowcount[y] > w - 2)) 901 continue; 902 903 for (x = sx; x < ex; x++) { 904 int i, i1, i2, i3; 905 if (!horizontal 906 && (complete[x] < h - 1 || colcount[x] > h - 2)) 907 continue; 908 909 i = (horizontal ? y : x); 910 i1 = (y-dy) * w2 + (x-dx); 911 i2 = y * w2 + x; 912 i3 = (y+dy) * w2 + (x+dx); 913 914 if (state->grid[i1] == fill && state->grid[i2] == EMPTY 915 && state->grid[i3] == EMPTY) { 916 /* 917 * Temporarily fill the empty spaces with something else. 918 * This avoids raising the counts for the row and column 919 */ 920 state->grid[i2] = BOGUS; 921 state->grid[i3] = BOGUS; 922 923#ifdef STANDALONE_SOLVER 924 if (solver_verbose) { 925 printf("Solver: Row %i nearly satisfied for %c\n", i, 926 (fill != N_ZERO ? '0' : '1')); 927 } 928#endif 929 ret += 930 unruly_solver_fill_row(state, i, horizontal, rowcount, 931 colcount, fill); 932 933 state->grid[i2] = EMPTY; 934 state->grid[i3] = EMPTY; 935 } 936 937 else if (state->grid[i1] == EMPTY && state->grid[i2] == fill 938 && state->grid[i3] == EMPTY) { 939 state->grid[i1] = BOGUS; 940 state->grid[i3] = BOGUS; 941 942#ifdef STANDALONE_SOLVER 943 if (solver_verbose) { 944 printf("Solver: Row %i nearly satisfied for %c\n", i, 945 (fill != N_ZERO ? '0' : '1')); 946 } 947#endif 948 ret += 949 unruly_solver_fill_row(state, i, horizontal, rowcount, 950 colcount, fill); 951 952 state->grid[i1] = EMPTY; 953 state->grid[i3] = EMPTY; 954 } 955 956 else if (state->grid[i1] == EMPTY && state->grid[i2] == EMPTY 957 && state->grid[i3] == fill) { 958 state->grid[i1] = BOGUS; 959 state->grid[i2] = BOGUS; 960 961#ifdef STANDALONE_SOLVER 962 if (solver_verbose) { 963 printf("Solver: Row %i nearly satisfied for %c\n", i, 964 (fill != N_ZERO ? '0' : '1')); 965 } 966#endif 967 ret += 968 unruly_solver_fill_row(state, i, horizontal, rowcount, 969 colcount, fill); 970 971 state->grid[i1] = EMPTY; 972 state->grid[i2] = EMPTY; 973 } 974 975 else if (state->grid[i1] == EMPTY && state->grid[i2] == EMPTY 976 && state->grid[i3] == EMPTY) { 977 state->grid[i1] = BOGUS; 978 state->grid[i2] = BOGUS; 979 state->grid[i3] = BOGUS; 980 981#ifdef STANDALONE_SOLVER 982 if (solver_verbose) { 983 printf("Solver: Row %i nearly satisfied for %c\n", i, 984 (fill != N_ZERO ? '0' : '1')); 985 } 986#endif 987 ret += 988 unruly_solver_fill_row(state, i, horizontal, rowcount, 989 colcount, fill); 990 991 state->grid[i1] = EMPTY; 992 state->grid[i2] = EMPTY; 993 state->grid[i3] = EMPTY; 994 } 995 } 996 } 997 998 return ret; 999} 1000 1001static int unruly_solver_check_all_near_complete(game_state *state, 1002 struct unruly_scratch *scratch) 1003{ 1004 int ret = 0; 1005 1006 ret += 1007 unruly_solver_check_near_complete(state, scratch->ones_rows, true, 1008 scratch->zeros_rows, 1009 scratch->zeros_cols, N_ZERO); 1010 ret += 1011 unruly_solver_check_near_complete(state, scratch->ones_cols, false, 1012 scratch->zeros_rows, 1013 scratch->zeros_cols, N_ZERO); 1014 ret += 1015 unruly_solver_check_near_complete(state, scratch->zeros_rows, true, 1016 scratch->ones_rows, 1017 scratch->ones_cols, N_ONE); 1018 ret += 1019 unruly_solver_check_near_complete(state, scratch->zeros_cols, false, 1020 scratch->ones_rows, 1021 scratch->ones_cols, N_ONE); 1022 1023 return ret; 1024} 1025 1026static int unruly_validate_rows(const game_state *state, bool horizontal, 1027 char check, int *errors) 1028{ 1029 int w2 = state->w2, h2 = state->h2; 1030 1031 int dx = horizontal ? 1 : 0, dy = 1 - dx; 1032 1033 int sx = dx, sy = dy; 1034 int ex = w2 - dx, ey = h2 - dy; 1035 1036 int x, y; 1037 int ret = 0; 1038 1039 int err1 = (horizontal ? FE_HOR_ROW_LEFT : FE_VER_ROW_TOP); 1040 int err2 = (horizontal ? FE_HOR_ROW_MID : FE_VER_ROW_MID); 1041 int err3 = (horizontal ? FE_HOR_ROW_RIGHT : FE_VER_ROW_BOTTOM); 1042 1043 /* Check for any three in a row, and mark errors accordingly (if 1044 * required) */ 1045 for (y = sy; y < ey; y++) { 1046 for (x = sx; x < ex; x++) { 1047 int i1 = (y-dy) * w2 + (x-dx); 1048 int i2 = y * w2 + x; 1049 int i3 = (y+dy) * w2 + (x+dx); 1050 1051 if (state->grid[i1] == check && state->grid[i2] == check 1052 && state->grid[i3] == check) { 1053 ret++; 1054 if (errors) { 1055 errors[i1] |= err1; 1056 errors[i2] |= err2; 1057 errors[i3] |= err3; 1058 } 1059 } 1060 } 1061 } 1062 1063 return ret; 1064} 1065 1066static int unruly_validate_unique(const game_state *state, bool horizontal, 1067 int *errors) 1068{ 1069 int w2 = state->w2, h2 = state->h2; 1070 1071 int rmult = (horizontal ? w2 : 1); 1072 int cmult = (horizontal ? 1 : w2); 1073 int nr = (horizontal ? h2 : w2); 1074 int nc = (horizontal ? w2 : h2); 1075 int err = (horizontal ? FE_ROW_MATCH : FE_COL_MATCH); 1076 1077 int r, r2, c; 1078 int ret = 0; 1079 1080 /* Check for any two full rows matching exactly, and mark errors 1081 * accordingly (if required) */ 1082 for (r = 0; r < nr; r++) { 1083 int nfull = 0; 1084 for (c = 0; c < nc; c++) 1085 if (state->grid[r*rmult + c*cmult] != EMPTY) 1086 nfull++; 1087 if (nfull != nc) 1088 continue; 1089 for (r2 = r+1; r2 < nr; r2++) { 1090 bool match = true; 1091 for (c = 0; c < nc; c++) 1092 if (state->grid[r*rmult + c*cmult] != 1093 state->grid[r2*rmult + c*cmult]) 1094 match = false; 1095 if (match) { 1096 if (errors) { 1097 for (c = 0; c < nc; c++) { 1098 errors[r*rmult + c*cmult] |= err; 1099 errors[r2*rmult + c*cmult] |= err; 1100 } 1101 } 1102 ret++; 1103 } 1104 } 1105 } 1106 1107 return ret; 1108} 1109 1110static int unruly_validate_all_rows(const game_state *state, int *errors) 1111{ 1112 int errcount = 0; 1113 1114 errcount += unruly_validate_rows(state, true, N_ONE, errors); 1115 errcount += unruly_validate_rows(state, false, N_ONE, errors); 1116 errcount += unruly_validate_rows(state, true, N_ZERO, errors); 1117 errcount += unruly_validate_rows(state, false, N_ZERO, errors); 1118 1119 if (state->unique) { 1120 errcount += unruly_validate_unique(state, true, errors); 1121 errcount += unruly_validate_unique(state, false, errors); 1122 } 1123 1124 if (errcount) 1125 return -1; 1126 return 0; 1127} 1128 1129static int unruly_validate_counts(const game_state *state, 1130 struct unruly_scratch *scratch, bool *errors) 1131{ 1132 int w2 = state->w2, h2 = state->h2; 1133 int w = w2/2, h = h2/2; 1134 bool below = false; 1135 bool above = false; 1136 int i; 1137 1138 /* See if all rows/columns are satisfied. If one is exceeded, 1139 * mark it as an error (if required) 1140 */ 1141 1142 bool hasscratch = true; 1143 if (!scratch) { 1144 scratch = unruly_new_scratch(state); 1145 hasscratch = false; 1146 } 1147 1148 for (i = 0; i < w2; i++) { 1149 if (scratch->ones_cols[i] < h) 1150 below = true; 1151 if (scratch->zeros_cols[i] < h) 1152 below = true; 1153 1154 if (scratch->ones_cols[i] > h) { 1155 above = true; 1156 if (errors) 1157 errors[2*h2 + i] = true; 1158 } else if (errors) 1159 errors[2*h2 + i] = false; 1160 1161 if (scratch->zeros_cols[i] > h) { 1162 above = true; 1163 if (errors) 1164 errors[2*h2 + w2 + i] = true; 1165 } else if (errors) 1166 errors[2*h2 + w2 + i] = false; 1167 } 1168 for (i = 0; i < h2; i++) { 1169 if (scratch->ones_rows[i] < w) 1170 below = true; 1171 if (scratch->zeros_rows[i] < w) 1172 below = true; 1173 1174 if (scratch->ones_rows[i] > w) { 1175 above = true; 1176 if (errors) 1177 errors[i] = true; 1178 } else if (errors) 1179 errors[i] = false; 1180 1181 if (scratch->zeros_rows[i] > w) { 1182 above = true; 1183 if (errors) 1184 errors[h2 + i] = true; 1185 } else if (errors) 1186 errors[h2 + i] = false; 1187 } 1188 1189 if (!hasscratch) 1190 unruly_free_scratch(scratch); 1191 1192 return (above ? -1 : below ? 1 : 0); 1193} 1194 1195static int unruly_solve_game(game_state *state, 1196 struct unruly_scratch *scratch, int diff) 1197{ 1198 int done, maxdiff = -1; 1199 1200 while (true) { 1201 done = 0; 1202 1203 /* Check for impending 3's */ 1204 done += unruly_solver_check_all_threes(state, scratch); 1205 1206 /* Keep using the simpler techniques while they produce results */ 1207 if (done) { 1208 if (maxdiff < DIFF_TRIVIAL) 1209 maxdiff = DIFF_TRIVIAL; 1210 continue; 1211 } 1212 1213 /* Check for rows with only one unfilled square */ 1214 done += unruly_solver_check_all_single_gap(state, scratch); 1215 1216 if (done) { 1217 if (maxdiff < DIFF_TRIVIAL) 1218 maxdiff = DIFF_TRIVIAL; 1219 continue; 1220 } 1221 1222 /* Easy techniques */ 1223 if (diff < DIFF_EASY) 1224 break; 1225 1226 /* Check for completed rows */ 1227 done += unruly_solver_check_all_complete_nums(state, scratch); 1228 1229 if (done) { 1230 if (maxdiff < DIFF_EASY) 1231 maxdiff = DIFF_EASY; 1232 continue; 1233 } 1234 1235 /* Check for impending failures of row/column uniqueness, if 1236 * it's enabled in this game mode */ 1237 if (state->unique) { 1238 done += unruly_solver_check_all_uniques(state, scratch); 1239 1240 if (done) { 1241 if (maxdiff < DIFF_EASY) 1242 maxdiff = DIFF_EASY; 1243 continue; 1244 } 1245 } 1246 1247 /* Normal techniques */ 1248 if (diff < DIFF_NORMAL) 1249 break; 1250 1251 /* Check for nearly completed rows */ 1252 done += unruly_solver_check_all_near_complete(state, scratch); 1253 1254 if (done) { 1255 if (maxdiff < DIFF_NORMAL) 1256 maxdiff = DIFF_NORMAL; 1257 continue; 1258 } 1259 1260 break; 1261 } 1262 return maxdiff; 1263} 1264 1265static char *solve_game(const game_state *state, const game_state *currstate, 1266 const char *aux, const char **error) 1267{ 1268 game_state *solved = dup_game(state); 1269 struct unruly_scratch *scratch = unruly_new_scratch(solved); 1270 char *ret = NULL; 1271 int result; 1272 1273 unruly_solve_game(solved, scratch, DIFFCOUNT); 1274 1275 result = unruly_validate_counts(solved, scratch, NULL); 1276 if (unruly_validate_all_rows(solved, NULL) == -1) 1277 result = -1; 1278 1279 if (result == 0) { 1280 int w2 = solved->w2, h2 = solved->h2; 1281 int s = w2 * h2; 1282 char *p; 1283 int i; 1284 1285 ret = snewn(s + 2, char); 1286 p = ret; 1287 *p++ = 'S'; 1288 1289 for (i = 0; i < s; i++) 1290 *p++ = (solved->grid[i] == N_ONE ? '1' : '0'); 1291 1292 *p++ = '\0'; 1293 } else if (result == 1) 1294 *error = "No solution found."; 1295 else if (result == -1) 1296 *error = "Puzzle is invalid."; 1297 1298 free_game(solved); 1299 unruly_free_scratch(scratch); 1300 return ret; 1301} 1302 1303/* ********* * 1304 * Generator * 1305 * ********* */ 1306 1307static bool unruly_fill_game(game_state *state, struct unruly_scratch *scratch, 1308 random_state *rs) 1309{ 1310 1311 int w2 = state->w2, h2 = state->h2; 1312 int s = w2 * h2; 1313 int i, j; 1314 int *spaces; 1315 1316#ifdef STANDALONE_SOLVER 1317 if (solver_verbose) { 1318 printf("Generator: Attempt to fill grid\n"); 1319 } 1320#endif 1321 1322 /* Generate random array of spaces */ 1323 spaces = snewn(s, int); 1324 for (i = 0; i < s; i++) 1325 spaces[i] = i; 1326 shuffle(spaces, s, sizeof(*spaces), rs); 1327 1328 /* 1329 * Construct a valid filled grid by repeatedly picking an unfilled 1330 * space and fill it, then calling the solver to fill in any 1331 * spaces forced by the change. 1332 */ 1333 for (j = 0; j < s; j++) { 1334 i = spaces[j]; 1335 1336 if (state->grid[i] != EMPTY) 1337 continue; 1338 1339 if (random_upto(rs, 2)) { 1340 state->grid[i] = N_ONE; 1341 scratch->ones_rows[i / w2]++; 1342 scratch->ones_cols[i % w2]++; 1343 } else { 1344 state->grid[i] = N_ZERO; 1345 scratch->zeros_rows[i / w2]++; 1346 scratch->zeros_cols[i % w2]++; 1347 } 1348 1349 unruly_solve_game(state, scratch, DIFFCOUNT); 1350 } 1351 sfree(spaces); 1352 1353 if (unruly_validate_all_rows(state, NULL) != 0 1354 || unruly_validate_counts(state, scratch, NULL) != 0) 1355 return false; 1356 1357 return true; 1358} 1359 1360static char *new_game_desc(const game_params *params, random_state *rs, 1361 char **aux, bool interactive) 1362{ 1363#ifdef STANDALONE_SOLVER 1364 char *debug; 1365 bool temp_verbose = false; 1366#endif 1367 1368 int w2 = params->w2, h2 = params->h2; 1369 int s = w2 * h2; 1370 int *spaces; 1371 int i, j, run; 1372 char *ret, *p; 1373 1374 game_state *state; 1375 struct unruly_scratch *scratch; 1376 1377 int attempts = 0; 1378 1379 while (1) { 1380 1381 while (true) { 1382 attempts++; 1383 state = blank_state(w2, h2, params->unique, true); 1384 scratch = unruly_new_scratch(state); 1385 if (unruly_fill_game(state, scratch, rs)) 1386 break; 1387 free_game(state); 1388 unruly_free_scratch(scratch); 1389 } 1390 1391#ifdef STANDALONE_SOLVER 1392 if (solver_verbose) { 1393 printf("Puzzle generated in %i attempts\n", attempts); 1394 debug = game_text_format(state); 1395 fputs(debug, stdout); 1396 sfree(debug); 1397 1398 temp_verbose = solver_verbose; 1399 solver_verbose = false; 1400 } 1401#else 1402 (void)attempts; 1403#endif 1404 1405 unruly_free_scratch(scratch); 1406 1407 /* Generate random array of spaces */ 1408 spaces = snewn(s, int); 1409 for (i = 0; i < s; i++) 1410 spaces[i] = i; 1411 shuffle(spaces, s, sizeof(*spaces), rs); 1412 1413 /* 1414 * Winnow the clues by starting from our filled grid, repeatedly 1415 * picking a filled space and emptying it, as long as the solver 1416 * reports that the puzzle can still be solved after doing so. 1417 */ 1418 for (j = 0; j < s; j++) { 1419 char c; 1420 game_state *solver; 1421 1422 i = spaces[j]; 1423 1424 c = state->grid[i]; 1425 state->grid[i] = EMPTY; 1426 1427 solver = dup_game(state); 1428 scratch = unruly_new_scratch(state); 1429 1430 unruly_solve_game(solver, scratch, params->diff); 1431 1432 if (unruly_validate_counts(solver, scratch, NULL) != 0) 1433 state->grid[i] = c; 1434 1435 free_game(solver); 1436 unruly_free_scratch(scratch); 1437 } 1438 sfree(spaces); 1439 1440#ifdef STANDALONE_SOLVER 1441 if (temp_verbose) { 1442 solver_verbose = true; 1443 1444 printf("Final puzzle:\n"); 1445 debug = game_text_format(state); 1446 fputs(debug, stdout); 1447 sfree(debug); 1448 } 1449#endif 1450 1451 /* 1452 * See if the game has accidentally come out too easy. 1453 */ 1454 if (params->diff > 0) { 1455 bool ok; 1456 game_state *solver; 1457 1458 solver = dup_game(state); 1459 scratch = unruly_new_scratch(state); 1460 1461 unruly_solve_game(solver, scratch, params->diff - 1); 1462 1463 ok = unruly_validate_counts(solver, scratch, NULL) > 0; 1464 1465 free_game(solver); 1466 unruly_free_scratch(scratch); 1467 1468 if (ok) 1469 break; 1470 } else { 1471 /* 1472 * Puzzles of the easiest difficulty can't be too easy. 1473 */ 1474 break; 1475 } 1476 } 1477 1478 /* Encode description */ 1479 ret = snewn(s + 1, char); 1480 p = ret; 1481 run = 0; 1482 for (i = 0; i < s+1; i++) { 1483 if (i == s || state->grid[i] == N_ZERO) { 1484 while (run > 24) { 1485 *p++ = 'z'; 1486 run -= 25; 1487 } 1488 *p++ = 'a' + run; 1489 run = 0; 1490 } else if (state->grid[i] == N_ONE) { 1491 while (run > 24) { 1492 *p++ = 'Z'; 1493 run -= 25; 1494 } 1495 *p++ = 'A' + run; 1496 run = 0; 1497 } else { 1498 run++; 1499 } 1500 } 1501 *p = '\0'; 1502 1503 free_game(state); 1504 1505 return ret; 1506} 1507 1508/* ************** * 1509 * User Interface * 1510 * ************** */ 1511 1512struct game_ui { 1513 int cx, cy; 1514 bool cursor; 1515}; 1516 1517static game_ui *new_ui(const game_state *state) 1518{ 1519 game_ui *ret = snew(game_ui); 1520 1521 ret->cx = ret->cy = 0; 1522 ret->cursor = getenv_bool("PUZZLES_SHOW_CURSOR", false); 1523 1524 return ret; 1525} 1526 1527static void free_ui(game_ui *ui) 1528{ 1529 sfree(ui); 1530} 1531 1532static void game_changed_state(game_ui *ui, const game_state *oldstate, 1533 const game_state *newstate) 1534{ 1535} 1536 1537static const char *current_key_label(const game_ui *ui, 1538 const game_state *state, int button) 1539{ 1540 int hx = ui->cx, hy = ui->cy; 1541 int w2 = state->w2; 1542 char i = state->grid[hy * w2 + hx]; 1543 1544 if (ui->cursor && IS_CURSOR_SELECT(button)) { 1545 if (state->common->immutable[hy * w2 + hx]) return ""; 1546 switch (i) { 1547 case EMPTY: 1548 return button == CURSOR_SELECT ? "Black" : "White"; 1549 case N_ONE: 1550 return button == CURSOR_SELECT ? "White" : "Empty"; 1551 case N_ZERO: 1552 return button == CURSOR_SELECT ? "Empty" : "Black"; 1553 } 1554 } 1555 return ""; 1556} 1557 1558struct game_drawstate { 1559 int tilesize; 1560 int w2, h2; 1561 bool started; 1562 1563 int *gridfs; 1564 bool *rowfs; 1565 1566 int *grid; 1567}; 1568 1569static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) 1570{ 1571 struct game_drawstate *ds = snew(struct game_drawstate); 1572 1573 int w2 = state->w2, h2 = state->h2; 1574 int s = w2 * h2; 1575 int i; 1576 1577 ds->tilesize = 0; 1578 ds->w2 = w2; 1579 ds->h2 = h2; 1580 ds->started = false; 1581 1582 ds->gridfs = snewn(s, int); 1583 ds->rowfs = snewn(2 * (w2 + h2), bool); 1584 1585 ds->grid = snewn(s, int); 1586 for (i = 0; i < s; i++) 1587 ds->grid[i] = -1; 1588 1589 return ds; 1590} 1591 1592static void game_free_drawstate(drawing *dr, game_drawstate *ds) 1593{ 1594 sfree(ds->gridfs); 1595 sfree(ds->rowfs); 1596 sfree(ds->grid); 1597 sfree(ds); 1598} 1599 1600#define COORD(x) ( (x) * ds->tilesize + ds->tilesize/2 ) 1601#define FROMCOORD(x) ( ((x)-(ds->tilesize/2)) / ds->tilesize ) 1602 1603static char *interpret_move(const game_state *state, game_ui *ui, 1604 const game_drawstate *ds, 1605 int ox, int oy, int button) 1606{ 1607 int hx = ui->cx; 1608 int hy = ui->cy; 1609 1610 int gx = FROMCOORD(ox); 1611 int gy = FROMCOORD(oy); 1612 1613 int w2 = state->w2, h2 = state->h2; 1614 1615 char *nullret = MOVE_NO_EFFECT; 1616 1617 button = STRIP_BUTTON_MODIFIERS(button); 1618 1619 /* Mouse click */ 1620 if (button == LEFT_BUTTON || button == RIGHT_BUTTON || 1621 button == MIDDLE_BUTTON) { 1622 if (ox >= (ds->tilesize / 2) && gx < w2 1623 && oy >= (ds->tilesize / 2) && gy < h2) { 1624 hx = gx; 1625 hy = gy; 1626 if (ui->cursor) { 1627 ui->cursor = false; 1628 nullret = MOVE_UI_UPDATE; 1629 } 1630 } else 1631 return MOVE_UNUSED; 1632 } 1633 1634 /* Keyboard move */ 1635 if (IS_CURSOR_MOVE(button)) 1636 return move_cursor(button, &ui->cx, &ui->cy, w2, h2, false, 1637 &ui->cursor); 1638 1639 /* Place one */ 1640 if ((ui->cursor && (button == CURSOR_SELECT || button == CURSOR_SELECT2 1641 || button == '\b' || button == '0' || button == '1' 1642 || button == '2')) || 1643 button == LEFT_BUTTON || button == RIGHT_BUTTON || 1644 button == MIDDLE_BUTTON) { 1645 char buf[80]; 1646 char c, i; 1647 1648 if (state->common->immutable[hy * w2 + hx]) 1649 return nullret; 1650 1651 c = '-'; 1652 i = state->grid[hy * w2 + hx]; 1653 1654 if (button == '0' || button == '2') 1655 c = '0'; 1656 else if (button == '1') 1657 c = '1'; 1658 else if (button == MIDDLE_BUTTON) 1659 c = '-'; 1660 1661 /* Cycle through options */ 1662 else if (button == CURSOR_SELECT2 || button == RIGHT_BUTTON) 1663 c = (i == EMPTY ? '0' : i == N_ZERO ? '1' : '-'); 1664 else if (button == CURSOR_SELECT || button == LEFT_BUTTON) 1665 c = (i == EMPTY ? '1' : i == N_ONE ? '0' : '-'); 1666 1667 if (state->grid[hy * w2 + hx] == 1668 (c == '0' ? N_ZERO : c == '1' ? N_ONE : EMPTY)) 1669 return nullret; /* don't put no-ops on the undo chain */ 1670 1671 sprintf(buf, "P%c,%d,%d", c, hx, hy); 1672 1673 return dupstr(buf); 1674 } 1675 return MOVE_UNUSED; 1676} 1677 1678static game_state *execute_move(const game_state *state, const char *move) 1679{ 1680 int w2 = state->w2, h2 = state->h2; 1681 int s = w2 * h2; 1682 int x, y, i; 1683 char c; 1684 1685 game_state *ret; 1686 1687 if (move[0] == 'S') { 1688 const char *p; 1689 1690 ret = dup_game(state); 1691 p = move + 1; 1692 1693 for (i = 0; i < s; i++) { 1694 1695 if (!*p || !(*p == '1' || *p == '0')) { 1696 free_game(ret); 1697 return NULL; 1698 } 1699 1700 ret->grid[i] = (*p == '1' ? N_ONE : N_ZERO); 1701 p++; 1702 } 1703 1704 ret->completed = ret->cheated = true; 1705 return ret; 1706 } else if (move[0] == 'P' 1707 && sscanf(move + 1, "%c,%d,%d", &c, &x, &y) == 3 && x >= 0 1708 && x < w2 && y >= 0 && y < h2 && (c == '-' || c == '0' 1709 || c == '1')) { 1710 ret = dup_game(state); 1711 i = y * w2 + x; 1712 1713 if (state->common->immutable[i]) { 1714 free_game(ret); 1715 return NULL; 1716 } 1717 1718 ret->grid[i] = (c == '1' ? N_ONE : c == '0' ? N_ZERO : EMPTY); 1719 1720 if (!ret->completed && unruly_validate_counts(ret, NULL, NULL) == 0 1721 && (unruly_validate_all_rows(ret, NULL) == 0)) 1722 ret->completed = true; 1723 1724 return ret; 1725 } 1726 1727 return NULL; 1728} 1729 1730/* ---------------------------------------------------------------------- 1731 * Drawing routines. 1732 */ 1733 1734static void game_compute_size(const game_params *params, int tilesize, 1735 const game_ui *ui, int *x, int *y) 1736{ 1737 *x = tilesize * (params->w2 + 1); 1738 *y = tilesize * (params->h2 + 1); 1739} 1740 1741static void game_set_size(drawing *dr, game_drawstate *ds, 1742 const game_params *params, int tilesize) 1743{ 1744 ds->tilesize = tilesize; 1745} 1746 1747static float *game_colours(frontend *fe, int *ncolours) 1748{ 1749 float *ret = snewn(3 * NCOLOURS, float); 1750 int i; 1751 1752 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); 1753 1754 for (i = 0; i < 3; i++) { 1755 ret[COL_1 * 3 + i] = 0.2F; 1756 ret[COL_1_HIGHLIGHT * 3 + i] = 0.4F; 1757 ret[COL_1_LOWLIGHT * 3 + i] = 0.0F; 1758 ret[COL_0 * 3 + i] = 0.95F; 1759 ret[COL_0_HIGHLIGHT * 3 + i] = 1.0F; 1760 ret[COL_0_LOWLIGHT * 3 + i] = 0.9F; 1761 ret[COL_EMPTY * 3 + i] = 0.5F; 1762 ret[COL_GRID * 3 + i] = 0.3F; 1763 } 1764 game_mkhighlight_specific(fe, ret, COL_0, COL_0_HIGHLIGHT, COL_0_LOWLIGHT); 1765 game_mkhighlight_specific(fe, ret, COL_1, COL_1_HIGHLIGHT, COL_1_LOWLIGHT); 1766 1767 ret[COL_ERROR * 3 + 0] = 1.0F; 1768 ret[COL_ERROR * 3 + 1] = 0.0F; 1769 ret[COL_ERROR * 3 + 2] = 0.0F; 1770 1771 ret[COL_CURSOR * 3 + 0] = 0.0F; 1772 ret[COL_CURSOR * 3 + 1] = 0.7F; 1773 ret[COL_CURSOR * 3 + 2] = 0.0F; 1774 1775 *ncolours = NCOLOURS; 1776 return ret; 1777} 1778 1779static void unruly_draw_err_rectangle(drawing *dr, int x, int y, int w, int h, 1780 int tilesize) 1781{ 1782 double thick = tilesize / 10; 1783 double margin = tilesize / 20; 1784 1785 draw_rect(dr, x+margin, y+margin, w-2*margin, thick, COL_ERROR); 1786 draw_rect(dr, x+margin, y+margin, thick, h-2*margin, COL_ERROR); 1787 draw_rect(dr, x+margin, y+h-margin-thick, w-2*margin, thick, COL_ERROR); 1788 draw_rect(dr, x+w-margin-thick, y+margin, thick, h-2*margin, COL_ERROR); 1789} 1790 1791static void unruly_draw_tile(drawing *dr, int x, int y, int tilesize, int tile) 1792{ 1793 clip(dr, x, y, tilesize, tilesize); 1794 1795 /* Draw the grid edge first, so the tile can overwrite it */ 1796 draw_rect(dr, x, y, tilesize, tilesize, COL_GRID); 1797 1798 /* Background of the tile */ 1799 { 1800 int val = (tile & FF_ZERO ? 0 : tile & FF_ONE ? 2 : 1); 1801 val = (val == 0 ? COL_0 : val == 2 ? COL_1 : COL_EMPTY); 1802 1803 if ((tile & (FF_FLASH1 | FF_FLASH2)) && 1804 (val == COL_0 || val == COL_1)) { 1805 val += (tile & FF_FLASH1 ? 1 : 2); 1806 } 1807 1808 draw_rect(dr, x, y, tilesize-1, tilesize-1, val); 1809 1810 if ((val == COL_0 || val == COL_1) && (tile & FF_IMMUTABLE)) { 1811 draw_rect(dr, x + tilesize/6, y + tilesize/6, 1812 tilesize - 2*(tilesize/6) - 2, 1, val + 2); 1813 draw_rect(dr, x + tilesize/6, y + tilesize/6, 1814 1, tilesize - 2*(tilesize/6) - 2, val + 2); 1815 draw_rect(dr, x + tilesize/6 + 1, y + tilesize - tilesize/6 - 2, 1816 tilesize - 2*(tilesize/6) - 2, 1, val + 1); 1817 draw_rect(dr, x + tilesize - tilesize/6 - 2, y + tilesize/6 + 1, 1818 1, tilesize - 2*(tilesize/6) - 2, val + 1); 1819 } 1820 } 1821 1822 /* 3-in-a-row errors */ 1823 if (tile & (FE_HOR_ROW_LEFT | FE_HOR_ROW_RIGHT)) { 1824 int left = x, right = x + tilesize - 1; 1825 if ((tile & FE_HOR_ROW_LEFT)) 1826 right += tilesize/2; 1827 if ((tile & FE_HOR_ROW_RIGHT)) 1828 left -= tilesize/2; 1829 unruly_draw_err_rectangle(dr, left, y, right-left, tilesize-1, tilesize); 1830 } 1831 if (tile & (FE_VER_ROW_TOP | FE_VER_ROW_BOTTOM)) { 1832 int top = y, bottom = y + tilesize - 1; 1833 if ((tile & FE_VER_ROW_TOP)) 1834 bottom += tilesize/2; 1835 if ((tile & FE_VER_ROW_BOTTOM)) 1836 top -= tilesize/2; 1837 unruly_draw_err_rectangle(dr, x, top, tilesize-1, bottom-top, tilesize); 1838 } 1839 1840 /* Count errors */ 1841 if (tile & FE_COUNT) { 1842 draw_text(dr, x + tilesize/2, y + tilesize/2, FONT_VARIABLE, 1843 tilesize/2, ALIGN_HCENTRE | ALIGN_VCENTRE, COL_ERROR, "!"); 1844 } 1845 1846 /* Row-match errors */ 1847 if (tile & FE_ROW_MATCH) { 1848 draw_rect(dr, x, y+tilesize/2-tilesize/12, 1849 tilesize, 2*(tilesize/12), COL_ERROR); 1850 } 1851 if (tile & FE_COL_MATCH) { 1852 draw_rect(dr, x+tilesize/2-tilesize/12, y, 1853 2*(tilesize/12), tilesize, COL_ERROR); 1854 } 1855 1856 /* Cursor rectangle */ 1857 if (tile & FF_CURSOR) { 1858 draw_rect(dr, x, y, tilesize/12, tilesize-1, COL_CURSOR); 1859 draw_rect(dr, x, y, tilesize-1, tilesize/12, COL_CURSOR); 1860 draw_rect(dr, x+tilesize-1-tilesize/12, y, tilesize/12, tilesize-1, 1861 COL_CURSOR); 1862 draw_rect(dr, x, y+tilesize-1-tilesize/12, tilesize-1, tilesize/12, 1863 COL_CURSOR); 1864 } 1865 1866 unclip(dr); 1867 draw_update(dr, x, y, tilesize, tilesize); 1868} 1869 1870#define TILE_SIZE (ds->tilesize) 1871#define DEFAULT_TILE_SIZE 32 1872#define FLASH_FRAME 0.12F 1873#define FLASH_TIME (FLASH_FRAME * 3) 1874 1875static void game_redraw(drawing *dr, game_drawstate *ds, 1876 const game_state *oldstate, const game_state *state, 1877 int dir, const game_ui *ui, 1878 float animtime, float flashtime) 1879{ 1880 int w2 = state->w2, h2 = state->h2; 1881 int s = w2 * h2; 1882 int flash; 1883 int x, y, i; 1884 1885 if (!ds->started) { 1886 /* Outer edge of grid */ 1887 draw_rect(dr, COORD(0)-TILE_SIZE/10, COORD(0)-TILE_SIZE/10, 1888 TILE_SIZE*w2 + 2*(TILE_SIZE/10) - 1, 1889 TILE_SIZE*h2 + 2*(TILE_SIZE/10) - 1, COL_GRID); 1890 1891 draw_update(dr, 0, 0, TILE_SIZE * (w2+1), TILE_SIZE * (h2+1)); 1892 ds->started = true; 1893 } 1894 1895 flash = 0; 1896 if (flashtime > 0) 1897 flash = (int)(flashtime / FLASH_FRAME) == 1 ? FF_FLASH2 : FF_FLASH1; 1898 1899 for (i = 0; i < s; i++) 1900 ds->gridfs[i] = 0; 1901 unruly_validate_all_rows(state, ds->gridfs); 1902 for (i = 0; i < 2 * (h2 + w2); i++) 1903 ds->rowfs[i] = false; 1904 unruly_validate_counts(state, NULL, ds->rowfs); 1905 1906 for (y = 0; y < h2; y++) { 1907 for (x = 0; x < w2; x++) { 1908 int tile; 1909 1910 i = y * w2 + x; 1911 1912 tile = ds->gridfs[i]; 1913 1914 if (state->grid[i] == N_ONE) { 1915 tile |= FF_ONE; 1916 if (ds->rowfs[y] || ds->rowfs[2*h2 + x]) 1917 tile |= FE_COUNT; 1918 } else if (state->grid[i] == N_ZERO) { 1919 tile |= FF_ZERO; 1920 if (ds->rowfs[h2 + y] || ds->rowfs[2*h2 + w2 + x]) 1921 tile |= FE_COUNT; 1922 } 1923 1924 tile |= flash; 1925 1926 if (state->common->immutable[i]) 1927 tile |= FF_IMMUTABLE; 1928 1929 if (ui->cursor && ui->cx == x && ui->cy == y) 1930 tile |= FF_CURSOR; 1931 1932 if (ds->grid[i] != tile) { 1933 ds->grid[i] = tile; 1934 unruly_draw_tile(dr, COORD(x), COORD(y), TILE_SIZE, tile); 1935 } 1936 } 1937 } 1938} 1939 1940static float game_anim_length(const game_state *oldstate, 1941 const game_state *newstate, int dir, game_ui *ui) 1942{ 1943 return 0.0F; 1944} 1945 1946static float game_flash_length(const game_state *oldstate, 1947 const game_state *newstate, int dir, game_ui *ui) 1948{ 1949 if (!oldstate->completed && newstate->completed && 1950 !oldstate->cheated && !newstate->cheated) 1951 return FLASH_TIME; 1952 return 0.0F; 1953} 1954 1955static void game_get_cursor_location(const game_ui *ui, 1956 const game_drawstate *ds, 1957 const game_state *state, 1958 const game_params *params, 1959 int *x, int *y, int *w, int *h) 1960{ 1961 if(ui->cursor) { 1962 *x = COORD(ui->cx); 1963 *y = COORD(ui->cy); 1964 *w = *h = TILE_SIZE; 1965 } 1966} 1967 1968static int game_status(const game_state *state) 1969{ 1970 return state->completed ? +1 : 0; 1971} 1972 1973static void game_print_size(const game_params *params, const game_ui *ui, 1974 float *x, float *y) 1975{ 1976 int pw, ph; 1977 1978 /* Using 7mm squares */ 1979 game_compute_size(params, 700, ui, &pw, &ph); 1980 *x = pw / 100.0F; 1981 *y = ph / 100.0F; 1982} 1983 1984static void game_print(drawing *dr, const game_state *state, const game_ui *ui, 1985 int tilesize) 1986{ 1987 int w2 = state->w2, h2 = state->h2; 1988 int x, y; 1989 1990 int ink = print_mono_colour(dr, 0); 1991 1992 for (y = 0; y < h2; y++) 1993 for (x = 0; x < w2; x++) { 1994 int tx = x * tilesize + (tilesize / 2); 1995 int ty = y * tilesize + (tilesize / 2); 1996 1997 /* Draw the border */ 1998 int coords[8]; 1999 coords[0] = tx; 2000 coords[1] = ty - 1; 2001 coords[2] = tx + tilesize; 2002 coords[3] = ty - 1; 2003 coords[4] = tx + tilesize; 2004 coords[5] = ty + tilesize - 1; 2005 coords[6] = tx; 2006 coords[7] = ty + tilesize - 1; 2007 draw_polygon(dr, coords, 4, -1, ink); 2008 2009 if (state->grid[y * w2 + x] == N_ONE) 2010 draw_rect(dr, tx, ty, tilesize, tilesize, ink); 2011 else if (state->grid[y * w2 + x] == N_ZERO) 2012 draw_circle(dr, tx + tilesize/2, ty + tilesize/2, 2013 tilesize/12, ink, ink); 2014 } 2015} 2016 2017#ifdef COMBINED 2018#define thegame unruly 2019#endif 2020 2021const struct game thegame = { 2022 "Unruly", "games.unruly", "unruly", 2023 default_params, 2024 game_fetch_preset, NULL, 2025 decode_params, 2026 encode_params, 2027 free_params, 2028 dup_params, 2029 true, game_configure, custom_params, 2030 validate_params, 2031 new_game_desc, 2032 validate_desc, 2033 new_game, 2034 dup_game, 2035 free_game, 2036 true, solve_game, 2037 true, game_can_format_as_text_now, game_text_format, 2038 NULL, NULL, /* get_prefs, set_prefs */ 2039 new_ui, 2040 free_ui, 2041 NULL, /* encode_ui */ 2042 NULL, /* decode_ui */ 2043 NULL, /* game_request_keys */ 2044 game_changed_state, 2045 current_key_label, 2046 interpret_move, 2047 execute_move, 2048 DEFAULT_TILE_SIZE, game_compute_size, game_set_size, 2049 game_colours, 2050 game_new_drawstate, 2051 game_free_drawstate, 2052 game_redraw, 2053 game_anim_length, 2054 game_flash_length, 2055 game_get_cursor_location, 2056 game_status, 2057 true, false, game_print_size, game_print, 2058 false, /* wants_statusbar */ 2059 false, NULL, /* timing_state */ 2060 0, /* flags */ 2061}; 2062 2063/* ***************** * 2064 * Standalone solver * 2065 * ***************** */ 2066 2067#ifdef STANDALONE_SOLVER 2068#include <time.h> 2069#include <stdarg.h> 2070 2071/* Most of the standalone solver code was copied from unequal.c and singles.c */ 2072 2073static const char *quis; 2074 2075static void usage_exit(const char *msg) 2076{ 2077 if (msg) 2078 fprintf(stderr, "%s: %s\n", quis, msg); 2079 fprintf(stderr, 2080 "Usage: %s [-v] [--seed SEED] <params> | [game_id [game_id ...]]\n", 2081 quis); 2082 exit(1); 2083} 2084 2085int main(int argc, char *argv[]) 2086{ 2087 random_state *rs; 2088 time_t seed = time(NULL); 2089 2090 game_params *params = NULL; 2091 2092 char *id = NULL, *desc = NULL; 2093 const char *err; 2094 2095 quis = argv[0]; 2096 2097 while (--argc > 0) { 2098 char *p = *++argv; 2099 if (!strcmp(p, "--seed")) { 2100 if (argc == 0) 2101 usage_exit("--seed needs an argument"); 2102 seed = (time_t) atoi(*++argv); 2103 argc--; 2104 } else if (!strcmp(p, "-v")) 2105 solver_verbose = true; 2106 else if (*p == '-') 2107 usage_exit("unrecognised option"); 2108 else 2109 id = p; 2110 } 2111 2112 if (id) { 2113 desc = strchr(id, ':'); 2114 if (desc) 2115 *desc++ = '\0'; 2116 2117 params = default_params(); 2118 decode_params(params, id); 2119 err = validate_params(params, true); 2120 if (err) { 2121 fprintf(stderr, "Parameters are invalid\n"); 2122 fprintf(stderr, "%s: %s", argv[0], err); 2123 exit(1); 2124 } 2125 } 2126 2127 if (!desc) { 2128 char *desc_gen, *aux; 2129 rs = random_new((void *) &seed, sizeof(time_t)); 2130 if (!params) 2131 params = default_params(); 2132 printf("Generating puzzle with parameters %s\n", 2133 encode_params(params, true)); 2134 desc_gen = new_game_desc(params, rs, &aux, false); 2135 2136 if (!solver_verbose) { 2137 char *fmt = game_text_format(new_game(NULL, params, desc_gen)); 2138 fputs(fmt, stdout); 2139 sfree(fmt); 2140 } 2141 2142 printf("Game ID: %s\n", desc_gen); 2143 } else { 2144 game_state *input; 2145 struct unruly_scratch *scratch; 2146 int maxdiff, errcode; 2147 2148 err = validate_desc(params, desc); 2149 if (err) { 2150 fprintf(stderr, "Description is invalid\n"); 2151 fprintf(stderr, "%s", err); 2152 exit(1); 2153 } 2154 2155 input = new_game(NULL, params, desc); 2156 scratch = unruly_new_scratch(input); 2157 2158 maxdiff = unruly_solve_game(input, scratch, DIFFCOUNT); 2159 2160 errcode = unruly_validate_counts(input, scratch, NULL); 2161 if (unruly_validate_all_rows(input, NULL) == -1) 2162 errcode = -1; 2163 2164 if (errcode != -1) { 2165 char *fmt = game_text_format(input); 2166 fputs(fmt, stdout); 2167 sfree(fmt); 2168 if (maxdiff < 0) 2169 printf("Difficulty: already solved!\n"); 2170 else 2171 printf("Difficulty: %s\n", unruly_diffnames[maxdiff]); 2172 } 2173 2174 if (errcode == 1) 2175 printf("No solution found.\n"); 2176 else if (errcode == -1) 2177 printf("Puzzle is invalid.\n"); 2178 2179 free_game(input); 2180 unruly_free_scratch(scratch); 2181 } 2182 2183 return 0; 2184} 2185#endif