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 */
85 #define ENUM(upper,title,lower) DIFF_ ## upper,
86 #define TITLE(upper,title,lower) #title,
87 #define ENCODE(upper,title,lower) #lower
88 #define CONFIG(upper,title,lower) ":" #title
89 enum { DIFFLIST(ENUM) DIFFCOUNT };
90 static char const *const unruly_diffnames[] = { DIFFLIST(TITLE) };
92 static char const unruly_diffchars[] = DIFFLIST(ENCODE);
93 #define DIFFCONFIG DIFFLIST(CONFIG)
95 const static struct game_params unruly_presets[] = {
99 {10, 10, DIFF_NORMAL},
101 {14, 14, DIFF_NORMAL}
104 #define DEFAULT_PRESET 0
113 #define FE_HOR_ROW_LEFT 0x001
114 #define FE_HOR_ROW_MID 0x003
115 #define FE_HOR_ROW_RIGHT 0x002
117 #define FE_VER_ROW_TOP 0x004
118 #define FE_VER_ROW_MID 0x00C
119 #define FE_VER_ROW_BOTTOM 0x008
121 #define FE_COUNT 0x010
124 #define FF_ZERO 0x040
125 #define FF_CURSOR 0x080
127 #define FF_FLASH1 0x100
128 #define FF_FLASH2 0x200
129 #define FF_IMMUTABLE 0x400
134 unsigned char *immutable;
136 int completed, cheated;
139 static game_params *default_params(void)
141 game_params *ret = snew(game_params);
143 *ret = unruly_presets[DEFAULT_PRESET]; /* structure copy */
148 static int game_fetch_preset(int i, char **name, game_params **params)
153 if (i < 0 || i >= lenof(unruly_presets))
156 ret = snew(game_params);
157 *ret = unruly_presets[i]; /* structure copy */
159 sprintf(buf, "%dx%d %s", ret->w2, ret->h2, unruly_diffnames[ret->diff]);
166 static void free_params(game_params *params)
171 static game_params *dup_params(const game_params *params)
173 game_params *ret = snew(game_params);
174 *ret = *params; /* structure copy */
178 static void decode_params(game_params *params, char const *string)
180 char const *p = string;
182 params->w2 = atoi(p);
183 while (*p && isdigit((unsigned char)*p)) p++;
186 params->h2 = atoi(p);
187 while (*p && isdigit((unsigned char)*p)) p++;
189 params->h2 = params->w2;
195 params->diff = DIFFCOUNT + 1; /* ...which is invalid */
197 for (i = 0; i < DIFFCOUNT; i++) {
198 if (*p == unruly_diffchars[i])
206 static char *encode_params(const game_params *params, int full)
210 sprintf(buf, "%dx%d", params->w2, params->h2);
212 sprintf(buf + strlen(buf), "d%c", unruly_diffchars[params->diff]);
217 static config_item *game_configure(const game_params *params)
222 ret = snewn(4, config_item);
224 ret[0].name = "Width";
225 ret[0].type = C_STRING;
226 sprintf(buf, "%d", params->w2);
227 ret[0].sval = dupstr(buf);
230 ret[1].name = "Height";
231 ret[1].type = C_STRING;
232 sprintf(buf, "%d", params->h2);
233 ret[1].sval = dupstr(buf);
236 ret[2].name = "Difficulty";
237 ret[2].type = C_CHOICES;
238 ret[2].sval = DIFFCONFIG;
239 ret[2].ival = params->diff;
249 static game_params *custom_params(const config_item *cfg)
251 game_params *ret = snew(game_params);
253 ret->w2 = atoi(cfg[0].sval);
254 ret->h2 = atoi(cfg[1].sval);
255 ret->diff = cfg[2].ival;
260 static char *validate_params(const game_params *params, int full)
262 if ((params->w2 & 1) || (params->h2 & 1))
263 return "Width and height must both be even";
264 if (params->w2 < 6 || params->h2 < 6)
265 return "Width and height must be at least 6";
266 if (params->diff >= DIFFCOUNT)
267 return "Unknown difficulty rating";
272 static char *validate_desc(const game_params *params, const char *desc)
274 int w2 = params->w2, h2 = params->h2;
277 const char *p = desc;
281 if (*p >= 'a' && *p < 'z')
282 pos += 1 + (*p - 'a');
283 else if (*p >= 'A' && *p < 'Z')
284 pos += 1 + (*p - 'A');
285 else if (*p == 'Z' || *p == 'z')
288 return "Description contains invalid characters";
294 return "Description too short";
296 return "Description too long";
301 static game_state *blank_state(int w2, int h2)
303 game_state *state = snew(game_state);
308 state->grid = snewn(s, char);
309 state->immutable = snewn(s, unsigned char);
311 memset(state->grid, EMPTY, s);
312 memset(state->immutable, FALSE, s);
314 state->completed = state->cheated = FALSE;
319 static game_state *new_game(midend *me, const game_params *params,
322 int w2 = params->w2, h2 = params->h2;
325 game_state *state = blank_state(w2, h2);
327 const char *p = desc;
331 if (*p >= 'a' && *p < 'z') {
334 state->grid[pos] = N_ZERO;
335 state->immutable[pos] = TRUE;
338 } else if (*p >= 'A' && *p < 'Z') {
341 state->grid[pos] = N_ONE;
342 state->immutable[pos] = TRUE;
345 } else if (*p == 'Z' || *p == 'z') {
348 assert(!"Description contains invalid characters");
357 static game_state *dup_game(const game_state *state)
359 int w2 = state->w2, h2 = state->h2;
362 game_state *ret = blank_state(w2, h2);
364 memcpy(ret->grid, state->grid, s);
365 memcpy(ret->immutable, state->immutable, s);
367 ret->completed = state->completed;
368 ret->cheated = state->cheated;
373 static void free_game(game_state *state)
376 sfree(state->immutable);
381 static int game_can_format_as_text_now(const game_params *params)
386 static char *game_text_format(const game_state *state)
388 int w2 = state->w2, h2 = state->h2;
391 char *ret = snewn(lr * h2 + 1, char);
395 for (y = 0; y < h2; y++) {
396 for (x = 0; x < w2; x++) {
398 char c = state->grid[y * w2 + x];
399 *p++ = (c == N_ONE ? '1' : c == N_ZERO ? '0' : '.');
415 struct unruly_scratch {
422 static void unruly_solver_update_remaining(const game_state *state,
423 struct unruly_scratch *scratch)
425 int w2 = state->w2, h2 = state->h2;
428 /* Reset all scratch data */
429 memset(scratch->ones_rows, 0, h2 * sizeof(int));
430 memset(scratch->ones_cols, 0, w2 * sizeof(int));
431 memset(scratch->zeros_rows, 0, h2 * sizeof(int));
432 memset(scratch->zeros_cols, 0, w2 * sizeof(int));
434 for (x = 0; x < w2; x++)
435 for (y = 0; y < h2; y++) {
436 if (state->grid[y * w2 + x] == N_ONE) {
437 scratch->ones_rows[y]++;
438 scratch->ones_cols[x]++;
439 } else if (state->grid[y * w2 + x] == N_ZERO) {
440 scratch->zeros_rows[y]++;
441 scratch->zeros_cols[x]++;
446 static struct unruly_scratch *unruly_new_scratch(const game_state *state)
448 int w2 = state->w2, h2 = state->h2;
450 struct unruly_scratch *ret = snew(struct unruly_scratch);
452 ret->ones_rows = snewn(h2, int);
453 ret->ones_cols = snewn(w2, int);
454 ret->zeros_rows = snewn(h2, int);
455 ret->zeros_cols = snewn(w2, int);
457 unruly_solver_update_remaining(state, ret);
462 static void unruly_free_scratch(struct unruly_scratch *scratch)
464 sfree(scratch->ones_rows);
465 sfree(scratch->ones_cols);
466 sfree(scratch->zeros_rows);
467 sfree(scratch->zeros_cols);
472 static int unruly_solver_check_threes(game_state *state, int *rowcount,
473 int *colcount, int horizontal,
474 char check, char block)
476 int w2 = state->w2, h2 = state->h2;
478 int dx = horizontal ? 1 : 0, dy = 1 - dx;
479 int sx = dx, sy = dy;
480 int ex = w2 - dx, ey = h2 - dy;
485 /* Check for any three squares which almost form three in a row */
486 for (y = sy; y < ey; y++) {
487 for (x = sx; x < ex; x++) {
488 int i1 = (y-dy) * w2 + (x-dx);
490 int i3 = (y+dy) * w2 + (x+dx);
492 if (state->grid[i1] == check && state->grid[i2] == check
493 && state->grid[i3] == EMPTY) {
495 #ifdef STANDALONE_SOLVER
496 if (solver_verbose) {
497 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n",
498 i1 % w2, i1 / w2, i2 % w2, i2 / w2,
499 (block == N_ONE ? '1' : '0'), i3 % w2,
503 state->grid[i3] = block;
507 if (state->grid[i1] == check && state->grid[i2] == EMPTY
508 && state->grid[i3] == check) {
510 #ifdef STANDALONE_SOLVER
511 if (solver_verbose) {
512 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n",
513 i1 % w2, i1 / w2, i3 % w2, i3 / w2,
514 (block == N_ONE ? '1' : '0'), i2 % w2,
518 state->grid[i2] = block;
522 if (state->grid[i1] == EMPTY && state->grid[i2] == check
523 && state->grid[i3] == check) {
525 #ifdef STANDALONE_SOLVER
526 if (solver_verbose) {
527 printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n",
528 i2 % w2, i2 / w2, i3 % w2, i3 / w2,
529 (block == N_ONE ? '1' : '0'), i1 % w2,
533 state->grid[i1] = block;
543 static int unruly_solver_check_all_threes(game_state *state,
544 struct unruly_scratch *scratch)
549 unruly_solver_check_threes(state, scratch->zeros_rows,
550 scratch->zeros_cols, TRUE, N_ONE, N_ZERO);
552 unruly_solver_check_threes(state, scratch->ones_rows,
553 scratch->ones_cols, TRUE, N_ZERO, N_ONE);
555 unruly_solver_check_threes(state, scratch->zeros_rows,
556 scratch->zeros_cols, FALSE, N_ONE,
559 unruly_solver_check_threes(state, scratch->ones_rows,
560 scratch->ones_cols, FALSE, N_ZERO, N_ONE);
565 static int unruly_solver_fill_row(game_state *state, int i, int horizontal,
566 int *rowcount, int *colcount, char fill)
569 int w2 = state->w2, h2 = state->h2;
572 #ifdef STANDALONE_SOLVER
573 if (solver_verbose) {
574 printf("Solver: Filling %s %i with %c:",
575 (horizontal ? "Row" : "Col"), i,
576 (fill == N_ZERO ? '0' : '1'));
579 /* Place a number in every empty square in a row/column */
580 for (j = 0; j < (horizontal ? w2 : h2); j++) {
581 int p = (horizontal ? i * w2 + j : j * w2 + i);
583 if (state->grid[p] == EMPTY) {
584 #ifdef STANDALONE_SOLVER
585 if (solver_verbose) {
586 printf(" (%i,%i)", (horizontal ? j : i),
587 (horizontal ? i : j));
591 state->grid[p] = fill;
592 rowcount[(horizontal ? i : j)]++;
593 colcount[(horizontal ? j : i)]++;
597 #ifdef STANDALONE_SOLVER
598 if (solver_verbose) {
606 static int unruly_solver_check_complete_nums(game_state *state,
607 int *complete, int horizontal,
608 int *rowcount, int *colcount,
611 int w2 = state->w2, h2 = state->h2;
612 int count = (horizontal ? h2 : w2); /* number of rows to check */
613 int target = (horizontal ? w2 : h2) / 2; /* target number of 0s/1s */
614 int *other = (horizontal ? rowcount : colcount);
619 /* Check for completed rows/cols for one number, then fill in the rest */
620 for (i = 0; i < count; i++) {
621 if (complete[i] == target && other[i] < target) {
622 #ifdef STANDALONE_SOLVER
623 if (solver_verbose) {
624 printf("Solver: Row %i satisfied for %c\n", i,
625 (fill != N_ZERO ? '0' : '1'));
628 ret += unruly_solver_fill_row(state, i, horizontal, rowcount,
636 static int unruly_solver_check_all_complete_nums(game_state *state,
637 struct unruly_scratch *scratch)
642 unruly_solver_check_complete_nums(state, scratch->ones_rows, TRUE,
644 scratch->zeros_cols, N_ZERO);
646 unruly_solver_check_complete_nums(state, scratch->ones_cols, FALSE,
648 scratch->zeros_cols, N_ZERO);
650 unruly_solver_check_complete_nums(state, scratch->zeros_rows, TRUE,
652 scratch->ones_cols, N_ONE);
654 unruly_solver_check_complete_nums(state, scratch->zeros_cols, FALSE,
656 scratch->ones_cols, N_ONE);
661 static int unruly_solver_check_near_complete(game_state *state,
662 int *complete, int horizontal,
663 int *rowcount, int *colcount,
666 int w2 = state->w2, h2 = state->h2;
667 int w = w2/2, h = h2/2;
669 int dx = horizontal ? 1 : 0, dy = 1 - dx;
671 int sx = dx, sy = dy;
672 int ex = w2 - dx, ey = h2 - dy;
678 * This function checks for a row with one Y remaining, then looks
679 * for positions that could cause the remaining squares in the row
680 * to make 3 X's in a row. Example:
682 * Consider the following row:
684 * If the last 1 was placed in the last square, the remaining
685 * squares would be 0:
687 * This violates the 3 in a row rule. We now know that the last 1
688 * shouldn't be in the last cell.
692 /* Check for any two blank and one filled square */
693 for (y = sy; y < ey; y++) {
694 /* One type must have 1 remaining, the other at least 2 */
695 if (horizontal && (complete[y] < w - 1 || rowcount[y] > w - 2))
698 for (x = sx; x < ex; x++) {
701 && (complete[x] < h - 1 || colcount[x] > h - 2))
704 i = (horizontal ? y : x);
705 i1 = (y-dy) * w2 + (x-dx);
707 i3 = (y+dy) * w2 + (x+dx);
709 if (state->grid[i1] == fill && state->grid[i2] == EMPTY
710 && state->grid[i3] == EMPTY) {
712 * Temporarily fill the empty spaces with something else.
713 * This avoids raising the counts for the row and column
715 state->grid[i2] = BOGUS;
716 state->grid[i3] = BOGUS;
718 #ifdef STANDALONE_SOLVER
719 if (solver_verbose) {
720 printf("Solver: Row %i nearly satisfied for %c\n", i,
721 (fill != N_ZERO ? '0' : '1'));
725 unruly_solver_fill_row(state, i, horizontal, rowcount,
728 state->grid[i2] = EMPTY;
729 state->grid[i3] = EMPTY;
732 else if (state->grid[i1] == EMPTY && state->grid[i2] == fill
733 && state->grid[i3] == EMPTY) {
734 state->grid[i1] = BOGUS;
735 state->grid[i3] = BOGUS;
737 #ifdef STANDALONE_SOLVER
738 if (solver_verbose) {
739 printf("Solver: Row %i nearly satisfied for %c\n", i,
740 (fill != N_ZERO ? '0' : '1'));
744 unruly_solver_fill_row(state, i, horizontal, rowcount,
747 state->grid[i1] = EMPTY;
748 state->grid[i3] = EMPTY;
751 else if (state->grid[i1] == EMPTY && state->grid[i2] == EMPTY
752 && state->grid[i3] == fill) {
753 state->grid[i1] = BOGUS;
754 state->grid[i2] = BOGUS;
756 #ifdef STANDALONE_SOLVER
757 if (solver_verbose) {
758 printf("Solver: Row %i nearly satisfied for %c\n", i,
759 (fill != N_ZERO ? '0' : '1'));
763 unruly_solver_fill_row(state, i, horizontal, rowcount,
766 state->grid[i1] = EMPTY;
767 state->grid[i2] = EMPTY;
770 else if (state->grid[i1] == EMPTY && state->grid[i2] == EMPTY
771 && state->grid[i3] == EMPTY) {
772 state->grid[i1] = BOGUS;
773 state->grid[i2] = BOGUS;
774 state->grid[i3] = BOGUS;
776 #ifdef STANDALONE_SOLVER
777 if (solver_verbose) {
778 printf("Solver: Row %i nearly satisfied for %c\n", i,
779 (fill != N_ZERO ? '0' : '1'));
783 unruly_solver_fill_row(state, i, horizontal, rowcount,
786 state->grid[i1] = EMPTY;
787 state->grid[i2] = EMPTY;
788 state->grid[i3] = EMPTY;
796 static int unruly_solver_check_all_near_complete(game_state *state,
797 struct unruly_scratch *scratch)
802 unruly_solver_check_near_complete(state, scratch->ones_rows, TRUE,
804 scratch->zeros_cols, N_ZERO);
806 unruly_solver_check_near_complete(state, scratch->ones_cols, FALSE,
808 scratch->zeros_cols, N_ZERO);
810 unruly_solver_check_near_complete(state, scratch->zeros_rows, TRUE,
812 scratch->ones_cols, N_ONE);
814 unruly_solver_check_near_complete(state, scratch->zeros_cols, FALSE,
816 scratch->ones_cols, N_ONE);
821 static int unruly_validate_rows(const game_state *state, int horizontal,
822 char check, int *errors)
824 int w2 = state->w2, h2 = state->h2;
826 int dx = horizontal ? 1 : 0, dy = 1 - dx;
828 int sx = dx, sy = dy;
829 int ex = w2 - dx, ey = h2 - dy;
834 int err1 = (horizontal ? FE_HOR_ROW_LEFT : FE_VER_ROW_TOP);
835 int err2 = (horizontal ? FE_HOR_ROW_MID : FE_VER_ROW_MID);
836 int err3 = (horizontal ? FE_HOR_ROW_RIGHT : FE_VER_ROW_BOTTOM);
838 /* Check for any three in a row, and mark errors accordingly (if
840 for (y = sy; y < ey; y++) {
841 for (x = sx; x < ex; x++) {
842 int i1 = (y-dy) * w2 + (x-dx);
844 int i3 = (y+dy) * w2 + (x+dx);
846 if (state->grid[i1] == check && state->grid[i2] == check
847 && state->grid[i3] == check) {
861 static int unruly_validate_all_rows(const game_state *state, int *errors)
865 errcount += unruly_validate_rows(state, TRUE, N_ONE, errors);
866 errcount += unruly_validate_rows(state, FALSE, N_ONE, errors);
867 errcount += unruly_validate_rows(state, TRUE, N_ZERO, errors);
868 errcount += unruly_validate_rows(state, FALSE, N_ZERO, errors);
875 static int unruly_validate_counts(const game_state *state,
876 struct unruly_scratch *scratch, int *errors)
878 int w2 = state->w2, h2 = state->h2;
879 int w = w2/2, h = h2/2;
884 /* See if all rows/columns are satisfied. If one is exceeded,
885 * mark it as an error (if required)
888 char hasscratch = TRUE;
890 scratch = unruly_new_scratch(state);
894 for (i = 0; i < w2; i++) {
895 if (scratch->ones_cols[i] < h)
897 if (scratch->zeros_cols[i] < h)
900 if (scratch->ones_cols[i] > h) {
903 errors[2*h2 + i] = TRUE;
905 errors[2*h2 + i] = FALSE;
907 if (scratch->zeros_cols[i] > h) {
910 errors[2*h2 + w2 + i] = TRUE;
912 errors[2*h2 + w2 + i] = FALSE;
914 for (i = 0; i < h2; i++) {
915 if (scratch->ones_rows[i] < w)
917 if (scratch->zeros_rows[i] < w)
920 if (scratch->ones_rows[i] > w) {
927 if (scratch->zeros_rows[i] > w) {
930 errors[h2 + i] = TRUE;
932 errors[h2 + i] = FALSE;
936 unruly_free_scratch(scratch);
938 return (above ? -1 : below ? 1 : 0);
941 static int unruly_solve_game(game_state *state,
942 struct unruly_scratch *scratch, int diff)
944 int done, maxdiff = -1;
949 /* Check for impending 3's */
950 done += unruly_solver_check_all_threes(state, scratch);
952 /* Keep using the simpler techniques while they produce results */
954 if (maxdiff < DIFF_EASY)
959 /* Check for completed rows */
960 done += unruly_solver_check_all_complete_nums(state, scratch);
963 if (maxdiff < DIFF_EASY)
968 /* Normal techniques */
969 if (diff < DIFF_NORMAL)
972 /* Check for nearly completed rows */
973 done += unruly_solver_check_all_near_complete(state, scratch);
976 if (maxdiff < DIFF_NORMAL)
977 maxdiff = DIFF_NORMAL;
986 static char *solve_game(const game_state *state, const game_state *currstate,
987 const char *aux, char **error)
989 game_state *solved = dup_game(state);
990 struct unruly_scratch *scratch = unruly_new_scratch(solved);
994 unruly_solve_game(solved, scratch, DIFFCOUNT);
996 result = unruly_validate_counts(solved, scratch, NULL);
997 if (unruly_validate_all_rows(solved, NULL) == -1)
1001 int w2 = solved->w2, h2 = solved->h2;
1006 ret = snewn(s + 2, char);
1010 for (i = 0; i < s; i++)
1011 *p++ = (solved->grid[i] == N_ONE ? '1' : '0');
1014 } else if (result == 1)
1015 *error = "No solution found.";
1016 else if (result == -1)
1017 *error = "Puzzle is invalid.";
1020 unruly_free_scratch(scratch);
1028 static int unruly_fill_game(game_state *state, struct unruly_scratch *scratch,
1032 int w2 = state->w2, h2 = state->h2;
1037 #ifdef STANDALONE_SOLVER
1038 if (solver_verbose) {
1039 printf("Generator: Attempt to fill grid\n");
1043 /* Generate random array of spaces */
1044 spaces = snewn(s, int);
1045 for (i = 0; i < s; i++)
1047 shuffle(spaces, s, sizeof(*spaces), rs);
1050 * Construct a valid filled grid by repeatedly picking an unfilled
1051 * space and fill it, then calling the solver to fill in any
1052 * spaces forced by the change.
1054 for (j = 0; j < s; j++) {
1057 if (state->grid[i] != EMPTY)
1060 if (random_upto(rs, 2)) {
1061 state->grid[i] = N_ONE;
1062 scratch->ones_rows[i / w2]++;
1063 scratch->ones_cols[i % w2]++;
1065 state->grid[i] = N_ZERO;
1066 scratch->zeros_rows[i / w2]++;
1067 scratch->zeros_cols[i % w2]++;
1070 unruly_solve_game(state, scratch, DIFFCOUNT);
1074 if (unruly_validate_all_rows(state, NULL) != 0
1075 || unruly_validate_counts(state, scratch, NULL) != 0)
1081 static char *new_game_desc(const game_params *params, random_state *rs,
1082 char **aux, int interactive)
1084 #ifdef STANDALONE_SOLVER
1086 int temp_verbose = FALSE;
1089 int w2 = params->w2, h2 = params->h2;
1096 struct unruly_scratch *scratch;
1104 state = blank_state(w2, h2);
1105 scratch = unruly_new_scratch(state);
1106 if (unruly_fill_game(state, scratch, rs))
1109 unruly_free_scratch(scratch);
1112 #ifdef STANDALONE_SOLVER
1113 if (solver_verbose) {
1114 printf("Puzzle generated in %i attempts\n", attempts);
1115 debug = game_text_format(state);
1116 fputs(debug, stdout);
1119 temp_verbose = solver_verbose;
1120 solver_verbose = FALSE;
1124 unruly_free_scratch(scratch);
1126 /* Generate random array of spaces */
1127 spaces = snewn(s, int);
1128 for (i = 0; i < s; i++)
1130 shuffle(spaces, s, sizeof(*spaces), rs);
1133 * Winnow the clues by starting from our filled grid, repeatedly
1134 * picking a filled space and emptying it, as long as the solver
1135 * reports that the puzzle can still be solved after doing so.
1137 for (j = 0; j < s; j++) {
1144 state->grid[i] = EMPTY;
1146 solver = dup_game(state);
1147 scratch = unruly_new_scratch(state);
1149 unruly_solve_game(solver, scratch, params->diff);
1151 if (unruly_validate_counts(solver, scratch, NULL) != 0)
1155 unruly_free_scratch(scratch);
1159 #ifdef STANDALONE_SOLVER
1161 solver_verbose = TRUE;
1163 printf("Final puzzle:\n");
1164 debug = game_text_format(state);
1165 fputs(debug, stdout);
1171 * See if the game has accidentally come out too easy.
1173 if (params->diff > 0) {
1177 solver = dup_game(state);
1178 scratch = unruly_new_scratch(state);
1180 unruly_solve_game(solver, scratch, params->diff - 1);
1182 ok = unruly_validate_counts(solver, scratch, NULL);
1185 unruly_free_scratch(scratch);
1191 * Puzzles of the easiest difficulty can't be too easy.
1197 /* Encode description */
1198 ret = snewn(s + 1, char);
1201 for (i = 0; i < s+1; i++) {
1202 if (i == s || state->grid[i] == N_ZERO) {
1209 } else if (state->grid[i] == N_ONE) {
1236 static game_ui *new_ui(const game_state *state)
1238 game_ui *ret = snew(game_ui);
1240 ret->cx = ret->cy = 0;
1241 ret->cursor = FALSE;
1246 static void free_ui(game_ui *ui)
1251 static char *encode_ui(const game_ui *ui)
1256 static void decode_ui(game_ui *ui, const char *encoding)
1260 static void game_changed_state(game_ui *ui, const game_state *oldstate,
1261 const game_state *newstate)
1265 struct game_drawstate {
1276 static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1278 struct game_drawstate *ds = snew(struct game_drawstate);
1280 int w2 = state->w2, h2 = state->h2;
1287 ds->started = FALSE;
1289 ds->gridfs = snewn(s, int);
1290 ds->rowfs = snewn(2 * (w2 + h2), int);
1292 ds->grid = snewn(s, int);
1293 for (i = 0; i < s; i++)
1299 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1307 #define COORD(x) ( (x) * ds->tilesize + ds->tilesize/2 )
1308 #define FROMCOORD(x) ( ((x)-(ds->tilesize/2)) / ds->tilesize )
1310 static char *interpret_move(const game_state *state, game_ui *ui,
1311 const game_drawstate *ds,
1312 int ox, int oy, int button)
1317 int gx = FROMCOORD(ox);
1318 int gy = FROMCOORD(oy);
1320 int w2 = state->w2, h2 = state->h2;
1322 button &= ~MOD_MASK;
1325 if (button == LEFT_BUTTON || button == RIGHT_BUTTON ||
1326 button == MIDDLE_BUTTON) {
1327 if (ox >= (ds->tilesize / 2) && gx < w2
1328 && oy >= (ds->tilesize / 2) && gy < h2) {
1337 if (IS_CURSOR_MOVE(button)) {
1338 move_cursor(button, &ui->cx, &ui->cy, w2, h2, 0);
1344 if ((ui->cursor && (button == CURSOR_SELECT || button == CURSOR_SELECT2
1345 || button == '\b' || button == '0' || button == '1'
1346 || button == '2')) ||
1347 button == LEFT_BUTTON || button == RIGHT_BUTTON ||
1348 button == MIDDLE_BUTTON) {
1352 if (state->immutable[hy * w2 + hx])
1356 i = state->grid[hy * w2 + hx];
1358 if (button == '0' || button == '2')
1360 else if (button == '1')
1362 else if (button == MIDDLE_BUTTON)
1365 /* Cycle through options */
1366 else if (button == CURSOR_SELECT2 || button == RIGHT_BUTTON)
1367 c = (i == EMPTY ? '0' : i == N_ZERO ? '1' : '-');
1368 else if (button == CURSOR_SELECT || button == LEFT_BUTTON)
1369 c = (i == EMPTY ? '1' : i == N_ONE ? '0' : '-');
1371 if (state->grid[hy * w2 + hx] ==
1372 (c == '0' ? N_ZERO : c == '1' ? N_ONE : EMPTY))
1373 return NULL; /* don't put no-ops on the undo chain */
1375 sprintf(buf, "P%c,%d,%d", c, hx, hy);
1382 static game_state *execute_move(const game_state *state, const char *move)
1384 int w2 = state->w2, h2 = state->h2;
1391 if (move[0] == 'S') {
1394 ret = dup_game(state);
1397 for (i = 0; i < s; i++) {
1399 if (!*p || !(*p == '1' || *p == '0')) {
1404 ret->grid[i] = (*p == '1' ? N_ONE : N_ZERO);
1408 ret->completed = ret->cheated = TRUE;
1410 } else if (move[0] == 'P'
1411 && sscanf(move + 1, "%c,%d,%d", &c, &x, &y) == 3 && x >= 0
1412 && x < w2 && y >= 0 && y < h2 && (c == '-' || c == '0'
1414 ret = dup_game(state);
1417 if (state->immutable[i]) {
1422 ret->grid[i] = (c == '1' ? N_ONE : c == '0' ? N_ZERO : EMPTY);
1424 if (!ret->completed && unruly_validate_counts(ret, NULL, NULL) == 0
1425 && (unruly_validate_all_rows(ret, NULL) == 0))
1426 ret->completed = TRUE;
1434 /* ----------------------------------------------------------------------
1438 static void game_compute_size(const game_params *params, int tilesize,
1441 *x = tilesize * (params->w2 + 1);
1442 *y = tilesize * (params->h2 + 1);
1445 static void game_set_size(drawing *dr, game_drawstate *ds,
1446 const game_params *params, int tilesize)
1448 ds->tilesize = tilesize;
1451 static float *game_colours(frontend *fe, int *ncolours)
1453 float *ret = snewn(3 * NCOLOURS, float);
1456 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
1458 for (i = 0; i < 3; i++) {
1459 ret[COL_1 * 3 + i] = 0.2F;
1460 ret[COL_1_HIGHLIGHT * 3 + i] = 0.4F;
1461 ret[COL_1_LOWLIGHT * 3 + i] = 0.0F;
1462 ret[COL_0 * 3 + i] = 0.95F;
1463 ret[COL_0_HIGHLIGHT * 3 + i] = 1.0F;
1464 ret[COL_0_LOWLIGHT * 3 + i] = 0.9F;
1465 ret[COL_EMPTY * 3 + i] = 0.5F;
1466 ret[COL_GRID * 3 + i] = 0.3F;
1468 game_mkhighlight_specific(fe, ret, COL_0, COL_0_HIGHLIGHT, COL_0_LOWLIGHT);
1469 game_mkhighlight_specific(fe, ret, COL_1, COL_1_HIGHLIGHT, COL_1_LOWLIGHT);
1471 ret[COL_ERROR * 3 + 0] = 1.0F;
1472 ret[COL_ERROR * 3 + 1] = 0.0F;
1473 ret[COL_ERROR * 3 + 2] = 0.0F;
1475 ret[COL_CURSOR * 3 + 0] = 0.0F;
1476 ret[COL_CURSOR * 3 + 1] = 0.7F;
1477 ret[COL_CURSOR * 3 + 2] = 0.0F;
1479 *ncolours = NCOLOURS;
1483 static void unruly_draw_err_rectangle(drawing *dr, int x, int y, int w, int h,
1486 double thick = tilesize / 10;
1487 double margin = tilesize / 20;
1489 draw_rect(dr, x+margin, y+margin, w-2*margin, thick, COL_ERROR);
1490 draw_rect(dr, x+margin, y+margin, thick, h-2*margin, COL_ERROR);
1491 draw_rect(dr, x+margin, y+h-margin-thick, w-2*margin, thick, COL_ERROR);
1492 draw_rect(dr, x+w-margin-thick, y+margin, thick, h-2*margin, COL_ERROR);
1495 static void unruly_draw_tile(drawing *dr, int x, int y, int tilesize, int tile)
1497 clip(dr, x, y, tilesize, tilesize);
1499 /* Draw the grid edge first, so the tile can overwrite it */
1500 draw_rect(dr, x, y, tilesize, tilesize, COL_GRID);
1502 /* Background of the tile */
1504 int val = (tile & FF_ZERO ? 0 : tile & FF_ONE ? 2 : 1);
1505 val = (val == 0 ? COL_0 : val == 2 ? COL_1 : COL_EMPTY);
1507 if ((tile & (FF_FLASH1 | FF_FLASH2)) &&
1508 (val == COL_0 || val == COL_1)) {
1509 val += (tile & FF_FLASH1 ? 1 : 2);
1512 draw_rect(dr, x, y, tilesize-1, tilesize-1, val);
1514 if ((val == COL_0 || val == COL_1) && (tile & FF_IMMUTABLE)) {
1515 draw_rect(dr, x + tilesize/6, y + tilesize/6,
1516 tilesize - 2*(tilesize/6) - 2, 1, val + 2);
1517 draw_rect(dr, x + tilesize/6, y + tilesize/6,
1518 1, tilesize - 2*(tilesize/6) - 2, val + 2);
1519 draw_rect(dr, x + tilesize/6 + 1, y + tilesize - tilesize/6 - 2,
1520 tilesize - 2*(tilesize/6) - 2, 1, val + 1);
1521 draw_rect(dr, x + tilesize - tilesize/6 - 2, y + tilesize/6 + 1,
1522 1, tilesize - 2*(tilesize/6) - 2, val + 1);
1526 /* 3-in-a-row errors */
1527 if (tile & (FE_HOR_ROW_LEFT | FE_HOR_ROW_RIGHT)) {
1528 int left = x, right = x + tilesize - 1;
1529 if ((tile & FE_HOR_ROW_LEFT))
1530 right += tilesize/2;
1531 if ((tile & FE_HOR_ROW_RIGHT))
1533 unruly_draw_err_rectangle(dr, left, y, right-left, tilesize-1, tilesize);
1535 if (tile & (FE_VER_ROW_TOP | FE_VER_ROW_BOTTOM)) {
1536 int top = y, bottom = y + tilesize - 1;
1537 if ((tile & FE_VER_ROW_TOP))
1538 bottom += tilesize/2;
1539 if ((tile & FE_VER_ROW_BOTTOM))
1541 unruly_draw_err_rectangle(dr, x, top, tilesize-1, bottom-top, tilesize);
1545 if (tile & FE_COUNT) {
1546 draw_text(dr, x + tilesize/2, y + tilesize/2, FONT_VARIABLE,
1547 tilesize/2, ALIGN_HCENTRE | ALIGN_VCENTRE, COL_ERROR, "!");
1550 /* Cursor rectangle */
1551 if (tile & FF_CURSOR) {
1552 draw_rect(dr, x, y, tilesize/12, tilesize-1, COL_CURSOR);
1553 draw_rect(dr, x, y, tilesize-1, tilesize/12, COL_CURSOR);
1554 draw_rect(dr, x+tilesize-1-tilesize/12, y, tilesize/12, tilesize-1,
1556 draw_rect(dr, x, y+tilesize-1-tilesize/12, tilesize-1, tilesize/12,
1561 draw_update(dr, x, y, tilesize, tilesize);
1564 #define TILE_SIZE (ds->tilesize)
1565 #define DEFAULT_TILE_SIZE 32
1566 #define FLASH_FRAME 0.12F
1567 #define FLASH_TIME (FLASH_FRAME * 3)
1569 static void game_redraw(drawing *dr, game_drawstate *ds,
1570 const game_state *oldstate, const game_state *state,
1571 int dir, const game_ui *ui,
1572 float animtime, float flashtime)
1574 int w2 = state->w2, h2 = state->h2;
1580 /* Main window background */
1581 draw_rect(dr, 0, 0, TILE_SIZE * (w2+1), TILE_SIZE * (h2+1),
1583 /* Outer edge of grid */
1584 draw_rect(dr, COORD(0)-TILE_SIZE/10, COORD(0)-TILE_SIZE/10,
1585 TILE_SIZE*w2 + 2*(TILE_SIZE/10) - 1,
1586 TILE_SIZE*h2 + 2*(TILE_SIZE/10) - 1, COL_GRID);
1588 draw_update(dr, 0, 0, TILE_SIZE * (w2+1), TILE_SIZE * (h2+1));
1594 flash = (int)(flashtime / FLASH_FRAME) == 1 ? FF_FLASH2 : FF_FLASH1;
1596 for (i = 0; i < s; i++)
1598 unruly_validate_all_rows(state, ds->gridfs);
1599 for (i = 0; i < 2 * (h2 + w2); i++)
1601 unruly_validate_counts(state, NULL, ds->rowfs);
1603 for (y = 0; y < h2; y++) {
1604 for (x = 0; x < w2; x++) {
1609 tile = ds->gridfs[i];
1611 if (state->grid[i] == N_ONE) {
1613 if (ds->rowfs[y] || ds->rowfs[2*h2 + x])
1615 } else if (state->grid[i] == N_ZERO) {
1617 if (ds->rowfs[h2 + y] || ds->rowfs[2*h2 + w2 + x])
1623 if (state->immutable[i])
1624 tile |= FF_IMMUTABLE;
1626 if (ui->cursor && ui->cx == x && ui->cy == y)
1629 if (ds->grid[i] != tile) {
1631 unruly_draw_tile(dr, COORD(x), COORD(y), TILE_SIZE, tile);
1637 static float game_anim_length(const game_state *oldstate,
1638 const game_state *newstate, int dir, game_ui *ui)
1643 static float game_flash_length(const game_state *oldstate,
1644 const game_state *newstate, int dir, game_ui *ui)
1646 if (!oldstate->completed && newstate->completed &&
1647 !oldstate->cheated && !newstate->cheated)
1652 static int game_status(const game_state *state)
1654 return state->completed ? +1 : 0;
1657 static int game_timing_state(const game_state *state, game_ui *ui)
1662 static void game_print_size(const game_params *params, float *x, float *y)
1666 /* Using 7mm squares */
1667 game_compute_size(params, 700, &pw, &ph);
1672 static void game_print(drawing *dr, const game_state *state, int tilesize)
1674 int w2 = state->w2, h2 = state->h2;
1677 int ink = print_mono_colour(dr, 0);
1679 for (y = 0; y < h2; y++)
1680 for (x = 0; x < w2; x++) {
1681 int tx = x * tilesize + (tilesize / 2);
1682 int ty = y * tilesize + (tilesize / 2);
1684 /* Draw the border */
1688 coords[2] = tx + tilesize;
1690 coords[4] = tx + tilesize;
1691 coords[5] = ty + tilesize - 1;
1693 coords[7] = ty + tilesize - 1;
1694 draw_polygon(dr, coords, 4, -1, ink);
1696 if (state->grid[y * w2 + x] == N_ONE)
1697 draw_rect(dr, tx, ty, tilesize, tilesize, ink);
1698 else if (state->grid[y * w2 + x] == N_ZERO)
1699 draw_circle(dr, tx + tilesize/2, ty + tilesize/2,
1700 tilesize/12, ink, ink);
1705 #define thegame unruly
1708 const struct game thegame = {
1709 "Unruly", "games.unruly", "unruly",
1716 TRUE, game_configure, custom_params,
1724 TRUE, game_can_format_as_text_now, game_text_format,
1732 DEFAULT_TILE_SIZE, game_compute_size, game_set_size,
1735 game_free_drawstate,
1740 TRUE, FALSE, game_print_size, game_print,
1741 FALSE, /* wants_statusbar */
1742 FALSE, game_timing_state,
1746 /* ***************** *
1747 * Standalone solver *
1748 * ***************** */
1750 #ifdef STANDALONE_SOLVER
1754 /* Most of the standalone solver code was copied from unequal.c and singles.c */
1758 static void usage_exit(const char *msg)
1761 fprintf(stderr, "%s: %s\n", quis, msg);
1763 "Usage: %s [-v] [--seed SEED] <params> | [game_id [game_id ...]]\n",
1768 int main(int argc, char *argv[])
1771 time_t seed = time(NULL);
1773 game_params *params = NULL;
1775 char *id = NULL, *desc = NULL, *err;
1779 while (--argc > 0) {
1781 if (!strcmp(p, "--seed")) {
1783 usage_exit("--seed needs an argument");
1784 seed = (time_t) atoi(*++argv);
1786 } else if (!strcmp(p, "-v"))
1787 solver_verbose = TRUE;
1789 usage_exit("unrecognised option");
1795 desc = strchr(id, ':');
1799 params = default_params();
1800 decode_params(params, id);
1801 err = validate_params(params, TRUE);
1803 fprintf(stderr, "Parameters are invalid\n");
1804 fprintf(stderr, "%s: %s", argv[0], err);
1810 char *desc_gen, *aux;
1811 rs = random_new((void *) &seed, sizeof(time_t));
1813 params = default_params();
1814 printf("Generating puzzle with parameters %s\n",
1815 encode_params(params, TRUE));
1816 desc_gen = new_game_desc(params, rs, &aux, FALSE);
1818 if (!solver_verbose) {
1819 char *fmt = game_text_format(new_game(NULL, params, desc_gen));
1824 printf("Game ID: %s\n", desc_gen);
1827 struct unruly_scratch *scratch;
1828 int maxdiff, errcode;
1830 err = validate_desc(params, desc);
1832 fprintf(stderr, "Description is invalid\n");
1833 fprintf(stderr, "%s", err);
1837 input = new_game(NULL, params, desc);
1838 scratch = unruly_new_scratch(input);
1840 maxdiff = unruly_solve_game(input, scratch, DIFFCOUNT);
1842 errcode = unruly_validate_counts(input, scratch, NULL);
1843 if (unruly_validate_all_rows(input, NULL) == -1)
1846 if (errcode != -1) {
1847 char *fmt = game_text_format(input);
1851 printf("Difficulty: already solved!\n");
1853 printf("Difficulty: %s\n", unruly_diffnames[maxdiff]);
1857 printf("No solution found.\n");
1858 else if (errcode == -1)
1859 printf("Puzzle is invalid.\n");
1862 unruly_free_scratch(scratch);