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 is not enabled in the default presets
18 * (but it can be selected via the Custom configurer).
21 * http://www.janko.at/Raetsel/Tohu-Wa-Vohu/index.htm
25 * Possible future improvements:
27 * More solver cleverness
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
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
41 * - an 'Unreasonable' difficulty level, supporting recursion and
54 #ifdef STANDALONE_SOLVER
55 int solver_verbose = FALSE;
63 * When editing this enum, maintain the invariants
64 * COL_n_HIGHLIGHT = COL_n + 1
65 * COL_n_LOWLIGHT = COL_n + 2
79 int w2, h2; /* full grid width and height respectively */
80 int unique; /* should row and column patterns be unique? */
87 #define ENUM(upper,title,lower) DIFF_ ## upper,
88 #define TITLE(upper,title,lower) #title,
89 #define ENCODE(upper,title,lower) #lower
90 #define CONFIG(upper,title,lower) ":" #title
91 enum { DIFFLIST(ENUM) DIFFCOUNT };
92 static char const *const unruly_diffnames[] = { DIFFLIST(TITLE) };
94 static char const unruly_diffchars[] = DIFFLIST(ENCODE);
95 #define DIFFCONFIG DIFFLIST(CONFIG)
97 const static struct game_params unruly_presets[] = {
98 { 8, 8, FALSE, DIFF_EASY},
99 { 8, 8, FALSE, DIFF_NORMAL},
100 {10, 10, FALSE, DIFF_EASY},
101 {10, 10, FALSE, DIFF_NORMAL},
102 {14, 14, FALSE, DIFF_EASY},
103 {14, 14, FALSE, DIFF_NORMAL}
106 #define DEFAULT_PRESET 0
115 #define FE_HOR_ROW_LEFT 0x0001
116 #define FE_HOR_ROW_MID 0x0003
117 #define FE_HOR_ROW_RIGHT 0x0002
119 #define FE_VER_ROW_TOP 0x0004
120 #define FE_VER_ROW_MID 0x000C
121 #define FE_VER_ROW_BOTTOM 0x0008
123 #define FE_COUNT 0x0010
125 #define FE_ROW_MATCH 0x0020
126 #define FE_COL_MATCH 0x0040
128 #define FF_ONE 0x0080
129 #define FF_ZERO 0x0100
130 #define FF_CURSOR 0x0200
132 #define FF_FLASH1 0x0400
133 #define FF_FLASH2 0x0800
134 #define FF_IMMUTABLE 0x1000
140 unsigned char *immutable;
142 int completed, cheated;
145 static game_params *default_params(void)
147 game_params *ret = snew(game_params);
149 *ret = unruly_presets[DEFAULT_PRESET]; /* structure copy */
154 static int game_fetch_preset(int i, char **name, game_params **params)
159 if (i < 0 || i >= lenof(unruly_presets))
162 ret = snew(game_params);
163 *ret = unruly_presets[i]; /* structure copy */
165 sprintf(buf, "%dx%d %s", ret->w2, ret->h2, unruly_diffnames[ret->diff]);
172 static void free_params(game_params *params)
177 static game_params *dup_params(const game_params *params)
179 game_params *ret = snew(game_params);
180 *ret = *params; /* structure copy */
184 static void decode_params(game_params *params, char const *string)
186 char const *p = string;
188 params->unique = FALSE;
190 params->w2 = atoi(p);
191 while (*p && isdigit((unsigned char)*p)) p++;
194 params->h2 = atoi(p);
195 while (*p && isdigit((unsigned char)*p)) p++;
197 params->h2 = params->w2;
202 params->unique = TRUE;
208 params->diff = DIFFCOUNT + 1; /* ...which is invalid */
210 for (i = 0; i < DIFFCOUNT; i++) {
211 if (*p == unruly_diffchars[i])
219 static char *encode_params(const game_params *params, int full)
223 sprintf(buf, "%dx%d", params->w2, params->h2);
227 sprintf(buf + strlen(buf), "d%c", unruly_diffchars[params->diff]);
232 static config_item *game_configure(const game_params *params)
237 ret = snewn(5, config_item);
239 ret[0].name = "Width";
240 ret[0].type = C_STRING;
241 sprintf(buf, "%d", params->w2);
242 ret[0].sval = dupstr(buf);
245 ret[1].name = "Height";
246 ret[1].type = C_STRING;
247 sprintf(buf, "%d", params->h2);
248 ret[1].sval = dupstr(buf);
251 ret[2].name = "Unique rows and columns";
252 ret[2].type = C_BOOLEAN;
253 ret[2].ival = params->unique;
255 ret[3].name = "Difficulty";
256 ret[3].type = C_CHOICES;
257 ret[3].sval = DIFFCONFIG;
258 ret[3].ival = params->diff;
268 static game_params *custom_params(const config_item *cfg)
270 game_params *ret = snew(game_params);
272 ret->w2 = atoi(cfg[0].sval);
273 ret->h2 = atoi(cfg[1].sval);
274 ret->unique = cfg[2].ival;
275 ret->diff = cfg[3].ival;
280 static char *validate_params(const game_params *params, int full)
282 if ((params->w2 & 1) || (params->h2 & 1))
283 return "Width and height must both be even";
284 if (params->w2 < 6 || params->h2 < 6)
285 return "Width and height must be at least 6";
286 if (params->unique) {
287 static const long A177790[] = {
289 * The nth element of this array gives the number of
290 * distinct possible Unruly rows of length 2n (that is,
291 * containing exactly n 1s and n 0s and not containing
292 * three consecutive elements the same) for as long as
293 * those numbers fit in a 32-bit signed int.
295 * So in unique-rows mode, if the puzzle width is 2n, then
296 * the height must be at most (this array)[n], and vice
299 * This is sequence A177790 in the Online Encyclopedia of
300 * Integer Sequences: http://oeis.org/A177790
302 1L, 2L, 6L, 14L, 34L, 84L, 208L, 518L, 1296L, 3254L,
303 8196L, 20700L, 52404L, 132942L, 337878L, 860142L,
304 2192902L, 5598144L, 14308378L, 36610970L, 93770358L,
305 240390602L, 616787116L, 1583765724L
307 if (params->w2 < 2*lenof(A177790) &&
308 params->h2 > A177790[params->w2/2]) {
309 return "Puzzle is too tall for unique-rows mode";
311 if (params->h2 < 2*lenof(A177790) &&
312 params->w2 > A177790[params->h2/2]) {
313 return "Puzzle is too long for unique-rows mode";
316 if (params->diff >= DIFFCOUNT)
317 return "Unknown difficulty rating";
322 static char *validate_desc(const game_params *params, const char *desc)
324 int w2 = params->w2, h2 = params->h2;
327 const char *p = desc;
331 if (*p >= 'a' && *p < 'z')
332 pos += 1 + (*p - 'a');
333 else if (*p >= 'A' && *p < 'Z')
334 pos += 1 + (*p - 'A');
335 else if (*p == 'Z' || *p == 'z')
338 return "Description contains invalid characters";
344 return "Description too short";
346 return "Description too long";
351 static game_state *blank_state(int w2, int h2, int unique)
353 game_state *state = snew(game_state);
358 state->unique = unique;
359 state->grid = snewn(s, char);
360 state->immutable = snewn(s, unsigned char);
362 memset(state->grid, EMPTY, s);
363 memset(state->immutable, FALSE, s);
365 state->completed = state->cheated = FALSE;
370 static game_state *new_game(midend *me, const game_params *params,
373 int w2 = params->w2, h2 = params->h2;
376 game_state *state = blank_state(w2, h2, params->unique);
378 const char *p = desc;
382 if (*p >= 'a' && *p < 'z') {
385 state->grid[pos] = N_ZERO;
386 state->immutable[pos] = TRUE;
389 } else if (*p >= 'A' && *p < 'Z') {
392 state->grid[pos] = N_ONE;
393 state->immutable[pos] = TRUE;
396 } else if (*p == 'Z' || *p == 'z') {
399 assert(!"Description contains invalid characters");
408 static game_state *dup_game(const game_state *state)
410 int w2 = state->w2, h2 = state->h2;
413 game_state *ret = blank_state(w2, h2, state->unique);
415 memcpy(ret->grid, state->grid, s);
416 memcpy(ret->immutable, state->immutable, s);
418 ret->completed = state->completed;
419 ret->cheated = state->cheated;
424 static void free_game(game_state *state)
427 sfree(state->immutable);
432 static int game_can_format_as_text_now(const game_params *params)
437 static char *game_text_format(const game_state *state)
439 int w2 = state->w2, h2 = state->h2;
442 char *ret = snewn(lr * h2 + 1, char);
446 for (y = 0; y < h2; y++) {
447 for (x = 0; x < w2; x++) {
449 char c = state->grid[y * w2 + x];
450 *p++ = (c == N_ONE ? '1' : c == N_ZERO ? '0' : '.');
466 struct unruly_scratch {
473 static void unruly_solver_update_remaining(const game_state *state,
474 struct unruly_scratch *scratch)
476 int w2 = state->w2, h2 = state->h2;
479 /* Reset all scratch data */
480 memset(scratch->ones_rows, 0, h2 * sizeof(int));
481 memset(scratch->ones_cols, 0, w2 * sizeof(int));
482 memset(scratch->zeros_rows, 0, h2 * sizeof(int));
483 memset(scratch->zeros_cols, 0, w2 * sizeof(int));
485 for (x = 0; x < w2; x++)
486 for (y = 0; y < h2; y++) {
487 if (state->grid[y * w2 + x] == N_ONE) {
488 scratch->ones_rows[y]++;
489 scratch->ones_cols[x]++;
490 } else if (state->grid[y * w2 + x] == N_ZERO) {
491 scratch->zeros_rows[y]++;
492 scratch->zeros_cols[x]++;
497 static struct unruly_scratch *unruly_new_scratch(const game_state *state)
499 int w2 = state->w2, h2 = state->h2;
501 struct unruly_scratch *ret = snew(struct unruly_scratch);
503 ret->ones_rows = snewn(h2, int);
504 ret->ones_cols = snewn(w2, int);
505 ret->zeros_rows = snewn(h2, int);
506 ret->zeros_cols = snewn(w2, int);
508 unruly_solver_update_remaining(state, ret);
513 static void unruly_free_scratch(struct unruly_scratch *scratch)
515 sfree(scratch->ones_rows);
516 sfree(scratch->ones_cols);
517 sfree(scratch->zeros_rows);
518 sfree(scratch->zeros_cols);
523 static int unruly_solver_check_threes(game_state *state, int *rowcount,
524 int *colcount, int horizontal,
525 char check, char block)
527 int w2 = state->w2, h2 = state->h2;
529 int dx = horizontal ? 1 : 0, dy = 1 - dx;
530 int sx = dx, sy = dy;
531 int ex = w2 - dx, ey = h2 - dy;
536 /* Check for any three squares which almost form three in a row */
537 for (y = sy; y < ey; y++) {
538 for (x = sx; x < ex; x++) {
539 int i1 = (y-dy) * w2 + (x-dx);
541 int i3 = (y+dy) * w2 + (x+dx);
543 if (state->grid[i1] == check && state->grid[i2] == check
544 && state->grid[i3] == EMPTY) {
546 #ifdef STANDALONE_SOLVER
547 if (solver_verbose) {
548 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n",
549 i1 % w2, i1 / w2, i2 % w2, i2 / w2,
550 (block == N_ONE ? '1' : '0'), i3 % w2,
554 state->grid[i3] = block;
558 if (state->grid[i1] == check && state->grid[i2] == EMPTY
559 && state->grid[i3] == check) {
561 #ifdef STANDALONE_SOLVER
562 if (solver_verbose) {
563 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n",
564 i1 % w2, i1 / w2, i3 % w2, i3 / w2,
565 (block == N_ONE ? '1' : '0'), i2 % w2,
569 state->grid[i2] = block;
573 if (state->grid[i1] == EMPTY && state->grid[i2] == check
574 && state->grid[i3] == check) {
576 #ifdef STANDALONE_SOLVER
577 if (solver_verbose) {
578 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n",
579 i2 % w2, i2 / w2, i3 % w2, i3 / w2,
580 (block == N_ONE ? '1' : '0'), i1 % w2,
584 state->grid[i1] = block;
594 static int unruly_solver_check_all_threes(game_state *state,
595 struct unruly_scratch *scratch)
600 unruly_solver_check_threes(state, scratch->zeros_rows,
601 scratch->zeros_cols, TRUE, N_ONE, N_ZERO);
603 unruly_solver_check_threes(state, scratch->ones_rows,
604 scratch->ones_cols, TRUE, N_ZERO, N_ONE);
606 unruly_solver_check_threes(state, scratch->zeros_rows,
607 scratch->zeros_cols, FALSE, N_ONE,
610 unruly_solver_check_threes(state, scratch->ones_rows,
611 scratch->ones_cols, FALSE, N_ZERO, N_ONE);
616 static int unruly_solver_check_uniques(game_state *state, int *rowcount,
617 int horizontal, char check, char block,
618 struct unruly_scratch *scratch)
620 int w2 = state->w2, h2 = state->h2;
622 int rmult = (horizontal ? w2 : 1);
623 int cmult = (horizontal ? 1 : w2);
624 int nr = (horizontal ? h2 : w2);
625 int nc = (horizontal ? w2 : h2);
632 * Find each row that has max entries of type 'check', and see if
633 * all those entries match those in any row with max-1 entries. If
634 * so, set the last non-matching entry of the latter row to ensure
635 * that it's different.
637 for (r = 0; r < nr; r++) {
638 if (rowcount[r] != max)
640 for (r2 = 0; r2 < nr; r2++) {
641 int nmatch = 0, nonmatch = -1;
642 if (rowcount[r2] != max-1)
644 for (c = 0; c < nc; c++) {
645 if (state->grid[r*rmult + c*cmult] == check) {
646 if (state->grid[r2*rmult + c*cmult] == check)
652 if (nmatch == max-1) {
653 int i1 = r2 * rmult + nonmatch * cmult;
654 assert(nonmatch != -1);
655 if (state->grid[i1] == block)
657 assert(state->grid[i1] == EMPTY);
658 #ifdef STANDALONE_SOLVER
659 if (solver_verbose) {
660 printf("Solver: matching %s %i, %i gives %c at %i,%i\n",
661 horizontal ? "rows" : "cols",
662 r, r2, (block == N_ONE ? '1' : '0'), i1 % w2,
666 state->grid[i1] = block;
667 if (block == N_ONE) {
668 scratch->ones_rows[i1 / w2]++;
669 scratch->ones_cols[i1 % w2]++;
671 scratch->zeros_rows[i1 / w2]++;
672 scratch->zeros_cols[i1 % w2]++;
681 static int unruly_solver_check_all_uniques(game_state *state,
682 struct unruly_scratch *scratch)
686 ret += unruly_solver_check_uniques(state, scratch->ones_rows,
687 TRUE, N_ONE, N_ZERO, scratch);
688 ret += unruly_solver_check_uniques(state, scratch->zeros_rows,
689 TRUE, N_ZERO, N_ONE, scratch);
690 ret += unruly_solver_check_uniques(state, scratch->ones_cols,
691 FALSE, N_ONE, N_ZERO, scratch);
692 ret += unruly_solver_check_uniques(state, scratch->zeros_cols,
693 FALSE, N_ZERO, N_ONE, scratch);
698 static int unruly_solver_fill_row(game_state *state, int i, int horizontal,
699 int *rowcount, int *colcount, char fill)
702 int w2 = state->w2, h2 = state->h2;
705 #ifdef STANDALONE_SOLVER
706 if (solver_verbose) {
707 printf("Solver: Filling %s %i with %c:",
708 (horizontal ? "Row" : "Col"), i,
709 (fill == N_ZERO ? '0' : '1'));
712 /* Place a number in every empty square in a row/column */
713 for (j = 0; j < (horizontal ? w2 : h2); j++) {
714 int p = (horizontal ? i * w2 + j : j * w2 + i);
716 if (state->grid[p] == EMPTY) {
717 #ifdef STANDALONE_SOLVER
718 if (solver_verbose) {
719 printf(" (%i,%i)", (horizontal ? j : i),
720 (horizontal ? i : j));
724 state->grid[p] = fill;
725 rowcount[(horizontal ? i : j)]++;
726 colcount[(horizontal ? j : i)]++;
730 #ifdef STANDALONE_SOLVER
731 if (solver_verbose) {
739 static int unruly_solver_check_complete_nums(game_state *state,
740 int *complete, int horizontal,
741 int *rowcount, int *colcount,
744 int w2 = state->w2, h2 = state->h2;
745 int count = (horizontal ? h2 : w2); /* number of rows to check */
746 int target = (horizontal ? w2 : h2) / 2; /* target number of 0s/1s */
747 int *other = (horizontal ? rowcount : colcount);
752 /* Check for completed rows/cols for one number, then fill in the rest */
753 for (i = 0; i < count; i++) {
754 if (complete[i] == target && other[i] < target) {
755 #ifdef STANDALONE_SOLVER
756 if (solver_verbose) {
757 printf("Solver: Row %i satisfied for %c\n", i,
758 (fill != N_ZERO ? '0' : '1'));
761 ret += unruly_solver_fill_row(state, i, horizontal, rowcount,
769 static int unruly_solver_check_all_complete_nums(game_state *state,
770 struct unruly_scratch *scratch)
775 unruly_solver_check_complete_nums(state, scratch->ones_rows, TRUE,
777 scratch->zeros_cols, N_ZERO);
779 unruly_solver_check_complete_nums(state, scratch->ones_cols, FALSE,
781 scratch->zeros_cols, N_ZERO);
783 unruly_solver_check_complete_nums(state, scratch->zeros_rows, TRUE,
785 scratch->ones_cols, N_ONE);
787 unruly_solver_check_complete_nums(state, scratch->zeros_cols, FALSE,
789 scratch->ones_cols, N_ONE);
794 static int unruly_solver_check_near_complete(game_state *state,
795 int *complete, int horizontal,
796 int *rowcount, int *colcount,
799 int w2 = state->w2, h2 = state->h2;
800 int w = w2/2, h = h2/2;
802 int dx = horizontal ? 1 : 0, dy = 1 - dx;
804 int sx = dx, sy = dy;
805 int ex = w2 - dx, ey = h2 - dy;
811 * This function checks for a row with one Y remaining, then looks
812 * for positions that could cause the remaining squares in the row
813 * to make 3 X's in a row. Example:
815 * Consider the following row:
817 * If the last 1 was placed in the last square, the remaining
818 * squares would be 0:
820 * This violates the 3 in a row rule. We now know that the last 1
821 * shouldn't be in the last cell.
825 /* Check for any two blank and one filled square */
826 for (y = sy; y < ey; y++) {
827 /* One type must have 1 remaining, the other at least 2 */
828 if (horizontal && (complete[y] < w - 1 || rowcount[y] > w - 2))
831 for (x = sx; x < ex; x++) {
834 && (complete[x] < h - 1 || colcount[x] > h - 2))
837 i = (horizontal ? y : x);
838 i1 = (y-dy) * w2 + (x-dx);
840 i3 = (y+dy) * w2 + (x+dx);
842 if (state->grid[i1] == fill && state->grid[i2] == EMPTY
843 && state->grid[i3] == EMPTY) {
845 * Temporarily fill the empty spaces with something else.
846 * This avoids raising the counts for the row and column
848 state->grid[i2] = BOGUS;
849 state->grid[i3] = BOGUS;
851 #ifdef STANDALONE_SOLVER
852 if (solver_verbose) {
853 printf("Solver: Row %i nearly satisfied for %c\n", i,
854 (fill != N_ZERO ? '0' : '1'));
858 unruly_solver_fill_row(state, i, horizontal, rowcount,
861 state->grid[i2] = EMPTY;
862 state->grid[i3] = EMPTY;
865 else if (state->grid[i1] == EMPTY && state->grid[i2] == fill
866 && state->grid[i3] == EMPTY) {
867 state->grid[i1] = BOGUS;
868 state->grid[i3] = BOGUS;
870 #ifdef STANDALONE_SOLVER
871 if (solver_verbose) {
872 printf("Solver: Row %i nearly satisfied for %c\n", i,
873 (fill != N_ZERO ? '0' : '1'));
877 unruly_solver_fill_row(state, i, horizontal, rowcount,
880 state->grid[i1] = EMPTY;
881 state->grid[i3] = EMPTY;
884 else if (state->grid[i1] == EMPTY && state->grid[i2] == EMPTY
885 && state->grid[i3] == fill) {
886 state->grid[i1] = BOGUS;
887 state->grid[i2] = BOGUS;
889 #ifdef STANDALONE_SOLVER
890 if (solver_verbose) {
891 printf("Solver: Row %i nearly satisfied for %c\n", i,
892 (fill != N_ZERO ? '0' : '1'));
896 unruly_solver_fill_row(state, i, horizontal, rowcount,
899 state->grid[i1] = EMPTY;
900 state->grid[i2] = EMPTY;
903 else if (state->grid[i1] == EMPTY && state->grid[i2] == EMPTY
904 && state->grid[i3] == EMPTY) {
905 state->grid[i1] = BOGUS;
906 state->grid[i2] = BOGUS;
907 state->grid[i3] = BOGUS;
909 #ifdef STANDALONE_SOLVER
910 if (solver_verbose) {
911 printf("Solver: Row %i nearly satisfied for %c\n", i,
912 (fill != N_ZERO ? '0' : '1'));
916 unruly_solver_fill_row(state, i, horizontal, rowcount,
919 state->grid[i1] = EMPTY;
920 state->grid[i2] = EMPTY;
921 state->grid[i3] = EMPTY;
929 static int unruly_solver_check_all_near_complete(game_state *state,
930 struct unruly_scratch *scratch)
935 unruly_solver_check_near_complete(state, scratch->ones_rows, TRUE,
937 scratch->zeros_cols, N_ZERO);
939 unruly_solver_check_near_complete(state, scratch->ones_cols, FALSE,
941 scratch->zeros_cols, N_ZERO);
943 unruly_solver_check_near_complete(state, scratch->zeros_rows, TRUE,
945 scratch->ones_cols, N_ONE);
947 unruly_solver_check_near_complete(state, scratch->zeros_cols, FALSE,
949 scratch->ones_cols, N_ONE);
954 static int unruly_validate_rows(const game_state *state, int horizontal,
955 char check, int *errors)
957 int w2 = state->w2, h2 = state->h2;
959 int dx = horizontal ? 1 : 0, dy = 1 - dx;
961 int sx = dx, sy = dy;
962 int ex = w2 - dx, ey = h2 - dy;
967 int err1 = (horizontal ? FE_HOR_ROW_LEFT : FE_VER_ROW_TOP);
968 int err2 = (horizontal ? FE_HOR_ROW_MID : FE_VER_ROW_MID);
969 int err3 = (horizontal ? FE_HOR_ROW_RIGHT : FE_VER_ROW_BOTTOM);
971 /* Check for any three in a row, and mark errors accordingly (if
973 for (y = sy; y < ey; y++) {
974 for (x = sx; x < ex; x++) {
975 int i1 = (y-dy) * w2 + (x-dx);
977 int i3 = (y+dy) * w2 + (x+dx);
979 if (state->grid[i1] == check && state->grid[i2] == check
980 && state->grid[i3] == check) {
994 static int unruly_validate_unique(const game_state *state, int horizontal,
997 int w2 = state->w2, h2 = state->h2;
999 int rmult = (horizontal ? w2 : 1);
1000 int cmult = (horizontal ? 1 : w2);
1001 int nr = (horizontal ? h2 : w2);
1002 int nc = (horizontal ? w2 : h2);
1003 int err = (horizontal ? FE_ROW_MATCH : FE_COL_MATCH);
1008 /* Check for any two full rows matching exactly, and mark errors
1009 * accordingly (if required) */
1010 for (r = 0; r < nr; r++) {
1012 for (c = 0; c < nc; c++)
1013 if (state->grid[r*rmult + c*cmult] != EMPTY)
1017 for (r2 = r+1; r2 < nr; r2++) {
1019 for (c = 0; c < nc; c++)
1020 if (state->grid[r*rmult + c*cmult] !=
1021 state->grid[r2*rmult + c*cmult])
1025 for (c = 0; c < nc; c++) {
1026 errors[r*rmult + c*cmult] |= err;
1027 errors[r2*rmult + c*cmult] |= err;
1038 static int unruly_validate_all_rows(const game_state *state, int *errors)
1042 errcount += unruly_validate_rows(state, TRUE, N_ONE, errors);
1043 errcount += unruly_validate_rows(state, FALSE, N_ONE, errors);
1044 errcount += unruly_validate_rows(state, TRUE, N_ZERO, errors);
1045 errcount += unruly_validate_rows(state, FALSE, N_ZERO, errors);
1047 if (state->unique) {
1048 errcount += unruly_validate_unique(state, TRUE, errors);
1049 errcount += unruly_validate_unique(state, FALSE, errors);
1057 static int unruly_validate_counts(const game_state *state,
1058 struct unruly_scratch *scratch, int *errors)
1060 int w2 = state->w2, h2 = state->h2;
1061 int w = w2/2, h = h2/2;
1066 /* See if all rows/columns are satisfied. If one is exceeded,
1067 * mark it as an error (if required)
1070 char hasscratch = TRUE;
1072 scratch = unruly_new_scratch(state);
1076 for (i = 0; i < w2; i++) {
1077 if (scratch->ones_cols[i] < h)
1079 if (scratch->zeros_cols[i] < h)
1082 if (scratch->ones_cols[i] > h) {
1085 errors[2*h2 + i] = TRUE;
1087 errors[2*h2 + i] = FALSE;
1089 if (scratch->zeros_cols[i] > h) {
1092 errors[2*h2 + w2 + i] = TRUE;
1094 errors[2*h2 + w2 + i] = FALSE;
1096 for (i = 0; i < h2; i++) {
1097 if (scratch->ones_rows[i] < w)
1099 if (scratch->zeros_rows[i] < w)
1102 if (scratch->ones_rows[i] > w) {
1109 if (scratch->zeros_rows[i] > w) {
1112 errors[h2 + i] = TRUE;
1114 errors[h2 + i] = FALSE;
1118 unruly_free_scratch(scratch);
1120 return (above ? -1 : below ? 1 : 0);
1123 static int unruly_solve_game(game_state *state,
1124 struct unruly_scratch *scratch, int diff)
1126 int done, maxdiff = -1;
1131 /* Check for impending 3's */
1132 done += unruly_solver_check_all_threes(state, scratch);
1134 /* Keep using the simpler techniques while they produce results */
1136 if (maxdiff < DIFF_EASY)
1137 maxdiff = DIFF_EASY;
1141 /* Check for completed rows */
1142 done += unruly_solver_check_all_complete_nums(state, scratch);
1145 if (maxdiff < DIFF_EASY)
1146 maxdiff = DIFF_EASY;
1150 /* Check for impending failures of row/column uniqueness, if
1151 * it's enabled in this game mode */
1152 if (state->unique) {
1153 done += unruly_solver_check_all_uniques(state, scratch);
1156 if (maxdiff < DIFF_EASY)
1157 maxdiff = DIFF_EASY;
1162 /* Normal techniques */
1163 if (diff < DIFF_NORMAL)
1166 /* Check for nearly completed rows */
1167 done += unruly_solver_check_all_near_complete(state, scratch);
1170 if (maxdiff < DIFF_NORMAL)
1171 maxdiff = DIFF_NORMAL;
1180 static char *solve_game(const game_state *state, const game_state *currstate,
1181 const char *aux, char **error)
1183 game_state *solved = dup_game(state);
1184 struct unruly_scratch *scratch = unruly_new_scratch(solved);
1188 unruly_solve_game(solved, scratch, DIFFCOUNT);
1190 result = unruly_validate_counts(solved, scratch, NULL);
1191 if (unruly_validate_all_rows(solved, NULL) == -1)
1195 int w2 = solved->w2, h2 = solved->h2;
1200 ret = snewn(s + 2, char);
1204 for (i = 0; i < s; i++)
1205 *p++ = (solved->grid[i] == N_ONE ? '1' : '0');
1208 } else if (result == 1)
1209 *error = "No solution found.";
1210 else if (result == -1)
1211 *error = "Puzzle is invalid.";
1214 unruly_free_scratch(scratch);
1222 static int unruly_fill_game(game_state *state, struct unruly_scratch *scratch,
1226 int w2 = state->w2, h2 = state->h2;
1231 #ifdef STANDALONE_SOLVER
1232 if (solver_verbose) {
1233 printf("Generator: Attempt to fill grid\n");
1237 /* Generate random array of spaces */
1238 spaces = snewn(s, int);
1239 for (i = 0; i < s; i++)
1241 shuffle(spaces, s, sizeof(*spaces), rs);
1244 * Construct a valid filled grid by repeatedly picking an unfilled
1245 * space and fill it, then calling the solver to fill in any
1246 * spaces forced by the change.
1248 for (j = 0; j < s; j++) {
1251 if (state->grid[i] != EMPTY)
1254 if (random_upto(rs, 2)) {
1255 state->grid[i] = N_ONE;
1256 scratch->ones_rows[i / w2]++;
1257 scratch->ones_cols[i % w2]++;
1259 state->grid[i] = N_ZERO;
1260 scratch->zeros_rows[i / w2]++;
1261 scratch->zeros_cols[i % w2]++;
1264 unruly_solve_game(state, scratch, DIFFCOUNT);
1268 if (unruly_validate_all_rows(state, NULL) != 0
1269 || unruly_validate_counts(state, scratch, NULL) != 0)
1275 static char *new_game_desc(const game_params *params, random_state *rs,
1276 char **aux, int interactive)
1278 #ifdef STANDALONE_SOLVER
1280 int temp_verbose = FALSE;
1283 int w2 = params->w2, h2 = params->h2;
1290 struct unruly_scratch *scratch;
1298 state = blank_state(w2, h2, params->unique);
1299 scratch = unruly_new_scratch(state);
1300 if (unruly_fill_game(state, scratch, rs))
1303 unruly_free_scratch(scratch);
1306 #ifdef STANDALONE_SOLVER
1307 if (solver_verbose) {
1308 printf("Puzzle generated in %i attempts\n", attempts);
1309 debug = game_text_format(state);
1310 fputs(debug, stdout);
1313 temp_verbose = solver_verbose;
1314 solver_verbose = FALSE;
1318 unruly_free_scratch(scratch);
1320 /* Generate random array of spaces */
1321 spaces = snewn(s, int);
1322 for (i = 0; i < s; i++)
1324 shuffle(spaces, s, sizeof(*spaces), rs);
1327 * Winnow the clues by starting from our filled grid, repeatedly
1328 * picking a filled space and emptying it, as long as the solver
1329 * reports that the puzzle can still be solved after doing so.
1331 for (j = 0; j < s; j++) {
1338 state->grid[i] = EMPTY;
1340 solver = dup_game(state);
1341 scratch = unruly_new_scratch(state);
1343 unruly_solve_game(solver, scratch, params->diff);
1345 if (unruly_validate_counts(solver, scratch, NULL) != 0)
1349 unruly_free_scratch(scratch);
1353 #ifdef STANDALONE_SOLVER
1355 solver_verbose = TRUE;
1357 printf("Final puzzle:\n");
1358 debug = game_text_format(state);
1359 fputs(debug, stdout);
1365 * See if the game has accidentally come out too easy.
1367 if (params->diff > 0) {
1371 solver = dup_game(state);
1372 scratch = unruly_new_scratch(state);
1374 unruly_solve_game(solver, scratch, params->diff - 1);
1376 ok = unruly_validate_counts(solver, scratch, NULL);
1379 unruly_free_scratch(scratch);
1385 * Puzzles of the easiest difficulty can't be too easy.
1391 /* Encode description */
1392 ret = snewn(s + 1, char);
1395 for (i = 0; i < s+1; i++) {
1396 if (i == s || state->grid[i] == N_ZERO) {
1403 } else if (state->grid[i] == N_ONE) {
1430 static game_ui *new_ui(const game_state *state)
1432 game_ui *ret = snew(game_ui);
1434 ret->cx = ret->cy = 0;
1435 ret->cursor = FALSE;
1440 static void free_ui(game_ui *ui)
1445 static char *encode_ui(const game_ui *ui)
1450 static void decode_ui(game_ui *ui, const char *encoding)
1454 static void game_changed_state(game_ui *ui, const game_state *oldstate,
1455 const game_state *newstate)
1459 struct game_drawstate {
1470 static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1472 struct game_drawstate *ds = snew(struct game_drawstate);
1474 int w2 = state->w2, h2 = state->h2;
1481 ds->started = FALSE;
1483 ds->gridfs = snewn(s, int);
1484 ds->rowfs = snewn(2 * (w2 + h2), int);
1486 ds->grid = snewn(s, int);
1487 for (i = 0; i < s; i++)
1493 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1501 #define COORD(x) ( (x) * ds->tilesize + ds->tilesize/2 )
1502 #define FROMCOORD(x) ( ((x)-(ds->tilesize/2)) / ds->tilesize )
1504 static char *interpret_move(const game_state *state, game_ui *ui,
1505 const game_drawstate *ds,
1506 int ox, int oy, int button)
1511 int gx = FROMCOORD(ox);
1512 int gy = FROMCOORD(oy);
1514 int w2 = state->w2, h2 = state->h2;
1516 button &= ~MOD_MASK;
1519 if (button == LEFT_BUTTON || button == RIGHT_BUTTON ||
1520 button == MIDDLE_BUTTON) {
1521 if (ox >= (ds->tilesize / 2) && gx < w2
1522 && oy >= (ds->tilesize / 2) && gy < h2) {
1531 if (IS_CURSOR_MOVE(button)) {
1532 move_cursor(button, &ui->cx, &ui->cy, w2, h2, 0);
1538 if ((ui->cursor && (button == CURSOR_SELECT || button == CURSOR_SELECT2
1539 || button == '\b' || button == '0' || button == '1'
1540 || button == '2')) ||
1541 button == LEFT_BUTTON || button == RIGHT_BUTTON ||
1542 button == MIDDLE_BUTTON) {
1546 if (state->immutable[hy * w2 + hx])
1550 i = state->grid[hy * w2 + hx];
1552 if (button == '0' || button == '2')
1554 else if (button == '1')
1556 else if (button == MIDDLE_BUTTON)
1559 /* Cycle through options */
1560 else if (button == CURSOR_SELECT2 || button == RIGHT_BUTTON)
1561 c = (i == EMPTY ? '0' : i == N_ZERO ? '1' : '-');
1562 else if (button == CURSOR_SELECT || button == LEFT_BUTTON)
1563 c = (i == EMPTY ? '1' : i == N_ONE ? '0' : '-');
1565 if (state->grid[hy * w2 + hx] ==
1566 (c == '0' ? N_ZERO : c == '1' ? N_ONE : EMPTY))
1567 return NULL; /* don't put no-ops on the undo chain */
1569 sprintf(buf, "P%c,%d,%d", c, hx, hy);
1576 static game_state *execute_move(const game_state *state, const char *move)
1578 int w2 = state->w2, h2 = state->h2;
1585 if (move[0] == 'S') {
1588 ret = dup_game(state);
1591 for (i = 0; i < s; i++) {
1593 if (!*p || !(*p == '1' || *p == '0')) {
1598 ret->grid[i] = (*p == '1' ? N_ONE : N_ZERO);
1602 ret->completed = ret->cheated = TRUE;
1604 } else if (move[0] == 'P'
1605 && sscanf(move + 1, "%c,%d,%d", &c, &x, &y) == 3 && x >= 0
1606 && x < w2 && y >= 0 && y < h2 && (c == '-' || c == '0'
1608 ret = dup_game(state);
1611 if (state->immutable[i]) {
1616 ret->grid[i] = (c == '1' ? N_ONE : c == '0' ? N_ZERO : EMPTY);
1618 if (!ret->completed && unruly_validate_counts(ret, NULL, NULL) == 0
1619 && (unruly_validate_all_rows(ret, NULL) == 0))
1620 ret->completed = TRUE;
1628 /* ----------------------------------------------------------------------
1632 static void game_compute_size(const game_params *params, int tilesize,
1635 *x = tilesize * (params->w2 + 1);
1636 *y = tilesize * (params->h2 + 1);
1639 static void game_set_size(drawing *dr, game_drawstate *ds,
1640 const game_params *params, int tilesize)
1642 ds->tilesize = tilesize;
1645 static float *game_colours(frontend *fe, int *ncolours)
1647 float *ret = snewn(3 * NCOLOURS, float);
1650 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
1652 for (i = 0; i < 3; i++) {
1653 ret[COL_1 * 3 + i] = 0.2F;
1654 ret[COL_1_HIGHLIGHT * 3 + i] = 0.4F;
1655 ret[COL_1_LOWLIGHT * 3 + i] = 0.0F;
1656 ret[COL_0 * 3 + i] = 0.95F;
1657 ret[COL_0_HIGHLIGHT * 3 + i] = 1.0F;
1658 ret[COL_0_LOWLIGHT * 3 + i] = 0.9F;
1659 ret[COL_EMPTY * 3 + i] = 0.5F;
1660 ret[COL_GRID * 3 + i] = 0.3F;
1662 game_mkhighlight_specific(fe, ret, COL_0, COL_0_HIGHLIGHT, COL_0_LOWLIGHT);
1663 game_mkhighlight_specific(fe, ret, COL_1, COL_1_HIGHLIGHT, COL_1_LOWLIGHT);
1665 ret[COL_ERROR * 3 + 0] = 1.0F;
1666 ret[COL_ERROR * 3 + 1] = 0.0F;
1667 ret[COL_ERROR * 3 + 2] = 0.0F;
1669 ret[COL_CURSOR * 3 + 0] = 0.0F;
1670 ret[COL_CURSOR * 3 + 1] = 0.7F;
1671 ret[COL_CURSOR * 3 + 2] = 0.0F;
1673 *ncolours = NCOLOURS;
1677 static void unruly_draw_err_rectangle(drawing *dr, int x, int y, int w, int h,
1680 double thick = tilesize / 10;
1681 double margin = tilesize / 20;
1683 draw_rect(dr, x+margin, y+margin, w-2*margin, thick, COL_ERROR);
1684 draw_rect(dr, x+margin, y+margin, thick, h-2*margin, COL_ERROR);
1685 draw_rect(dr, x+margin, y+h-margin-thick, w-2*margin, thick, COL_ERROR);
1686 draw_rect(dr, x+w-margin-thick, y+margin, thick, h-2*margin, COL_ERROR);
1689 static void unruly_draw_tile(drawing *dr, int x, int y, int tilesize, int tile)
1691 clip(dr, x, y, tilesize, tilesize);
1693 /* Draw the grid edge first, so the tile can overwrite it */
1694 draw_rect(dr, x, y, tilesize, tilesize, COL_GRID);
1696 /* Background of the tile */
1698 int val = (tile & FF_ZERO ? 0 : tile & FF_ONE ? 2 : 1);
1699 val = (val == 0 ? COL_0 : val == 2 ? COL_1 : COL_EMPTY);
1701 if ((tile & (FF_FLASH1 | FF_FLASH2)) &&
1702 (val == COL_0 || val == COL_1)) {
1703 val += (tile & FF_FLASH1 ? 1 : 2);
1706 draw_rect(dr, x, y, tilesize-1, tilesize-1, val);
1708 if ((val == COL_0 || val == COL_1) && (tile & FF_IMMUTABLE)) {
1709 draw_rect(dr, x + tilesize/6, y + tilesize/6,
1710 tilesize - 2*(tilesize/6) - 2, 1, val + 2);
1711 draw_rect(dr, x + tilesize/6, y + tilesize/6,
1712 1, tilesize - 2*(tilesize/6) - 2, val + 2);
1713 draw_rect(dr, x + tilesize/6 + 1, y + tilesize - tilesize/6 - 2,
1714 tilesize - 2*(tilesize/6) - 2, 1, val + 1);
1715 draw_rect(dr, x + tilesize - tilesize/6 - 2, y + tilesize/6 + 1,
1716 1, tilesize - 2*(tilesize/6) - 2, val + 1);
1720 /* 3-in-a-row errors */
1721 if (tile & (FE_HOR_ROW_LEFT | FE_HOR_ROW_RIGHT)) {
1722 int left = x, right = x + tilesize - 1;
1723 if ((tile & FE_HOR_ROW_LEFT))
1724 right += tilesize/2;
1725 if ((tile & FE_HOR_ROW_RIGHT))
1727 unruly_draw_err_rectangle(dr, left, y, right-left, tilesize-1, tilesize);
1729 if (tile & (FE_VER_ROW_TOP | FE_VER_ROW_BOTTOM)) {
1730 int top = y, bottom = y + tilesize - 1;
1731 if ((tile & FE_VER_ROW_TOP))
1732 bottom += tilesize/2;
1733 if ((tile & FE_VER_ROW_BOTTOM))
1735 unruly_draw_err_rectangle(dr, x, top, tilesize-1, bottom-top, tilesize);
1739 if (tile & FE_COUNT) {
1740 draw_text(dr, x + tilesize/2, y + tilesize/2, FONT_VARIABLE,
1741 tilesize/2, ALIGN_HCENTRE | ALIGN_VCENTRE, COL_ERROR, "!");
1744 /* Row-match errors */
1745 if (tile & FE_ROW_MATCH) {
1746 draw_rect(dr, x, y+tilesize/2-tilesize/12,
1747 tilesize, 2*(tilesize/12), COL_ERROR);
1749 if (tile & FE_COL_MATCH) {
1750 draw_rect(dr, x+tilesize/2-tilesize/12, y,
1751 2*(tilesize/12), tilesize, COL_ERROR);
1754 /* Cursor rectangle */
1755 if (tile & FF_CURSOR) {
1756 draw_rect(dr, x, y, tilesize/12, tilesize-1, COL_CURSOR);
1757 draw_rect(dr, x, y, tilesize-1, tilesize/12, COL_CURSOR);
1758 draw_rect(dr, x+tilesize-1-tilesize/12, y, tilesize/12, tilesize-1,
1760 draw_rect(dr, x, y+tilesize-1-tilesize/12, tilesize-1, tilesize/12,
1765 draw_update(dr, x, y, tilesize, tilesize);
1768 #define TILE_SIZE (ds->tilesize)
1769 #define DEFAULT_TILE_SIZE 32
1770 #define FLASH_FRAME 0.12F
1771 #define FLASH_TIME (FLASH_FRAME * 3)
1773 static void game_redraw(drawing *dr, game_drawstate *ds,
1774 const game_state *oldstate, const game_state *state,
1775 int dir, const game_ui *ui,
1776 float animtime, float flashtime)
1778 int w2 = state->w2, h2 = state->h2;
1784 /* Main window background */
1785 draw_rect(dr, 0, 0, TILE_SIZE * (w2+1), TILE_SIZE * (h2+1),
1787 /* Outer edge of grid */
1788 draw_rect(dr, COORD(0)-TILE_SIZE/10, COORD(0)-TILE_SIZE/10,
1789 TILE_SIZE*w2 + 2*(TILE_SIZE/10) - 1,
1790 TILE_SIZE*h2 + 2*(TILE_SIZE/10) - 1, COL_GRID);
1792 draw_update(dr, 0, 0, TILE_SIZE * (w2+1), TILE_SIZE * (h2+1));
1798 flash = (int)(flashtime / FLASH_FRAME) == 1 ? FF_FLASH2 : FF_FLASH1;
1800 for (i = 0; i < s; i++)
1802 unruly_validate_all_rows(state, ds->gridfs);
1803 for (i = 0; i < 2 * (h2 + w2); i++)
1805 unruly_validate_counts(state, NULL, ds->rowfs);
1807 for (y = 0; y < h2; y++) {
1808 for (x = 0; x < w2; x++) {
1813 tile = ds->gridfs[i];
1815 if (state->grid[i] == N_ONE) {
1817 if (ds->rowfs[y] || ds->rowfs[2*h2 + x])
1819 } else if (state->grid[i] == N_ZERO) {
1821 if (ds->rowfs[h2 + y] || ds->rowfs[2*h2 + w2 + x])
1827 if (state->immutable[i])
1828 tile |= FF_IMMUTABLE;
1830 if (ui->cursor && ui->cx == x && ui->cy == y)
1833 if (ds->grid[i] != tile) {
1835 unruly_draw_tile(dr, COORD(x), COORD(y), TILE_SIZE, tile);
1841 static float game_anim_length(const game_state *oldstate,
1842 const game_state *newstate, int dir, game_ui *ui)
1847 static float game_flash_length(const game_state *oldstate,
1848 const game_state *newstate, int dir, game_ui *ui)
1850 if (!oldstate->completed && newstate->completed &&
1851 !oldstate->cheated && !newstate->cheated)
1856 static int game_status(const game_state *state)
1858 return state->completed ? +1 : 0;
1861 static int game_timing_state(const game_state *state, game_ui *ui)
1866 static void game_print_size(const game_params *params, float *x, float *y)
1870 /* Using 7mm squares */
1871 game_compute_size(params, 700, &pw, &ph);
1876 static void game_print(drawing *dr, const game_state *state, int tilesize)
1878 int w2 = state->w2, h2 = state->h2;
1881 int ink = print_mono_colour(dr, 0);
1883 for (y = 0; y < h2; y++)
1884 for (x = 0; x < w2; x++) {
1885 int tx = x * tilesize + (tilesize / 2);
1886 int ty = y * tilesize + (tilesize / 2);
1888 /* Draw the border */
1892 coords[2] = tx + tilesize;
1894 coords[4] = tx + tilesize;
1895 coords[5] = ty + tilesize - 1;
1897 coords[7] = ty + tilesize - 1;
1898 draw_polygon(dr, coords, 4, -1, ink);
1900 if (state->grid[y * w2 + x] == N_ONE)
1901 draw_rect(dr, tx, ty, tilesize, tilesize, ink);
1902 else if (state->grid[y * w2 + x] == N_ZERO)
1903 draw_circle(dr, tx + tilesize/2, ty + tilesize/2,
1904 tilesize/12, ink, ink);
1909 #define thegame unruly
1912 const struct game thegame = {
1913 "Unruly", "games.unruly", "unruly",
1915 game_fetch_preset, NULL,
1920 TRUE, game_configure, custom_params,
1928 TRUE, game_can_format_as_text_now, game_text_format,
1936 DEFAULT_TILE_SIZE, game_compute_size, game_set_size,
1939 game_free_drawstate,
1944 TRUE, FALSE, game_print_size, game_print,
1945 FALSE, /* wants_statusbar */
1946 FALSE, game_timing_state,
1950 /* ***************** *
1951 * Standalone solver *
1952 * ***************** */
1954 #ifdef STANDALONE_SOLVER
1958 /* Most of the standalone solver code was copied from unequal.c and singles.c */
1962 static void usage_exit(const char *msg)
1965 fprintf(stderr, "%s: %s\n", quis, msg);
1967 "Usage: %s [-v] [--seed SEED] <params> | [game_id [game_id ...]]\n",
1972 int main(int argc, char *argv[])
1975 time_t seed = time(NULL);
1977 game_params *params = NULL;
1979 char *id = NULL, *desc = NULL, *err;
1983 while (--argc > 0) {
1985 if (!strcmp(p, "--seed")) {
1987 usage_exit("--seed needs an argument");
1988 seed = (time_t) atoi(*++argv);
1990 } else if (!strcmp(p, "-v"))
1991 solver_verbose = TRUE;
1993 usage_exit("unrecognised option");
1999 desc = strchr(id, ':');
2003 params = default_params();
2004 decode_params(params, id);
2005 err = validate_params(params, TRUE);
2007 fprintf(stderr, "Parameters are invalid\n");
2008 fprintf(stderr, "%s: %s", argv[0], err);
2014 char *desc_gen, *aux;
2015 rs = random_new((void *) &seed, sizeof(time_t));
2017 params = default_params();
2018 printf("Generating puzzle with parameters %s\n",
2019 encode_params(params, TRUE));
2020 desc_gen = new_game_desc(params, rs, &aux, FALSE);
2022 if (!solver_verbose) {
2023 char *fmt = game_text_format(new_game(NULL, params, desc_gen));
2028 printf("Game ID: %s\n", desc_gen);
2031 struct unruly_scratch *scratch;
2032 int maxdiff, errcode;
2034 err = validate_desc(params, desc);
2036 fprintf(stderr, "Description is invalid\n");
2037 fprintf(stderr, "%s", err);
2041 input = new_game(NULL, params, desc);
2042 scratch = unruly_new_scratch(input);
2044 maxdiff = unruly_solve_game(input, scratch, DIFFCOUNT);
2046 errcode = unruly_validate_counts(input, scratch, NULL);
2047 if (unruly_validate_all_rows(input, NULL) == -1)
2050 if (errcode != -1) {
2051 char *fmt = game_text_format(input);
2055 printf("Difficulty: already solved!\n");
2057 printf("Difficulty: %s\n", unruly_diffnames[maxdiff]);
2061 printf("No solution found.\n");
2062 else if (errcode == -1)
2063 printf("Puzzle is invalid.\n");
2066 unruly_free_scratch(scratch);