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
7 * Objective of the game: Fill the grid with zeros and ones, with the
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.
12 * This puzzle type is known under several names, including
13 * Tohu-Wa-Vohu, One and Two and Binairo.
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 has been discarded for this implementation.
20 * http://www.janko.at/Raetsel/Tohu-Wa-Vohu/index.htm
24 * Possible future improvements:
26 * More solver cleverness
28 * - a counting-based deduction in which you find groups of squares
29 * which must each contain at least one of a given colour, plus
30 * other squares which are already known to be that colour, and see
31 * if you have any squares left over when you've worked out where
32 * they all have to be. This is a generalisation of the current
33 * check_near_complete: where that only covers rows with three
34 * unfilled squares, this would handle more, such as
36 * in which each of the two-square gaps must contain a 0, and there
37 * are three 0s placed, and that means the rightmost square can't
40 * - an 'Unreasonable' difficulty level, supporting recursion and
53 #ifdef STANDALONE_SOLVER
54 int solver_verbose = FALSE;
62 * When editing this enum, maintain the invariants
63 * COL_n_HIGHLIGHT = COL_n + 1
64 * COL_n_LOWLIGHT = COL_n + 2
78 int w2, h2; /* full grid width and height respectively */
79 int unique; /* should row and column patterns be unique? */
86 #define ENUM(upper,title,lower) DIFF_ ## upper,
87 #define TITLE(upper,title,lower) #title,
88 #define ENCODE(upper,title,lower) #lower
89 #define CONFIG(upper,title,lower) ":" #title
90 enum { DIFFLIST(ENUM) DIFFCOUNT };
91 static char const *const unruly_diffnames[] = { DIFFLIST(TITLE) };
93 static char const unruly_diffchars[] = DIFFLIST(ENCODE);
94 #define DIFFCONFIG DIFFLIST(CONFIG)
96 const static struct game_params unruly_presets[] = {
97 { 8, 8, FALSE, DIFF_EASY},
98 { 8, 8, FALSE, DIFF_NORMAL},
99 {10, 10, FALSE, DIFF_EASY},
100 {10, 10, FALSE, DIFF_NORMAL},
101 {14, 14, FALSE, DIFF_EASY},
102 {14, 14, FALSE, DIFF_NORMAL}
105 #define DEFAULT_PRESET 0
114 #define FE_HOR_ROW_LEFT 0x0001
115 #define FE_HOR_ROW_MID 0x0003
116 #define FE_HOR_ROW_RIGHT 0x0002
118 #define FE_VER_ROW_TOP 0x0004
119 #define FE_VER_ROW_MID 0x000C
120 #define FE_VER_ROW_BOTTOM 0x0008
122 #define FE_COUNT 0x0010
124 #define FE_ROW_MATCH 0x0020
125 #define FE_COL_MATCH 0x0040
127 #define FF_ONE 0x0080
128 #define FF_ZERO 0x0100
129 #define FF_CURSOR 0x0200
131 #define FF_FLASH1 0x0400
132 #define FF_FLASH2 0x0800
133 #define FF_IMMUTABLE 0x1000
139 unsigned char *immutable;
141 int completed, cheated;
144 static game_params *default_params(void)
146 game_params *ret = snew(game_params);
148 *ret = unruly_presets[DEFAULT_PRESET]; /* structure copy */
153 static int game_fetch_preset(int i, char **name, game_params **params)
158 if (i < 0 || i >= lenof(unruly_presets))
161 ret = snew(game_params);
162 *ret = unruly_presets[i]; /* structure copy */
164 sprintf(buf, "%dx%d %s", ret->w2, ret->h2, unruly_diffnames[ret->diff]);
171 static void free_params(game_params *params)
176 static game_params *dup_params(const game_params *params)
178 game_params *ret = snew(game_params);
179 *ret = *params; /* structure copy */
183 static void decode_params(game_params *params, char const *string)
185 char const *p = string;
187 params->unique = FALSE;
189 params->w2 = atoi(p);
190 while (*p && isdigit((unsigned char)*p)) p++;
193 params->h2 = atoi(p);
194 while (*p && isdigit((unsigned char)*p)) p++;
196 params->h2 = params->w2;
201 params->unique = TRUE;
207 params->diff = DIFFCOUNT + 1; /* ...which is invalid */
209 for (i = 0; i < DIFFCOUNT; i++) {
210 if (*p == unruly_diffchars[i])
218 static char *encode_params(const game_params *params, int full)
222 sprintf(buf, "%dx%d", params->w2, params->h2);
226 sprintf(buf + strlen(buf), "d%c", unruly_diffchars[params->diff]);
231 static config_item *game_configure(const game_params *params)
236 ret = snewn(5, config_item);
238 ret[0].name = "Width";
239 ret[0].type = C_STRING;
240 sprintf(buf, "%d", params->w2);
241 ret[0].sval = dupstr(buf);
244 ret[1].name = "Height";
245 ret[1].type = C_STRING;
246 sprintf(buf, "%d", params->h2);
247 ret[1].sval = dupstr(buf);
250 ret[2].name = "Unique rows and columns";
251 ret[2].type = C_BOOLEAN;
252 ret[2].ival = params->unique;
254 ret[3].name = "Difficulty";
255 ret[3].type = C_CHOICES;
256 ret[3].sval = DIFFCONFIG;
257 ret[3].ival = params->diff;
267 static game_params *custom_params(const config_item *cfg)
269 game_params *ret = snew(game_params);
271 ret->w2 = atoi(cfg[0].sval);
272 ret->h2 = atoi(cfg[1].sval);
273 ret->unique = cfg[2].ival;
274 ret->diff = cfg[3].ival;
279 static char *validate_params(const game_params *params, int full)
281 if ((params->w2 & 1) || (params->h2 & 1))
282 return "Width and height must both be even";
283 if (params->w2 < 6 || params->h2 < 6)
284 return "Width and height must be at least 6";
285 if (params->unique) {
286 static const long A177790[] = {
288 * The nth element of this array gives the number of
289 * distinct possible Unruly rows of length 2n (that is,
290 * containing exactly n 1s and n 0s and not containing
291 * three consecutive elements the same) for as long as
292 * those numbers fit in a 32-bit signed int.
294 * So in unique-rows mode, if the puzzle width is 2n, then
295 * the height must be at most (this array)[n], and vice
298 * This is sequence A177790 in the Online Encyclopedia of
299 * Integer Sequences: http://oeis.org/A177790
301 1L, 2L, 6L, 14L, 34L, 84L, 208L, 518L, 1296L, 3254L,
302 8196L, 20700L, 52404L, 132942L, 337878L, 860142L,
303 2192902L, 5598144L, 14308378L, 36610970L, 93770358L,
304 240390602L, 616787116L, 1583765724L
306 if (params->w2 < 2*lenof(A177790) &&
307 params->h2 > A177790[params->w2/2]) {
308 return "Puzzle is too tall for unique-rows mode";
310 if (params->h2 < 2*lenof(A177790) &&
311 params->w2 > A177790[params->h2/2]) {
312 return "Puzzle is too long for unique-rows mode";
315 if (params->diff >= DIFFCOUNT)
316 return "Unknown difficulty rating";
321 static char *validate_desc(const game_params *params, const char *desc)
323 int w2 = params->w2, h2 = params->h2;
326 const char *p = desc;
330 if (*p >= 'a' && *p < 'z')
331 pos += 1 + (*p - 'a');
332 else if (*p >= 'A' && *p < 'Z')
333 pos += 1 + (*p - 'A');
334 else if (*p == 'Z' || *p == 'z')
337 return "Description contains invalid characters";
343 return "Description too short";
345 return "Description too long";
350 static game_state *blank_state(int w2, int h2, int unique)
352 game_state *state = snew(game_state);
357 state->unique = unique;
358 state->grid = snewn(s, char);
359 state->immutable = snewn(s, unsigned char);
361 memset(state->grid, EMPTY, s);
362 memset(state->immutable, FALSE, s);
364 state->completed = state->cheated = FALSE;
369 static game_state *new_game(midend *me, const game_params *params,
372 int w2 = params->w2, h2 = params->h2;
375 game_state *state = blank_state(w2, h2, params->unique);
377 const char *p = desc;
381 if (*p >= 'a' && *p < 'z') {
384 state->grid[pos] = N_ZERO;
385 state->immutable[pos] = TRUE;
388 } else if (*p >= 'A' && *p < 'Z') {
391 state->grid[pos] = N_ONE;
392 state->immutable[pos] = TRUE;
395 } else if (*p == 'Z' || *p == 'z') {
398 assert(!"Description contains invalid characters");
407 static game_state *dup_game(const game_state *state)
409 int w2 = state->w2, h2 = state->h2;
412 game_state *ret = blank_state(w2, h2, state->unique);
414 memcpy(ret->grid, state->grid, s);
415 memcpy(ret->immutable, state->immutable, s);
417 ret->completed = state->completed;
418 ret->cheated = state->cheated;
423 static void free_game(game_state *state)
426 sfree(state->immutable);
431 static int game_can_format_as_text_now(const game_params *params)
436 static char *game_text_format(const game_state *state)
438 int w2 = state->w2, h2 = state->h2;
441 char *ret = snewn(lr * h2 + 1, char);
445 for (y = 0; y < h2; y++) {
446 for (x = 0; x < w2; x++) {
448 char c = state->grid[y * w2 + x];
449 *p++ = (c == N_ONE ? '1' : c == N_ZERO ? '0' : '.');
465 struct unruly_scratch {
472 static void unruly_solver_update_remaining(const game_state *state,
473 struct unruly_scratch *scratch)
475 int w2 = state->w2, h2 = state->h2;
478 /* Reset all scratch data */
479 memset(scratch->ones_rows, 0, h2 * sizeof(int));
480 memset(scratch->ones_cols, 0, w2 * sizeof(int));
481 memset(scratch->zeros_rows, 0, h2 * sizeof(int));
482 memset(scratch->zeros_cols, 0, w2 * sizeof(int));
484 for (x = 0; x < w2; x++)
485 for (y = 0; y < h2; y++) {
486 if (state->grid[y * w2 + x] == N_ONE) {
487 scratch->ones_rows[y]++;
488 scratch->ones_cols[x]++;
489 } else if (state->grid[y * w2 + x] == N_ZERO) {
490 scratch->zeros_rows[y]++;
491 scratch->zeros_cols[x]++;
496 static struct unruly_scratch *unruly_new_scratch(const game_state *state)
498 int w2 = state->w2, h2 = state->h2;
500 struct unruly_scratch *ret = snew(struct unruly_scratch);
502 ret->ones_rows = snewn(h2, int);
503 ret->ones_cols = snewn(w2, int);
504 ret->zeros_rows = snewn(h2, int);
505 ret->zeros_cols = snewn(w2, int);
507 unruly_solver_update_remaining(state, ret);
512 static void unruly_free_scratch(struct unruly_scratch *scratch)
514 sfree(scratch->ones_rows);
515 sfree(scratch->ones_cols);
516 sfree(scratch->zeros_rows);
517 sfree(scratch->zeros_cols);
522 static int unruly_solver_check_threes(game_state *state, int *rowcount,
523 int *colcount, int horizontal,
524 char check, char block)
526 int w2 = state->w2, h2 = state->h2;
528 int dx = horizontal ? 1 : 0, dy = 1 - dx;
529 int sx = dx, sy = dy;
530 int ex = w2 - dx, ey = h2 - dy;
535 /* Check for any three squares which almost form three in a row */
536 for (y = sy; y < ey; y++) {
537 for (x = sx; x < ex; x++) {
538 int i1 = (y-dy) * w2 + (x-dx);
540 int i3 = (y+dy) * w2 + (x+dx);
542 if (state->grid[i1] == check && state->grid[i2] == check
543 && state->grid[i3] == EMPTY) {
545 #ifdef STANDALONE_SOLVER
546 if (solver_verbose) {
547 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n",
548 i1 % w2, i1 / w2, i2 % w2, i2 / w2,
549 (block == N_ONE ? '1' : '0'), i3 % w2,
553 state->grid[i3] = block;
557 if (state->grid[i1] == check && state->grid[i2] == EMPTY
558 && state->grid[i3] == check) {
560 #ifdef STANDALONE_SOLVER
561 if (solver_verbose) {
562 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n",
563 i1 % w2, i1 / w2, i3 % w2, i3 / w2,
564 (block == N_ONE ? '1' : '0'), i2 % w2,
568 state->grid[i2] = block;
572 if (state->grid[i1] == EMPTY && state->grid[i2] == check
573 && state->grid[i3] == check) {
575 #ifdef STANDALONE_SOLVER
576 if (solver_verbose) {
577 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n",
578 i2 % w2, i2 / w2, i3 % w2, i3 / w2,
579 (block == N_ONE ? '1' : '0'), i1 % w2,
583 state->grid[i1] = block;
593 static int unruly_solver_check_all_threes(game_state *state,
594 struct unruly_scratch *scratch)
599 unruly_solver_check_threes(state, scratch->zeros_rows,
600 scratch->zeros_cols, TRUE, N_ONE, N_ZERO);
602 unruly_solver_check_threes(state, scratch->ones_rows,
603 scratch->ones_cols, TRUE, N_ZERO, N_ONE);
605 unruly_solver_check_threes(state, scratch->zeros_rows,
606 scratch->zeros_cols, FALSE, N_ONE,
609 unruly_solver_check_threes(state, scratch->ones_rows,
610 scratch->ones_cols, FALSE, N_ZERO, N_ONE);
615 static int unruly_solver_check_uniques(game_state *state, int *rowcount,
616 int horizontal, char check, char block,
617 struct unruly_scratch *scratch)
619 int w2 = state->w2, h2 = state->h2;
621 int rmult = (horizontal ? w2 : 1);
622 int cmult = (horizontal ? 1 : w2);
623 int nr = (horizontal ? h2 : w2);
624 int nc = (horizontal ? w2 : h2);
631 * Find each row that has max entries of type 'check', and see if
632 * all those entries match those in any row with max-1 entries. If
633 * so, set the last non-matching entry of the latter row to ensure
634 * that it's different.
636 for (r = 0; r < nr; r++) {
637 if (rowcount[r] != max)
639 for (r2 = 0; r2 < nr; r2++) {
640 int nmatch = 0, nonmatch = -1;
641 if (rowcount[r2] != max-1)
643 for (c = 0; c < nc; c++) {
644 if (state->grid[r*rmult + c*cmult] == check) {
645 if (state->grid[r2*rmult + c*cmult] == check)
651 if (nmatch == max-1) {
652 int i1 = r2 * rmult + nonmatch * cmult;
653 assert(nonmatch != -1);
654 if (state->grid[i1] == block)
656 assert(state->grid[i1] == EMPTY);
657 #ifdef STANDALONE_SOLVER
658 if (solver_verbose) {
659 printf("Solver: matching %s %i, %i gives %c at %i,%i\n",
660 horizontal ? "rows" : "cols",
661 r, r2, (block == N_ONE ? '1' : '0'), i1 % w2,
665 state->grid[i1] = block;
666 if (block == N_ONE) {
667 scratch->ones_rows[i1 / w2]++;
668 scratch->ones_cols[i1 % w2]++;
670 scratch->zeros_rows[i1 / w2]++;
671 scratch->zeros_cols[i1 % w2]++;
680 static int unruly_solver_check_all_uniques(game_state *state,
681 struct unruly_scratch *scratch)
685 ret += unruly_solver_check_uniques(state, scratch->ones_rows,
686 TRUE, N_ONE, N_ZERO, scratch);
687 ret += unruly_solver_check_uniques(state, scratch->zeros_rows,
688 TRUE, N_ZERO, N_ONE, scratch);
689 ret += unruly_solver_check_uniques(state, scratch->ones_cols,
690 FALSE, N_ONE, N_ZERO, scratch);
691 ret += unruly_solver_check_uniques(state, scratch->zeros_cols,
692 FALSE, N_ZERO, N_ONE, scratch);
697 static int unruly_solver_fill_row(game_state *state, int i, int horizontal,
698 int *rowcount, int *colcount, char fill)
701 int w2 = state->w2, h2 = state->h2;
704 #ifdef STANDALONE_SOLVER
705 if (solver_verbose) {
706 printf("Solver: Filling %s %i with %c:",
707 (horizontal ? "Row" : "Col"), i,
708 (fill == N_ZERO ? '0' : '1'));
711 /* Place a number in every empty square in a row/column */
712 for (j = 0; j < (horizontal ? w2 : h2); j++) {
713 int p = (horizontal ? i * w2 + j : j * w2 + i);
715 if (state->grid[p] == EMPTY) {
716 #ifdef STANDALONE_SOLVER
717 if (solver_verbose) {
718 printf(" (%i,%i)", (horizontal ? j : i),
719 (horizontal ? i : j));
723 state->grid[p] = fill;
724 rowcount[(horizontal ? i : j)]++;
725 colcount[(horizontal ? j : i)]++;
729 #ifdef STANDALONE_SOLVER
730 if (solver_verbose) {
738 static int unruly_solver_check_complete_nums(game_state *state,
739 int *complete, int horizontal,
740 int *rowcount, int *colcount,
743 int w2 = state->w2, h2 = state->h2;
744 int count = (horizontal ? h2 : w2); /* number of rows to check */
745 int target = (horizontal ? w2 : h2) / 2; /* target number of 0s/1s */
746 int *other = (horizontal ? rowcount : colcount);
751 /* Check for completed rows/cols for one number, then fill in the rest */
752 for (i = 0; i < count; i++) {
753 if (complete[i] == target && other[i] < target) {
754 #ifdef STANDALONE_SOLVER
755 if (solver_verbose) {
756 printf("Solver: Row %i satisfied for %c\n", i,
757 (fill != N_ZERO ? '0' : '1'));
760 ret += unruly_solver_fill_row(state, i, horizontal, rowcount,
768 static int unruly_solver_check_all_complete_nums(game_state *state,
769 struct unruly_scratch *scratch)
774 unruly_solver_check_complete_nums(state, scratch->ones_rows, TRUE,
776 scratch->zeros_cols, N_ZERO);
778 unruly_solver_check_complete_nums(state, scratch->ones_cols, FALSE,
780 scratch->zeros_cols, N_ZERO);
782 unruly_solver_check_complete_nums(state, scratch->zeros_rows, TRUE,
784 scratch->ones_cols, N_ONE);
786 unruly_solver_check_complete_nums(state, scratch->zeros_cols, FALSE,
788 scratch->ones_cols, N_ONE);
793 static int unruly_solver_check_near_complete(game_state *state,
794 int *complete, int horizontal,
795 int *rowcount, int *colcount,
798 int w2 = state->w2, h2 = state->h2;
799 int w = w2/2, h = h2/2;
801 int dx = horizontal ? 1 : 0, dy = 1 - dx;
803 int sx = dx, sy = dy;
804 int ex = w2 - dx, ey = h2 - dy;
810 * This function checks for a row with one Y remaining, then looks
811 * for positions that could cause the remaining squares in the row
812 * to make 3 X's in a row. Example:
814 * Consider the following row:
816 * If the last 1 was placed in the last square, the remaining
817 * squares would be 0:
819 * This violates the 3 in a row rule. We now know that the last 1
820 * shouldn't be in the last cell.
824 /* Check for any two blank and one filled square */
825 for (y = sy; y < ey; y++) {
826 /* One type must have 1 remaining, the other at least 2 */
827 if (horizontal && (complete[y] < w - 1 || rowcount[y] > w - 2))
830 for (x = sx; x < ex; x++) {
833 && (complete[x] < h - 1 || colcount[x] > h - 2))
836 i = (horizontal ? y : x);
837 i1 = (y-dy) * w2 + (x-dx);
839 i3 = (y+dy) * w2 + (x+dx);
841 if (state->grid[i1] == fill && state->grid[i2] == EMPTY
842 && state->grid[i3] == EMPTY) {
844 * Temporarily fill the empty spaces with something else.
845 * This avoids raising the counts for the row and column
847 state->grid[i2] = BOGUS;
848 state->grid[i3] = BOGUS;
850 #ifdef STANDALONE_SOLVER
851 if (solver_verbose) {
852 printf("Solver: Row %i nearly satisfied for %c\n", i,
853 (fill != N_ZERO ? '0' : '1'));
857 unruly_solver_fill_row(state, i, horizontal, rowcount,
860 state->grid[i2] = EMPTY;
861 state->grid[i3] = EMPTY;
864 else if (state->grid[i1] == EMPTY && state->grid[i2] == fill
865 && state->grid[i3] == EMPTY) {
866 state->grid[i1] = BOGUS;
867 state->grid[i3] = BOGUS;
869 #ifdef STANDALONE_SOLVER
870 if (solver_verbose) {
871 printf("Solver: Row %i nearly satisfied for %c\n", i,
872 (fill != N_ZERO ? '0' : '1'));
876 unruly_solver_fill_row(state, i, horizontal, rowcount,
879 state->grid[i1] = EMPTY;
880 state->grid[i3] = EMPTY;
883 else if (state->grid[i1] == EMPTY && state->grid[i2] == EMPTY
884 && state->grid[i3] == fill) {
885 state->grid[i1] = BOGUS;
886 state->grid[i2] = BOGUS;
888 #ifdef STANDALONE_SOLVER
889 if (solver_verbose) {
890 printf("Solver: Row %i nearly satisfied for %c\n", i,
891 (fill != N_ZERO ? '0' : '1'));
895 unruly_solver_fill_row(state, i, horizontal, rowcount,
898 state->grid[i1] = EMPTY;
899 state->grid[i2] = EMPTY;
902 else if (state->grid[i1] == EMPTY && state->grid[i2] == EMPTY
903 && state->grid[i3] == EMPTY) {
904 state->grid[i1] = BOGUS;
905 state->grid[i2] = BOGUS;
906 state->grid[i3] = BOGUS;
908 #ifdef STANDALONE_SOLVER
909 if (solver_verbose) {
910 printf("Solver: Row %i nearly satisfied for %c\n", i,
911 (fill != N_ZERO ? '0' : '1'));
915 unruly_solver_fill_row(state, i, horizontal, rowcount,
918 state->grid[i1] = EMPTY;
919 state->grid[i2] = EMPTY;
920 state->grid[i3] = EMPTY;
928 static int unruly_solver_check_all_near_complete(game_state *state,
929 struct unruly_scratch *scratch)
934 unruly_solver_check_near_complete(state, scratch->ones_rows, TRUE,
936 scratch->zeros_cols, N_ZERO);
938 unruly_solver_check_near_complete(state, scratch->ones_cols, FALSE,
940 scratch->zeros_cols, N_ZERO);
942 unruly_solver_check_near_complete(state, scratch->zeros_rows, TRUE,
944 scratch->ones_cols, N_ONE);
946 unruly_solver_check_near_complete(state, scratch->zeros_cols, FALSE,
948 scratch->ones_cols, N_ONE);
953 static int unruly_validate_rows(const game_state *state, int horizontal,
954 char check, int *errors)
956 int w2 = state->w2, h2 = state->h2;
958 int dx = horizontal ? 1 : 0, dy = 1 - dx;
960 int sx = dx, sy = dy;
961 int ex = w2 - dx, ey = h2 - dy;
966 int err1 = (horizontal ? FE_HOR_ROW_LEFT : FE_VER_ROW_TOP);
967 int err2 = (horizontal ? FE_HOR_ROW_MID : FE_VER_ROW_MID);
968 int err3 = (horizontal ? FE_HOR_ROW_RIGHT : FE_VER_ROW_BOTTOM);
970 /* Check for any three in a row, and mark errors accordingly (if
972 for (y = sy; y < ey; y++) {
973 for (x = sx; x < ex; x++) {
974 int i1 = (y-dy) * w2 + (x-dx);
976 int i3 = (y+dy) * w2 + (x+dx);
978 if (state->grid[i1] == check && state->grid[i2] == check
979 && state->grid[i3] == check) {
993 static int unruly_validate_unique(const game_state *state, int horizontal,
996 int w2 = state->w2, h2 = state->h2;
998 int rmult = (horizontal ? w2 : 1);
999 int cmult = (horizontal ? 1 : w2);
1000 int nr = (horizontal ? h2 : w2);
1001 int nc = (horizontal ? w2 : h2);
1002 int err = (horizontal ? FE_ROW_MATCH : FE_COL_MATCH);
1007 /* Check for any two full rows matching exactly, and mark errors
1008 * accordingly (if required) */
1009 for (r = 0; r < nr; r++) {
1011 for (c = 0; c < nc; c++)
1012 if (state->grid[r*rmult + c*cmult] != EMPTY)
1016 for (r2 = r+1; r2 < nr; r2++) {
1018 for (c = 0; c < nc; c++)
1019 if (state->grid[r*rmult + c*cmult] !=
1020 state->grid[r2*rmult + c*cmult])
1024 for (c = 0; c < nc; c++) {
1025 errors[r*rmult + c*cmult] |= err;
1026 errors[r2*rmult + c*cmult] |= err;
1037 static int unruly_validate_all_rows(const game_state *state, int *errors)
1041 errcount += unruly_validate_rows(state, TRUE, N_ONE, errors);
1042 errcount += unruly_validate_rows(state, FALSE, N_ONE, errors);
1043 errcount += unruly_validate_rows(state, TRUE, N_ZERO, errors);
1044 errcount += unruly_validate_rows(state, FALSE, N_ZERO, errors);
1046 if (state->unique) {
1047 errcount += unruly_validate_unique(state, TRUE, errors);
1048 errcount += unruly_validate_unique(state, FALSE, errors);
1056 static int unruly_validate_counts(const game_state *state,
1057 struct unruly_scratch *scratch, int *errors)
1059 int w2 = state->w2, h2 = state->h2;
1060 int w = w2/2, h = h2/2;
1065 /* See if all rows/columns are satisfied. If one is exceeded,
1066 * mark it as an error (if required)
1069 char hasscratch = TRUE;
1071 scratch = unruly_new_scratch(state);
1075 for (i = 0; i < w2; i++) {
1076 if (scratch->ones_cols[i] < h)
1078 if (scratch->zeros_cols[i] < h)
1081 if (scratch->ones_cols[i] > h) {
1084 errors[2*h2 + i] = TRUE;
1086 errors[2*h2 + i] = FALSE;
1088 if (scratch->zeros_cols[i] > h) {
1091 errors[2*h2 + w2 + i] = TRUE;
1093 errors[2*h2 + w2 + i] = FALSE;
1095 for (i = 0; i < h2; i++) {
1096 if (scratch->ones_rows[i] < w)
1098 if (scratch->zeros_rows[i] < w)
1101 if (scratch->ones_rows[i] > w) {
1108 if (scratch->zeros_rows[i] > w) {
1111 errors[h2 + i] = TRUE;
1113 errors[h2 + i] = FALSE;
1117 unruly_free_scratch(scratch);
1119 return (above ? -1 : below ? 1 : 0);
1122 static int unruly_solve_game(game_state *state,
1123 struct unruly_scratch *scratch, int diff)
1125 int done, maxdiff = -1;
1130 /* Check for impending 3's */
1131 done += unruly_solver_check_all_threes(state, scratch);
1133 /* Keep using the simpler techniques while they produce results */
1135 if (maxdiff < DIFF_EASY)
1136 maxdiff = DIFF_EASY;
1140 /* Check for completed rows */
1141 done += unruly_solver_check_all_complete_nums(state, scratch);
1144 if (maxdiff < DIFF_EASY)
1145 maxdiff = DIFF_EASY;
1149 /* Check for impending failures of row/column uniqueness, if
1150 * it's enabled in this game mode */
1151 if (state->unique) {
1152 done += unruly_solver_check_all_uniques(state, scratch);
1155 if (maxdiff < DIFF_EASY)
1156 maxdiff = DIFF_EASY;
1161 /* Normal techniques */
1162 if (diff < DIFF_NORMAL)
1165 /* Check for nearly completed rows */
1166 done += unruly_solver_check_all_near_complete(state, scratch);
1169 if (maxdiff < DIFF_NORMAL)
1170 maxdiff = DIFF_NORMAL;
1179 static char *solve_game(const game_state *state, const game_state *currstate,
1180 const char *aux, char **error)
1182 game_state *solved = dup_game(state);
1183 struct unruly_scratch *scratch = unruly_new_scratch(solved);
1187 unruly_solve_game(solved, scratch, DIFFCOUNT);
1189 result = unruly_validate_counts(solved, scratch, NULL);
1190 if (unruly_validate_all_rows(solved, NULL) == -1)
1194 int w2 = solved->w2, h2 = solved->h2;
1199 ret = snewn(s + 2, char);
1203 for (i = 0; i < s; i++)
1204 *p++ = (solved->grid[i] == N_ONE ? '1' : '0');
1207 } else if (result == 1)
1208 *error = "No solution found.";
1209 else if (result == -1)
1210 *error = "Puzzle is invalid.";
1213 unruly_free_scratch(scratch);
1221 static int unruly_fill_game(game_state *state, struct unruly_scratch *scratch,
1225 int w2 = state->w2, h2 = state->h2;
1230 #ifdef STANDALONE_SOLVER
1231 if (solver_verbose) {
1232 printf("Generator: Attempt to fill grid\n");
1236 /* Generate random array of spaces */
1237 spaces = snewn(s, int);
1238 for (i = 0; i < s; i++)
1240 shuffle(spaces, s, sizeof(*spaces), rs);
1243 * Construct a valid filled grid by repeatedly picking an unfilled
1244 * space and fill it, then calling the solver to fill in any
1245 * spaces forced by the change.
1247 for (j = 0; j < s; j++) {
1250 if (state->grid[i] != EMPTY)
1253 if (random_upto(rs, 2)) {
1254 state->grid[i] = N_ONE;
1255 scratch->ones_rows[i / w2]++;
1256 scratch->ones_cols[i % w2]++;
1258 state->grid[i] = N_ZERO;
1259 scratch->zeros_rows[i / w2]++;
1260 scratch->zeros_cols[i % w2]++;
1263 unruly_solve_game(state, scratch, DIFFCOUNT);
1267 if (unruly_validate_all_rows(state, NULL) != 0
1268 || unruly_validate_counts(state, scratch, NULL) != 0)
1274 static char *new_game_desc(const game_params *params, random_state *rs,
1275 char **aux, int interactive)
1277 #ifdef STANDALONE_SOLVER
1279 int temp_verbose = FALSE;
1282 int w2 = params->w2, h2 = params->h2;
1289 struct unruly_scratch *scratch;
1297 state = blank_state(w2, h2, params->unique);
1298 scratch = unruly_new_scratch(state);
1299 if (unruly_fill_game(state, scratch, rs))
1302 unruly_free_scratch(scratch);
1305 #ifdef STANDALONE_SOLVER
1306 if (solver_verbose) {
1307 printf("Puzzle generated in %i attempts\n", attempts);
1308 debug = game_text_format(state);
1309 fputs(debug, stdout);
1312 temp_verbose = solver_verbose;
1313 solver_verbose = FALSE;
1317 unruly_free_scratch(scratch);
1319 /* Generate random array of spaces */
1320 spaces = snewn(s, int);
1321 for (i = 0; i < s; i++)
1323 shuffle(spaces, s, sizeof(*spaces), rs);
1326 * Winnow the clues by starting from our filled grid, repeatedly
1327 * picking a filled space and emptying it, as long as the solver
1328 * reports that the puzzle can still be solved after doing so.
1330 for (j = 0; j < s; j++) {
1337 state->grid[i] = EMPTY;
1339 solver = dup_game(state);
1340 scratch = unruly_new_scratch(state);
1342 unruly_solve_game(solver, scratch, params->diff);
1344 if (unruly_validate_counts(solver, scratch, NULL) != 0)
1348 unruly_free_scratch(scratch);
1352 #ifdef STANDALONE_SOLVER
1354 solver_verbose = TRUE;
1356 printf("Final puzzle:\n");
1357 debug = game_text_format(state);
1358 fputs(debug, stdout);
1364 * See if the game has accidentally come out too easy.
1366 if (params->diff > 0) {
1370 solver = dup_game(state);
1371 scratch = unruly_new_scratch(state);
1373 unruly_solve_game(solver, scratch, params->diff - 1);
1375 ok = unruly_validate_counts(solver, scratch, NULL);
1378 unruly_free_scratch(scratch);
1384 * Puzzles of the easiest difficulty can't be too easy.
1390 /* Encode description */
1391 ret = snewn(s + 1, char);
1394 for (i = 0; i < s+1; i++) {
1395 if (i == s || state->grid[i] == N_ZERO) {
1402 } else if (state->grid[i] == N_ONE) {
1429 static game_ui *new_ui(const game_state *state)
1431 game_ui *ret = snew(game_ui);
1433 ret->cx = ret->cy = 0;
1434 ret->cursor = FALSE;
1439 static void free_ui(game_ui *ui)
1444 static char *encode_ui(const game_ui *ui)
1449 static void decode_ui(game_ui *ui, const char *encoding)
1453 static void game_changed_state(game_ui *ui, const game_state *oldstate,
1454 const game_state *newstate)
1458 struct game_drawstate {
1469 static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1471 struct game_drawstate *ds = snew(struct game_drawstate);
1473 int w2 = state->w2, h2 = state->h2;
1480 ds->started = FALSE;
1482 ds->gridfs = snewn(s, int);
1483 ds->rowfs = snewn(2 * (w2 + h2), int);
1485 ds->grid = snewn(s, int);
1486 for (i = 0; i < s; i++)
1492 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1500 #define COORD(x) ( (x) * ds->tilesize + ds->tilesize/2 )
1501 #define FROMCOORD(x) ( ((x)-(ds->tilesize/2)) / ds->tilesize )
1503 static char *interpret_move(const game_state *state, game_ui *ui,
1504 const game_drawstate *ds,
1505 int ox, int oy, int button)
1510 int gx = FROMCOORD(ox);
1511 int gy = FROMCOORD(oy);
1513 int w2 = state->w2, h2 = state->h2;
1515 button &= ~MOD_MASK;
1518 if (button == LEFT_BUTTON || button == RIGHT_BUTTON ||
1519 button == MIDDLE_BUTTON) {
1520 if (ox >= (ds->tilesize / 2) && gx < w2
1521 && oy >= (ds->tilesize / 2) && gy < h2) {
1530 if (IS_CURSOR_MOVE(button)) {
1531 move_cursor(button, &ui->cx, &ui->cy, w2, h2, 0);
1537 if ((ui->cursor && (button == CURSOR_SELECT || button == CURSOR_SELECT2
1538 || button == '\b' || button == '0' || button == '1'
1539 || button == '2')) ||
1540 button == LEFT_BUTTON || button == RIGHT_BUTTON ||
1541 button == MIDDLE_BUTTON) {
1545 if (state->immutable[hy * w2 + hx])
1549 i = state->grid[hy * w2 + hx];
1551 if (button == '0' || button == '2')
1553 else if (button == '1')
1555 else if (button == MIDDLE_BUTTON)
1558 /* Cycle through options */
1559 else if (button == CURSOR_SELECT2 || button == RIGHT_BUTTON)
1560 c = (i == EMPTY ? '0' : i == N_ZERO ? '1' : '-');
1561 else if (button == CURSOR_SELECT || button == LEFT_BUTTON)
1562 c = (i == EMPTY ? '1' : i == N_ONE ? '0' : '-');
1564 if (state->grid[hy * w2 + hx] ==
1565 (c == '0' ? N_ZERO : c == '1' ? N_ONE : EMPTY))
1566 return NULL; /* don't put no-ops on the undo chain */
1568 sprintf(buf, "P%c,%d,%d", c, hx, hy);
1575 static game_state *execute_move(const game_state *state, const char *move)
1577 int w2 = state->w2, h2 = state->h2;
1584 if (move[0] == 'S') {
1587 ret = dup_game(state);
1590 for (i = 0; i < s; i++) {
1592 if (!*p || !(*p == '1' || *p == '0')) {
1597 ret->grid[i] = (*p == '1' ? N_ONE : N_ZERO);
1601 ret->completed = ret->cheated = TRUE;
1603 } else if (move[0] == 'P'
1604 && sscanf(move + 1, "%c,%d,%d", &c, &x, &y) == 3 && x >= 0
1605 && x < w2 && y >= 0 && y < h2 && (c == '-' || c == '0'
1607 ret = dup_game(state);
1610 if (state->immutable[i]) {
1615 ret->grid[i] = (c == '1' ? N_ONE : c == '0' ? N_ZERO : EMPTY);
1617 if (!ret->completed && unruly_validate_counts(ret, NULL, NULL) == 0
1618 && (unruly_validate_all_rows(ret, NULL) == 0))
1619 ret->completed = TRUE;
1627 /* ----------------------------------------------------------------------
1631 static void game_compute_size(const game_params *params, int tilesize,
1634 *x = tilesize * (params->w2 + 1);
1635 *y = tilesize * (params->h2 + 1);
1638 static void game_set_size(drawing *dr, game_drawstate *ds,
1639 const game_params *params, int tilesize)
1641 ds->tilesize = tilesize;
1644 static float *game_colours(frontend *fe, int *ncolours)
1646 float *ret = snewn(3 * NCOLOURS, float);
1649 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
1651 for (i = 0; i < 3; i++) {
1652 ret[COL_1 * 3 + i] = 0.2F;
1653 ret[COL_1_HIGHLIGHT * 3 + i] = 0.4F;
1654 ret[COL_1_LOWLIGHT * 3 + i] = 0.0F;
1655 ret[COL_0 * 3 + i] = 0.95F;
1656 ret[COL_0_HIGHLIGHT * 3 + i] = 1.0F;
1657 ret[COL_0_LOWLIGHT * 3 + i] = 0.9F;
1658 ret[COL_EMPTY * 3 + i] = 0.5F;
1659 ret[COL_GRID * 3 + i] = 0.3F;
1661 game_mkhighlight_specific(fe, ret, COL_0, COL_0_HIGHLIGHT, COL_0_LOWLIGHT);
1662 game_mkhighlight_specific(fe, ret, COL_1, COL_1_HIGHLIGHT, COL_1_LOWLIGHT);
1664 ret[COL_ERROR * 3 + 0] = 1.0F;
1665 ret[COL_ERROR * 3 + 1] = 0.0F;
1666 ret[COL_ERROR * 3 + 2] = 0.0F;
1668 ret[COL_CURSOR * 3 + 0] = 0.0F;
1669 ret[COL_CURSOR * 3 + 1] = 0.7F;
1670 ret[COL_CURSOR * 3 + 2] = 0.0F;
1672 *ncolours = NCOLOURS;
1676 static void unruly_draw_err_rectangle(drawing *dr, int x, int y, int w, int h,
1679 double thick = tilesize / 10;
1680 double margin = tilesize / 20;
1682 draw_rect(dr, x+margin, y+margin, w-2*margin, thick, COL_ERROR);
1683 draw_rect(dr, x+margin, y+margin, thick, h-2*margin, COL_ERROR);
1684 draw_rect(dr, x+margin, y+h-margin-thick, w-2*margin, thick, COL_ERROR);
1685 draw_rect(dr, x+w-margin-thick, y+margin, thick, h-2*margin, COL_ERROR);
1688 static void unruly_draw_tile(drawing *dr, int x, int y, int tilesize, int tile)
1690 clip(dr, x, y, tilesize, tilesize);
1692 /* Draw the grid edge first, so the tile can overwrite it */
1693 draw_rect(dr, x, y, tilesize, tilesize, COL_GRID);
1695 /* Background of the tile */
1697 int val = (tile & FF_ZERO ? 0 : tile & FF_ONE ? 2 : 1);
1698 val = (val == 0 ? COL_0 : val == 2 ? COL_1 : COL_EMPTY);
1700 if ((tile & (FF_FLASH1 | FF_FLASH2)) &&
1701 (val == COL_0 || val == COL_1)) {
1702 val += (tile & FF_FLASH1 ? 1 : 2);
1705 draw_rect(dr, x, y, tilesize-1, tilesize-1, val);
1707 if ((val == COL_0 || val == COL_1) && (tile & FF_IMMUTABLE)) {
1708 draw_rect(dr, x + tilesize/6, y + tilesize/6,
1709 tilesize - 2*(tilesize/6) - 2, 1, val + 2);
1710 draw_rect(dr, x + tilesize/6, y + tilesize/6,
1711 1, tilesize - 2*(tilesize/6) - 2, val + 2);
1712 draw_rect(dr, x + tilesize/6 + 1, y + tilesize - tilesize/6 - 2,
1713 tilesize - 2*(tilesize/6) - 2, 1, val + 1);
1714 draw_rect(dr, x + tilesize - tilesize/6 - 2, y + tilesize/6 + 1,
1715 1, tilesize - 2*(tilesize/6) - 2, val + 1);
1719 /* 3-in-a-row errors */
1720 if (tile & (FE_HOR_ROW_LEFT | FE_HOR_ROW_RIGHT)) {
1721 int left = x, right = x + tilesize - 1;
1722 if ((tile & FE_HOR_ROW_LEFT))
1723 right += tilesize/2;
1724 if ((tile & FE_HOR_ROW_RIGHT))
1726 unruly_draw_err_rectangle(dr, left, y, right-left, tilesize-1, tilesize);
1728 if (tile & (FE_VER_ROW_TOP | FE_VER_ROW_BOTTOM)) {
1729 int top = y, bottom = y + tilesize - 1;
1730 if ((tile & FE_VER_ROW_TOP))
1731 bottom += tilesize/2;
1732 if ((tile & FE_VER_ROW_BOTTOM))
1734 unruly_draw_err_rectangle(dr, x, top, tilesize-1, bottom-top, tilesize);
1738 if (tile & FE_COUNT) {
1739 draw_text(dr, x + tilesize/2, y + tilesize/2, FONT_VARIABLE,
1740 tilesize/2, ALIGN_HCENTRE | ALIGN_VCENTRE, COL_ERROR, "!");
1743 /* Row-match errors */
1744 if (tile & FE_ROW_MATCH) {
1745 draw_rect(dr, x, y+tilesize/2-tilesize/12,
1746 tilesize, 2*(tilesize/12), COL_ERROR);
1748 if (tile & FE_COL_MATCH) {
1749 draw_rect(dr, x+tilesize/2-tilesize/12, y,
1750 2*(tilesize/12), tilesize, COL_ERROR);
1753 /* Cursor rectangle */
1754 if (tile & FF_CURSOR) {
1755 draw_rect(dr, x, y, tilesize/12, tilesize-1, COL_CURSOR);
1756 draw_rect(dr, x, y, tilesize-1, tilesize/12, COL_CURSOR);
1757 draw_rect(dr, x+tilesize-1-tilesize/12, y, tilesize/12, tilesize-1,
1759 draw_rect(dr, x, y+tilesize-1-tilesize/12, tilesize-1, tilesize/12,
1764 draw_update(dr, x, y, tilesize, tilesize);
1767 #define TILE_SIZE (ds->tilesize)
1768 #define DEFAULT_TILE_SIZE 32
1769 #define FLASH_FRAME 0.12F
1770 #define FLASH_TIME (FLASH_FRAME * 3)
1772 static void game_redraw(drawing *dr, game_drawstate *ds,
1773 const game_state *oldstate, const game_state *state,
1774 int dir, const game_ui *ui,
1775 float animtime, float flashtime)
1777 int w2 = state->w2, h2 = state->h2;
1783 /* Main window background */
1784 draw_rect(dr, 0, 0, TILE_SIZE * (w2+1), TILE_SIZE * (h2+1),
1786 /* Outer edge of grid */
1787 draw_rect(dr, COORD(0)-TILE_SIZE/10, COORD(0)-TILE_SIZE/10,
1788 TILE_SIZE*w2 + 2*(TILE_SIZE/10) - 1,
1789 TILE_SIZE*h2 + 2*(TILE_SIZE/10) - 1, COL_GRID);
1791 draw_update(dr, 0, 0, TILE_SIZE * (w2+1), TILE_SIZE * (h2+1));
1797 flash = (int)(flashtime / FLASH_FRAME) == 1 ? FF_FLASH2 : FF_FLASH1;
1799 for (i = 0; i < s; i++)
1801 unruly_validate_all_rows(state, ds->gridfs);
1802 for (i = 0; i < 2 * (h2 + w2); i++)
1804 unruly_validate_counts(state, NULL, ds->rowfs);
1806 for (y = 0; y < h2; y++) {
1807 for (x = 0; x < w2; x++) {
1812 tile = ds->gridfs[i];
1814 if (state->grid[i] == N_ONE) {
1816 if (ds->rowfs[y] || ds->rowfs[2*h2 + x])
1818 } else if (state->grid[i] == N_ZERO) {
1820 if (ds->rowfs[h2 + y] || ds->rowfs[2*h2 + w2 + x])
1826 if (state->immutable[i])
1827 tile |= FF_IMMUTABLE;
1829 if (ui->cursor && ui->cx == x && ui->cy == y)
1832 if (ds->grid[i] != tile) {
1834 unruly_draw_tile(dr, COORD(x), COORD(y), TILE_SIZE, tile);
1840 static float game_anim_length(const game_state *oldstate,
1841 const game_state *newstate, int dir, game_ui *ui)
1846 static float game_flash_length(const game_state *oldstate,
1847 const game_state *newstate, int dir, game_ui *ui)
1849 if (!oldstate->completed && newstate->completed &&
1850 !oldstate->cheated && !newstate->cheated)
1855 static int game_status(const game_state *state)
1857 return state->completed ? +1 : 0;
1860 static int game_timing_state(const game_state *state, game_ui *ui)
1865 static void game_print_size(const game_params *params, float *x, float *y)
1869 /* Using 7mm squares */
1870 game_compute_size(params, 700, &pw, &ph);
1875 static void game_print(drawing *dr, const game_state *state, int tilesize)
1877 int w2 = state->w2, h2 = state->h2;
1880 int ink = print_mono_colour(dr, 0);
1882 for (y = 0; y < h2; y++)
1883 for (x = 0; x < w2; x++) {
1884 int tx = x * tilesize + (tilesize / 2);
1885 int ty = y * tilesize + (tilesize / 2);
1887 /* Draw the border */
1891 coords[2] = tx + tilesize;
1893 coords[4] = tx + tilesize;
1894 coords[5] = ty + tilesize - 1;
1896 coords[7] = ty + tilesize - 1;
1897 draw_polygon(dr, coords, 4, -1, ink);
1899 if (state->grid[y * w2 + x] == N_ONE)
1900 draw_rect(dr, tx, ty, tilesize, tilesize, ink);
1901 else if (state->grid[y * w2 + x] == N_ZERO)
1902 draw_circle(dr, tx + tilesize/2, ty + tilesize/2,
1903 tilesize/12, ink, ink);
1908 #define thegame unruly
1911 const struct game thegame = {
1912 "Unruly", "games.unruly", "unruly",
1919 TRUE, game_configure, custom_params,
1927 TRUE, game_can_format_as_text_now, game_text_format,
1935 DEFAULT_TILE_SIZE, game_compute_size, game_set_size,
1938 game_free_drawstate,
1943 TRUE, FALSE, game_print_size, game_print,
1944 FALSE, /* wants_statusbar */
1945 FALSE, game_timing_state,
1949 /* ***************** *
1950 * Standalone solver *
1951 * ***************** */
1953 #ifdef STANDALONE_SOLVER
1957 /* Most of the standalone solver code was copied from unequal.c and singles.c */
1961 static void usage_exit(const char *msg)
1964 fprintf(stderr, "%s: %s\n", quis, msg);
1966 "Usage: %s [-v] [--seed SEED] <params> | [game_id [game_id ...]]\n",
1971 int main(int argc, char *argv[])
1974 time_t seed = time(NULL);
1976 game_params *params = NULL;
1978 char *id = NULL, *desc = NULL, *err;
1982 while (--argc > 0) {
1984 if (!strcmp(p, "--seed")) {
1986 usage_exit("--seed needs an argument");
1987 seed = (time_t) atoi(*++argv);
1989 } else if (!strcmp(p, "-v"))
1990 solver_verbose = TRUE;
1992 usage_exit("unrecognised option");
1998 desc = strchr(id, ':');
2002 params = default_params();
2003 decode_params(params, id);
2004 err = validate_params(params, TRUE);
2006 fprintf(stderr, "Parameters are invalid\n");
2007 fprintf(stderr, "%s: %s", argv[0], err);
2013 char *desc_gen, *aux;
2014 rs = random_new((void *) &seed, sizeof(time_t));
2016 params = default_params();
2017 printf("Generating puzzle with parameters %s\n",
2018 encode_params(params, TRUE));
2019 desc_gen = new_game_desc(params, rs, &aux, FALSE);
2021 if (!solver_verbose) {
2022 char *fmt = game_text_format(new_game(NULL, params, desc_gen));
2027 printf("Game ID: %s\n", desc_gen);
2030 struct unruly_scratch *scratch;
2031 int maxdiff, errcode;
2033 err = validate_desc(params, desc);
2035 fprintf(stderr, "Description is invalid\n");
2036 fprintf(stderr, "%s", err);
2040 input = new_game(NULL, params, desc);
2041 scratch = unruly_new_scratch(input);
2043 maxdiff = unruly_solve_game(input, scratch, DIFFCOUNT);
2045 errcode = unruly_validate_counts(input, scratch, NULL);
2046 if (unruly_validate_all_rows(input, NULL) == -1)
2049 if (errcode != -1) {
2050 char *fmt = game_text_format(input);
2054 printf("Difficulty: already solved!\n");
2056 printf("Difficulty: %s\n", unruly_diffnames[maxdiff]);
2060 printf("No solution found.\n");
2061 else if (errcode == -1)
2062 printf("Puzzle is invalid.\n");
2065 unruly_free_scratch(scratch);