1 /* -*- tab-width: 8; indent-tabs-mode: t -*-
2 * filling.c: An implementation of the Nikoli game fillomino.
3 * Copyright (C) 2007 Jonas Kölker. See LICENSE for the license.
8 * - use a typedef instead of int for numbers on the board
9 * + replace int with something else (signed short?)
10 * - the type should be signed (for -board[i] and -SENTINEL)
11 * - the type should be somewhat big: board[i] = i
12 * - Using shorts gives us 181x181 puzzles as upper bound.
14 * - make a somewhat more clever solver
15 * + enable "ghost regions" of size > 1
16 * - one can put an upper bound on the size of a ghost region
17 * by considering the board size and summing present hints.
18 * + for each square, for i=1..n, what is the distance to a region
19 * containing i? How full is the region? How is this useful?
21 * - in board generation, after having merged regions such that no
22 * more merges are necessary, try splitting (big) regions.
23 * + it seems that smaller regions make for better puzzles; see
24 * for instance the 7x7 puzzle in this file (grep for 7x7:).
26 * - symmetric hints (solo-style)
27 * + right now that means including _many_ hints, and the puzzles
28 * won't look any nicer. Not worth it (at the moment).
30 * - make the solver do recursion/backtracking.
31 * + This is for user-submitted puzzles, not for puzzle
32 * generation (on the other hand, never say never).
34 * - prove that only w=h=2 needs a special case
36 * - solo-like pencil marks?
38 * - a user says that the difficulty is unevenly distributed.
39 * + partition into levels? Will they be non-crap?
41 * - Allow square contents > 9?
42 * + I could use letters for digits (solo does this), but
43 * letters don't have numeric significance (normal people hate
44 * base36), which is relevant here (much more than in solo).
45 * + [click, 1, 0, enter] => [10 in clicked square]?
46 * + How much information is needed to solve? Does one need to
47 * know the algorithm by which the largest number is set?
49 * - eliminate puzzle instances with done chunks (1's in particular)?
50 * + that's what the qsort call is all about.
51 * + the 1's don't bother me that much.
52 * + but this takes a LONG time (not always possible)?
53 * - this may be affected by solver (lack of) quality.
54 * - weed them out by construction instead of post-cons check
55 * + but that interleaves make_board and new_game_desc: you
56 * have to alternate between changing the board and
57 * changing the hint set (instead of just creating the
58 * board once, then changing the hint set once -> done).
60 * - use binary search when discovering the minimal sovable point
61 * + profile to show a need (but when the solver gets slower...)
62 * + 7x9 @ .011s, 9x13 @ .075s, 17x13 @ .661s (all avg with n=100)
63 * + but the hints are independent, not linear, so... what?
76 static unsigned char verbose
;
78 static void printv(char *fmt
, ...) {
89 /*****************************************************************************
90 * GAME CONFIGURATION AND PARAMETERS *
91 *****************************************************************************/
98 struct game_params params
;
105 struct shared_state
*shared
;
106 int completed
, cheated
;
109 static const struct game_params filling_defaults
[3] = {{7, 9}, {9, 13}, {13, 17}};
111 static game_params
*default_params(void)
113 game_params
*ret
= snew(game_params
);
115 *ret
= filling_defaults
[1]; /* struct copy */
120 static int game_fetch_preset(int i
, char **name
, game_params
**params
)
124 if (i
< 0 || i
>= lenof(filling_defaults
)) return FALSE
;
125 *params
= snew(game_params
);
126 **params
= filling_defaults
[i
]; /* struct copy */
127 sprintf(buf
, "%dx%d", filling_defaults
[i
].h
, filling_defaults
[i
].w
);
133 static void free_params(game_params
*params
)
138 static game_params
*dup_params(game_params
*params
)
140 game_params
*ret
= snew(game_params
);
141 *ret
= *params
; /* struct copy */
145 static void decode_params(game_params
*ret
, char const *string
)
147 ret
->w
= ret
->h
= atoi(string
);
148 while (*string
&& isdigit((unsigned char) *string
)) ++string
;
149 if (*string
== 'x') ret
->h
= atoi(++string
);
152 static char *encode_params(game_params
*params
, int full
)
155 sprintf(buf
, "%dx%d", params
->w
, params
->h
);
159 static config_item
*game_configure(game_params
*params
)
164 ret
= snewn(3, config_item
);
166 ret
[0].name
= "Width";
167 ret
[0].type
= C_STRING
;
168 sprintf(buf
, "%d", params
->w
);
169 ret
[0].sval
= dupstr(buf
);
172 ret
[1].name
= "Height";
173 ret
[1].type
= C_STRING
;
174 sprintf(buf
, "%d", params
->h
);
175 ret
[1].sval
= dupstr(buf
);
186 static game_params
*custom_params(config_item
*cfg
)
188 game_params
*ret
= snew(game_params
);
190 ret
->w
= atoi(cfg
[0].sval
);
191 ret
->h
= atoi(cfg
[1].sval
);
196 static char *validate_params(game_params
*params
, int full
)
198 if (params
->w
< 1) return "Width must be at least one";
199 if (params
->h
< 1) return "Height must be at least one";
204 /*****************************************************************************
205 * STRINGIFICATION OF GAME STATE *
206 *****************************************************************************/
210 /* Example of plaintext rendering:
211 * +---+---+---+---+---+---+---+
212 * | 6 | | | 2 | | | 2 |
213 * +---+---+---+---+---+---+---+
214 * | | 3 | | 6 | | 3 | |
215 * +---+---+---+---+---+---+---+
216 * | 3 | | | | | | 1 |
217 * +---+---+---+---+---+---+---+
218 * | | 2 | 3 | | 4 | 2 | |
219 * +---+---+---+---+---+---+---+
220 * | 2 | | | | | | 3 |
221 * +---+---+---+---+---+---+---+
222 * | | 5 | | 1 | | 4 | |
223 * +---+---+---+---+---+---+---+
224 * | 4 | | | 3 | | | 3 |
225 * +---+---+---+---+---+---+---+
227 * This puzzle instance is taken from the nikoli website
228 * Encoded (unsolved and solved), the strings are these:
229 * 7x7:6002002030603030000010230420200000305010404003003
230 * 7x7:6662232336663232331311235422255544325413434443313
232 static char *board_to_string(int *board
, int w
, int h
) {
233 const int sz
= w
* h
;
234 const int chw
= (4*w
+ 2); /* +2 for trailing '+' and '\n' */
235 const int chh
= (2*h
+ 1); /* +1: n fence segments, n+1 posts */
236 const int chlen
= chw
* chh
;
237 char *repr
= snewn(chlen
+ 1, char);
242 /* build the first line ("^(\+---){n}\+$") */
243 for (i
= 0; i
< w
; ++i
) {
250 repr
[4*i
+ 1] = '\n';
252 /* ... and copy it onto the odd-numbered lines */
253 for (i
= 0; i
< h
; ++i
) memcpy(repr
+ (2*i
+ 2) * chw
, repr
, chw
);
255 /* build the second line ("^(\|\t){n}\|$") */
256 for (i
= 0; i
< w
; ++i
) {
257 repr
[chw
+ 4*i
+ 0] = '|';
258 repr
[chw
+ 4*i
+ 1] = ' ';
259 repr
[chw
+ 4*i
+ 2] = ' ';
260 repr
[chw
+ 4*i
+ 3] = ' ';
262 repr
[chw
+ 4*i
+ 0] = '|';
263 repr
[chw
+ 4*i
+ 1] = '\n';
265 /* ... and copy it onto the even-numbered lines */
266 for (i
= 1; i
< h
; ++i
) memcpy(repr
+ (2*i
+ 1) * chw
, repr
+ chw
, chw
);
268 /* fill in the numbers */
269 for (i
= 0; i
< sz
; ++i
) {
272 if (board
[i
] == EMPTY
) continue;
273 repr
[chw
*(2*y
+ 1) + (4*x
+ 2)] = board
[i
] + '0';
280 static int game_can_format_as_text_now(game_params
*params
)
285 static char *game_text_format(game_state
*state
)
287 const int w
= state
->shared
->params
.w
;
288 const int h
= state
->shared
->params
.h
;
289 return board_to_string(state
->board
, w
, h
);
292 /*****************************************************************************
293 * GAME GENERATION AND SOLVER *
294 *****************************************************************************/
296 static const int dx
[4] = {-1, 1, 0, 0};
297 static const int dy
[4] = {0, 0, -1, 1};
307 static void print_board(int *board
, int w
, int h
) {
309 char *repr
= board_to_string(board
, w
, h
);
310 printv("%s\n", repr
);
315 static game_state
*new_game(midend
*, game_params
*, char *);
316 static void free_game(game_state
*);
320 /* generate a random valid board; uses validate_board. */
321 static void make_board(int *board
, int w
, int h
, random_state
*rs
) {
324 const unsigned int sz
= w
* h
;
326 /* w=h=2 is a special case which requires a number > max(w, h) */
327 /* TODO prove that this is the case ONLY for w=h=2. */
328 const int maxsize
= min(max(max(w
, h
), 3), 9);
330 /* Note that if 1 in {w, h} then it's impossible to have a region
331 * of size > w*h, so the special case only affects w=h=2. */
341 dsf
= snew_dsf(sz
); /* implicit dsf_init */
343 /* I abuse the board variable: when generating the puzzle, it
344 * contains a shuffled list of numbers {0, ..., nsq-1}. */
345 for (i
= 0; i
< (int)sz
; ++i
) board
[i
] = i
;
350 shuffle(board
, sz
, sizeof (int), rs
);
351 /* while the board can in principle be fixed */
354 for (i
= 0; i
< (int)sz
; ++i
) {
358 const int aa
= dsf_canonify(dsf
, board
[i
]);
361 for (j
= 0; j
< 4; ++j
) {
362 const int x
= (board
[i
] % w
) + dx
[j
];
363 const int y
= (board
[i
] / w
) + dy
[j
];
365 if (x
< 0 || x
>= w
|| y
< 0 || y
>= h
) continue;
366 bb
= dsf_canonify(dsf
, w
*y
+ x
);
367 if (aa
== bb
) continue;
368 else if (dsf_size(dsf
, aa
) == dsf_size(dsf
, bb
)) {
372 } else if (cc
== sz
) c
= cc
= bb
;
375 a
= dsf_canonify(dsf
, a
);
376 assert(a
!= dsf_canonify(dsf
, b
));
377 if (c
!= sz
) assert(a
!= dsf_canonify(dsf
, c
));
378 dsf_merge(dsf
, a
, c
== sz
? b
: c
);
379 /* if repair impossible; make a new board */
380 if (dsf_size(dsf
, a
) > maxsize
) goto retry
;
386 for (i
= 0; i
< (int)sz
; ++i
) board
[i
] = dsf_size(dsf
, i
);
389 printv("returning board number %d\n", nboards
);
395 assert(FALSE
); /* unreachable */
398 static int rhofree(int *hop
, int start
) {
399 int turtle
= start
, rabbit
= hop
[start
];
400 while (rabbit
!= turtle
) { /* find a cycle */
401 turtle
= hop
[turtle
];
402 rabbit
= hop
[hop
[rabbit
]];
404 do { /* check that start is in the cycle */
405 rabbit
= hop
[rabbit
];
406 if (start
== rabbit
) return 1;
407 } while (rabbit
!= turtle
);
411 static void merge(int *dsf
, int *connected
, int a
, int b
) {
415 assert(rhofree(connected
, a
));
416 assert(rhofree(connected
, b
));
417 a
= dsf_canonify(dsf
, a
);
418 b
= dsf_canonify(dsf
, b
);
420 dsf_merge(dsf
, a
, b
);
422 connected
[a
] = connected
[b
];
424 assert(rhofree(connected
, a
));
425 assert(rhofree(connected
, b
));
428 static void *memdup(const void *ptr
, size_t len
, size_t esz
) {
429 void *dup
= smalloc(len
* esz
);
431 memcpy(dup
, ptr
, len
* esz
);
435 static void expand(struct solver_state
*s
, int w
, int h
, int t
, int f
) {
438 assert(s
->board
[t
] == EMPTY
); /* expand to empty square */
439 assert(s
->board
[f
] != EMPTY
); /* expand from non-empty square */
441 "learn: expanding %d from (%d, %d) into (%d, %d)\n",
442 s
->board
[f
], f
% w
, f
/ w
, t
% w
, t
/ w
);
443 s
->board
[t
] = s
->board
[f
];
444 for (j
= 0; j
< 4; ++j
) {
445 const int x
= (t
% w
) + dx
[j
];
446 const int y
= (t
/ w
) + dy
[j
];
447 const int idx
= w
*y
+ x
;
448 if (x
< 0 || x
>= w
|| y
< 0 || y
>= h
) continue;
449 if (s
->board
[idx
] != s
->board
[t
]) continue;
450 merge(s
->dsf
, s
->connected
, t
, idx
);
455 static void clear_count(int *board
, int sz
) {
457 for (i
= 0; i
< sz
; ++i
) {
458 if (board
[i
] >= 0) continue;
459 else if (board
[i
] == -SENTINEL
) board
[i
] = EMPTY
;
460 else board
[i
] = -board
[i
];
464 static void flood_count(int *board
, int w
, int h
, int i
, int n
, int *c
) {
465 const int sz
= w
* h
;
468 if (board
[i
] == EMPTY
) board
[i
] = -SENTINEL
;
469 else if (board
[i
] == n
) board
[i
] = -board
[i
];
472 if (--*c
== 0) return;
474 for (k
= 0; k
< 4; ++k
) {
475 const int x
= (i
% w
) + dx
[k
];
476 const int y
= (i
/ w
) + dy
[k
];
477 const int idx
= w
*y
+ x
;
478 if (x
< 0 || x
>= w
|| y
< 0 || y
>= h
) continue;
479 flood_count(board
, w
, h
, idx
, n
, c
);
484 static int check_capacity(int *board
, int w
, int h
, int i
) {
486 flood_count(board
, w
, h
, i
, board
[i
], &n
);
487 clear_count(board
, w
* h
);
491 static int expandsize(const int *board
, int *dsf
, int w
, int h
, int i
, int n
) {
496 for (j
= 0; j
< 4; ++j
) {
497 const int x
= (i
% w
) + dx
[j
];
498 const int y
= (i
/ w
) + dy
[j
];
499 const int idx
= w
*y
+ x
;
502 if (x
< 0 || x
>= w
|| y
< 0 || y
>= h
) continue;
503 if (board
[idx
] != n
) continue;
504 root
= dsf_canonify(dsf
, idx
);
505 for (m
= 0; m
< nhits
&& root
!= hits
[m
]; ++m
);
506 if (m
< nhits
) continue;
507 printv("\t (%d, %d) contrib %d to size\n", x
, y
, dsf
[root
] >> 2);
508 size
+= dsf_size(dsf
, root
);
509 assert(dsf_size(dsf
, root
) >= 1);
510 hits
[nhits
++] = root
;
516 * +---+---+---+---+---+---+---+
517 * | 6 | | | 2 | | | 2 |
518 * +---+---+---+---+---+---+---+
519 * | | 3 | | 6 | | 3 | |
520 * +---+---+---+---+---+---+---+
521 * | 3 | | | | | | 1 |
522 * +---+---+---+---+---+---+---+
523 * | | 2 | 3 | | 4 | 2 | |
524 * +---+---+---+---+---+---+---+
525 * | 2 | | | | | | 3 |
526 * +---+---+---+---+---+---+---+
527 * | | 5 | | 1 | | 4 | |
528 * +---+---+---+---+---+---+---+
529 * | 4 | | | 3 | | | 3 |
530 * +---+---+---+---+---+---+---+
533 /* Solving techniques:
535 * CONNECTED COMPONENT FORCED EXPANSION (too big):
536 * When a CC can only be expanded in one direction, because all the
537 * other ones would make the CC too big.
538 * +---+---+---+---+---+
539 * | 2 | 2 | | 2 | _ |
540 * +---+---+---+---+---+
542 * CONNECTED COMPONENT FORCED EXPANSION (too small):
543 * When a CC must include a particular square, because otherwise there
544 * would not be enough room to complete it. This includes squares not
545 * adjacent to the CC through learn_critical_square.
551 * When an empty square has no neighbouring empty squares and only a 1
552 * will go into the square (or other CCs would be too big).
557 * TODO: generalise DROPPING IN A ONE: find the size of the CC of
558 * empty squares and a list of all adjacent numbers. See if only one
559 * number in {1, ..., size} u {all adjacent numbers} is possible.
560 * Probably this is only effective for a CC size < n for some n (4?)
562 * TODO: backtracking.
565 static void filled_square(struct solver_state
*s
, int w
, int h
, int i
) {
567 for (j
= 0; j
< 4; ++j
) {
568 const int x
= (i
% w
) + dx
[j
];
569 const int y
= (i
/ w
) + dy
[j
];
570 const int idx
= w
*y
+ x
;
571 if (x
< 0 || x
>= w
|| y
< 0 || y
>= h
) continue;
572 if (s
->board
[i
] == s
->board
[idx
])
573 merge(s
->dsf
, s
->connected
, i
, idx
);
577 static void init_solver_state(struct solver_state
*s
, int w
, int h
) {
578 const int sz
= w
* h
;
583 for (i
= 0; i
< sz
; ++i
) s
->connected
[i
] = i
;
584 for (i
= 0; i
< sz
; ++i
)
585 if (s
->board
[i
] == EMPTY
) ++s
->nempty
;
586 else filled_square(s
, w
, h
, i
);
589 static int learn_expand_or_one(struct solver_state
*s
, int w
, int h
) {
590 const int sz
= w
* h
;
596 for (i
= 0; i
< sz
; ++i
) {
600 if (s
->board
[i
] != EMPTY
) continue;
602 for (j
= 0; j
< 4; ++j
) {
603 const int x
= (i
% w
) + dx
[j
];
604 const int y
= (i
/ w
) + dy
[j
];
605 const int idx
= w
*y
+ x
;
606 if (x
< 0 || x
>= w
|| y
< 0 || y
>= h
) continue;
607 if (s
->board
[idx
] == EMPTY
) {
612 (s
->board
[idx
] == 1 ||
613 (s
->board
[idx
] >= expandsize(s
->board
, s
->dsf
, w
, h
,
616 assert(s
->board
[i
] == EMPTY
);
617 s
->board
[i
] = -SENTINEL
;
618 if (check_capacity(s
->board
, w
, h
, idx
)) continue;
619 assert(s
->board
[i
] == EMPTY
);
620 printv("learn: expanding in one\n");
621 expand(s
, w
, h
, i
, idx
);
627 printv("learn: one at (%d, %d)\n", i
% w
, i
/ w
);
628 assert(s
->board
[i
] == EMPTY
);
638 static int learn_blocked_expansion(struct solver_state
*s
, int w
, int h
) {
639 const int sz
= w
* h
;
644 /* for every connected component */
645 for (i
= 0; i
< sz
; ++i
) {
649 if (s
->board
[i
] == EMPTY
) continue;
650 j
= dsf_canonify(s
->dsf
, i
);
652 /* (but only for each connected component) */
653 if (i
!= j
) continue;
655 /* (and not if it's already complete) */
656 if (dsf_size(s
->dsf
, j
) == s
->board
[j
]) continue;
658 /* for each square j _in_ the connected component */
661 printv(" looking at (%d, %d)\n", j
% w
, j
/ w
);
663 /* for each neighbouring square (idx) */
664 for (k
= 0; k
< 4; ++k
) {
665 const int x
= (j
% w
) + dx
[k
];
666 const int y
= (j
/ w
) + dy
[k
];
667 const int idx
= w
*y
+ x
;
672 if (x
< 0 || x
>= w
|| y
< 0 || y
>= h
) continue;
673 if (s
->board
[idx
] != EMPTY
) continue;
674 if (exp
== idx
) continue;
675 printv("\ttrying to expand onto (%d, %d)\n", x
, y
);
677 /* find out the would-be size of the new connected
678 * component if we actually expanded into idx */
681 for (l = 0; l < 4; ++l) {
682 const int lx = x + dx[l];
683 const int ly = y + dy[l];
684 const int idxl = w*ly + lx;
687 if (lx < 0 || lx >= w || ly < 0 || ly >= h) continue;
688 if (board[idxl] != board[j]) continue;
689 root = dsf_canonify(dsf, idxl);
690 for (m = 0; m < nhits && root != hits[m]; ++m);
691 if (m != nhits) continue;
692 // printv("\t (%d, %d) contributed %d to size\n", lx, ly, dsf[root] >> 2);
693 size += dsf_size(dsf, root);
694 assert(dsf_size(dsf, root) >= 1);
695 hits[nhits++] = root;
699 size
= expandsize(s
->board
, s
->dsf
, w
, h
, idx
, s
->board
[j
]);
701 /* ... and see if that size is too big, or if we
702 * have other expansion candidates. Otherwise
703 * remember the (so far) only candidate. */
705 printv("\tthat would give a size of %d\n", size
);
706 if (size
> s
->board
[j
]) continue;
707 /* printv("\tnow knowing %d expansions\n", nexpand + 1); */
708 if (exp
!= SENTINEL
) goto next_i
;
713 j
= s
->connected
[j
]; /* next square in the same CC */
714 assert(s
->board
[i
] == s
->board
[j
]);
716 /* end: for each square j _in_ the connected component */
718 if (exp
== SENTINEL
) continue;
719 printv("learning to expand\n");
720 expand(s
, w
, h
, exp
, i
);
726 /* end: for each connected component */
730 static int learn_critical_square(struct solver_state
*s
, int w
, int h
) {
731 const int sz
= w
* h
;
736 /* for each connected component */
737 for (i
= 0; i
< sz
; ++i
) {
739 if (s
->board
[i
] == EMPTY
) continue;
740 if (i
!= dsf_canonify(s
->dsf
, i
)) continue;
741 if (dsf_size(s
->dsf
, i
) == s
->board
[i
]) continue;
742 assert(s
->board
[i
] != 1);
743 /* for each empty square */
744 for (j
= 0; j
< sz
; ++j
) {
745 if (s
->board
[j
] != EMPTY
) continue;
746 s
->board
[j
] = -SENTINEL
;
747 if (check_capacity(s
->board
, w
, h
, i
)) continue;
748 /* if not expanding s->board[i] to s->board[j] implies
749 * that s->board[i] can't reach its full size, ... */
752 "learn: ds %d at (%d, %d) blocking (%d, %d)\n",
753 s
->board
[i
], j
% w
, j
/ w
, i
% w
, i
/ w
);
755 s
->board
[j
] = s
->board
[i
];
756 filled_square(s
, w
, h
, j
);
763 static int solver(const int *orig
, int w
, int h
, char **solution
) {
764 const int sz
= w
* h
;
766 struct solver_state ss
;
767 ss
.board
= memdup(orig
, sz
, sizeof (int));
768 ss
.dsf
= snew_dsf(sz
); /* eqv classes: connected components */
769 ss
.connected
= snewn(sz
, int); /* connected[n] := n.next; */
770 /* cyclic disjoint singly linked lists, same partitioning as dsf.
771 * The lists lets you iterate over a partition given any member */
773 printv("trying to solve this:\n");
774 print_board(ss
.board
, w
, h
);
776 init_solver_state(&ss
, w
, h
);
778 if (learn_blocked_expansion(&ss
, w
, h
)) continue;
779 if (learn_expand_or_one(&ss
, w
, h
)) continue;
780 if (learn_critical_square(&ss
, w
, h
)) continue;
784 printv("best guess:\n");
785 print_board(ss
.board
, w
, h
);
789 assert(*solution
== NULL
);
790 *solution
= snewn(sz
+ 2, char);
792 for (i
= 0; i
< sz
; ++i
) (*solution
)[i
+ 1] = ss
.board
[i
] + '0';
793 (*solution
)[sz
+ 1] = '\0';
794 /* We don't need the \0 for execute_move (the only user)
795 * I'm just being printf-friendly in case I wanna print */
805 static int *make_dsf(int *dsf
, int *board
, const int w
, const int h
) {
806 const int sz
= w
* h
;
810 dsf
= snew_dsf(w
* h
);
812 dsf_init(dsf
, w
* h
);
814 for (i
= 0; i
< sz
; ++i
) {
816 for (j
= 0; j
< 4; ++j
) {
817 const int x
= (i
% w
) + dx
[j
];
818 const int y
= (i
/ w
) + dy
[j
];
819 const int k
= w
*y
+ x
;
820 if (x
< 0 || x
>= w
|| y
< 0 || y
>= h
) continue;
821 if (board
[i
] == board
[k
]) dsf_merge(dsf
, i
, k
);
828 static int filled(int *board, int *randomize, int k, int n) {
830 if (board == NULL) return FALSE;
831 if (randomize == NULL) return FALSE;
832 if (k > n) return FALSE;
833 for (i = 0; i < k; ++i) if (board[randomize[i]] == 0) return FALSE;
834 for (; i < n; ++i) if (board[randomize[i]] != 0) return FALSE;
840 static int compare(const void *pa
, const void *pb
) {
841 if (!g_board
) return 0;
842 return g_board
[*(const int *)pb
] - g_board
[*(const int *)pa
];
845 static void minimize_clue_set(int *board
, int w
, int h
, int *randomize
) {
846 const int sz
= w
* h
;
848 int *board_cp
= snewn(sz
, int);
849 memcpy(board_cp
, board
, sz
* sizeof (int));
851 /* since more clues only helps and never hurts, one pass will do
852 * just fine: if we can remove clue n with k clues of index > n,
853 * we could have removed clue n with >= k clues of index > n.
854 * So an additional pass wouldn't do anything [use induction]. */
855 for (i
= 0; i
< sz
; ++i
) {
856 if (board
[randomize
[i
]] == EMPTY
) continue;
857 board
[randomize
[i
]] = EMPTY
;
858 /* (rot.) symmetry tends to include _way_ too many hints */
859 /* board[sz - randomize[i] - 1] = EMPTY; */
860 if (!solver(board
, w
, h
, NULL
)) {
861 board
[randomize
[i
]] = board_cp
[randomize
[i
]];
862 /* board[sz - randomize[i] - 1] =
863 board_cp[sz - randomize[i] - 1]; */
870 static char *new_game_desc(game_params
*params
, random_state
*rs
,
871 char **aux
, int interactive
)
873 const int w
= params
->w
;
874 const int h
= params
->h
;
875 const int sz
= w
* h
;
876 int *board
= snewn(sz
, int);
877 int *randomize
= snewn(sz
, int);
878 char *game_description
= snewn(sz
+ 1, char);
881 for (i
= 0; i
< sz
; ++i
) {
886 make_board(board
, w
, h
, rs
);
888 qsort(randomize
, sz
, sizeof (int), compare
);
889 minimize_clue_set(board
, w
, h
, randomize
);
891 for (i
= 0; i
< sz
; ++i
) {
892 assert(board
[i
] >= 0);
893 assert(board
[i
] < 10);
894 game_description
[i
] = board
[i
] + '0';
896 game_description
[sz
] = '\0';
899 solver(board, w, h, aux);
900 print_board(board, w, h);
906 return game_description
;
909 static char *validate_desc(game_params
*params
, char *desc
)
912 const int sz
= params
->w
* params
->h
;
913 const char m
= '0' + max(max(params
->w
, params
->h
), 3);
915 printv("desc = '%s'; sz = %d\n", desc
, sz
);
917 for (i
= 0; desc
[i
] && i
< sz
; ++i
)
918 if (!isdigit((unsigned char) *desc
))
919 return "non-digit in string";
920 else if (desc
[i
] > m
)
921 return "too large digit in string";
922 if (desc
[i
]) return "string too long";
923 else if (i
< sz
) return "string too short";
927 static game_state
*new_game(midend
*me
, game_params
*params
, char *desc
)
929 game_state
*state
= snew(game_state
);
930 int sz
= params
->w
* params
->h
;
933 state
->cheated
= state
->completed
= FALSE
;
934 state
->shared
= snew(struct shared_state
);
935 state
->shared
->refcnt
= 1;
936 state
->shared
->params
= *params
; /* struct copy */
937 state
->shared
->clues
= snewn(sz
, int);
938 for (i
= 0; i
< sz
; ++i
) state
->shared
->clues
[i
] = desc
[i
] - '0';
939 state
->board
= memdup(state
->shared
->clues
, sz
, sizeof (int));
944 static game_state
*dup_game(game_state
*state
)
946 const int sz
= state
->shared
->params
.w
* state
->shared
->params
.h
;
947 game_state
*ret
= snew(game_state
);
949 ret
->board
= memdup(state
->board
, sz
, sizeof (int));
950 ret
->shared
= state
->shared
;
951 ret
->cheated
= state
->cheated
;
952 ret
->completed
= state
->completed
;
953 ++ret
->shared
->refcnt
;
958 static void free_game(game_state
*state
)
962 if (--state
->shared
->refcnt
== 0) {
963 sfree(state
->shared
->clues
);
964 sfree(state
->shared
);
969 static char *solve_game(game_state
*state
, game_state
*currstate
,
970 char *aux
, char **error
)
973 const int w
= state
->shared
->params
.w
;
974 const int h
= state
->shared
->params
.h
;
975 if (!solver(state
->board
, w
, h
, &aux
))
976 *error
= "Sorry, I couldn't find a solution";
981 /*****************************************************************************
982 * USER INTERFACE STATE AND ACTION *
983 *****************************************************************************/
986 int *sel
; /* w*h highlighted squares, or NULL */
987 int cur_x
, cur_y
, cur_visible
;
990 static game_ui
*new_ui(game_state
*state
)
992 game_ui
*ui
= snew(game_ui
);
995 ui
->cur_x
= ui
->cur_y
= ui
->cur_visible
= 0;
1000 static void free_ui(game_ui
*ui
)
1007 static char *encode_ui(game_ui
*ui
)
1012 static void decode_ui(game_ui
*ui
, char *encoding
)
1016 static void game_changed_state(game_ui
*ui
, game_state
*oldstate
,
1017 game_state
*newstate
)
1019 /* Clear any selection */
1026 #define PREFERRED_TILE_SIZE 32
1027 #define TILE_SIZE (ds->tilesize)
1028 #define BORDER (TILE_SIZE / 2)
1029 #define BORDER_WIDTH (max(TILE_SIZE / 32, 1))
1031 struct game_drawstate
{
1032 struct game_params params
;
1036 int *dsf_scratch
, *border_scratch
;
1039 static char *interpret_move(game_state
*state
, game_ui
*ui
, game_drawstate
*ds
,
1040 int x
, int y
, int button
)
1042 const int w
= state
->shared
->params
.w
;
1043 const int h
= state
->shared
->params
.h
;
1045 const int tx
= (x
+ TILE_SIZE
- BORDER
) / TILE_SIZE
- 1;
1046 const int ty
= (y
+ TILE_SIZE
- BORDER
) / TILE_SIZE
- 1;
1054 button
&= ~MOD_MASK
;
1056 if (button
== LEFT_BUTTON
|| button
== LEFT_DRAG
) {
1057 /* A left-click anywhere will clear the current selection. */
1058 if (button
== LEFT_BUTTON
) {
1064 if (tx
>= 0 && tx
< w
&& ty
>= 0 && ty
< h
) {
1066 ui
->sel
= snewn(w
*h
, int);
1067 memset(ui
->sel
, 0, w
*h
*sizeof(int));
1069 if (!state
->shared
->clues
[w
*ty
+tx
])
1070 ui
->sel
[w
*ty
+tx
] = 1;
1072 ui
->cur_visible
= 0;
1073 return ""; /* redraw */
1076 if (IS_CURSOR_MOVE(button
)) {
1077 ui
->cur_visible
= 1;
1078 move_cursor(button
, &ui
->cur_x
, &ui
->cur_y
, w
, h
, 0);
1081 if (IS_CURSOR_SELECT(button
)) {
1082 if (!ui
->cur_visible
) {
1083 ui
->cur_visible
= 1;
1087 ui
->sel
= snewn(w
*h
, int);
1088 memset(ui
->sel
, 0, w
*h
*sizeof(int));
1090 if (state
->shared
->clues
[w
*ui
->cur_y
+ ui
->cur_x
] == 0)
1091 ui
->sel
[w
*ui
->cur_y
+ ui
->cur_x
] ^= 1;
1103 if (!isdigit(button
)) return NULL
;
1105 if (button
> (w
== 2 && h
== 2? 3: max(w
, h
))) return NULL
;
1108 for (i
= 0; i
< w
*h
; i
++) {
1110 if ((ui
->sel
&& ui
->sel
[i
]) ||
1111 (!ui
->sel
&& ui
->cur_visible
&& (w
*ui
->cur_y
+ui
->cur_x
) == i
)) {
1112 if (state
->shared
->clues
[i
] != 0) continue; /* in case cursor is on clue */
1113 if (state
->board
[i
] != button
) {
1114 sprintf(buf
, "%s%d", move
? "," : "", i
);
1116 move
= srealloc(move
, strlen(move
)+strlen(buf
)+1);
1119 move
= smalloc(strlen(buf
)+1);
1127 sprintf(buf
, "_%d", button
);
1128 move
= srealloc(move
, strlen(move
)+strlen(buf
)+1);
1131 if (!ui
->sel
) return move
? move
: NULL
;
1134 /* Need to update UI at least, as we cleared the selection */
1135 return move
? move
: "";
1138 static game_state
*execute_move(game_state
*state
, char *move
)
1140 game_state
*new_state
= NULL
;
1141 const int sz
= state
->shared
->params
.w
* state
->shared
->params
.h
;
1145 new_state
= dup_game(state
);
1146 for (++move
; i
< sz
; ++i
) new_state
->board
[i
] = move
[i
] - '0';
1147 new_state
->cheated
= TRUE
;
1150 char *endptr
, *delim
= strchr(move
, '_');
1151 if (!delim
) goto err
;
1152 value
= strtol(delim
+1, &endptr
, 0);
1153 if (*endptr
|| endptr
== delim
+1) goto err
;
1154 if (value
< 0 || value
> 9) goto err
;
1155 new_state
= dup_game(state
);
1157 const int i
= strtol(move
, &endptr
, 0);
1158 if (endptr
== move
) goto err
;
1159 if (i
< 0 || i
>= sz
) goto err
;
1160 new_state
->board
[i
] = value
;
1161 if (*endptr
== '_') break;
1162 if (*endptr
!= ',') goto err
;
1168 * Check for completion.
1170 if (!new_state
->completed
) {
1171 const int w
= new_state
->shared
->params
.w
;
1172 const int h
= new_state
->shared
->params
.h
;
1173 const int sz
= w
* h
;
1174 int *dsf
= make_dsf(NULL
, new_state
->board
, w
, h
);
1176 for (i
= 0; i
< sz
&& new_state
->board
[i
] == dsf_size(dsf
, i
); ++i
);
1179 new_state
->completed
= TRUE
;
1185 if (new_state
) free_game(new_state
);
1189 /* ----------------------------------------------------------------------
1193 #define FLASH_TIME 0.4F
1195 #define COL_CLUE COL_GRID
1207 static void game_compute_size(game_params
*params
, int tilesize
,
1210 *x
= (params
->w
+ 1) * tilesize
;
1211 *y
= (params
->h
+ 1) * tilesize
;
1214 static void game_set_size(drawing
*dr
, game_drawstate
*ds
,
1215 game_params
*params
, int tilesize
)
1217 ds
->tilesize
= tilesize
;
1220 static float *game_colours(frontend
*fe
, int *ncolours
)
1222 float *ret
= snewn(3 * NCOLOURS
, float);
1224 frontend_default_colour(fe
, &ret
[COL_BACKGROUND
* 3]);
1226 ret
[COL_GRID
* 3 + 0] = 0.0F
;
1227 ret
[COL_GRID
* 3 + 1] = 0.0F
;
1228 ret
[COL_GRID
* 3 + 2] = 0.0F
;
1230 ret
[COL_HIGHLIGHT
* 3 + 0] = 0.85F
* ret
[COL_BACKGROUND
* 3 + 0];
1231 ret
[COL_HIGHLIGHT
* 3 + 1] = 0.85F
* ret
[COL_BACKGROUND
* 3 + 1];
1232 ret
[COL_HIGHLIGHT
* 3 + 2] = 0.85F
* ret
[COL_BACKGROUND
* 3 + 2];
1234 ret
[COL_CORRECT
* 3 + 0] = 0.9F
* ret
[COL_BACKGROUND
* 3 + 0];
1235 ret
[COL_CORRECT
* 3 + 1] = 0.9F
* ret
[COL_BACKGROUND
* 3 + 1];
1236 ret
[COL_CORRECT
* 3 + 2] = 0.9F
* ret
[COL_BACKGROUND
* 3 + 2];
1238 ret
[COL_CURSOR
* 3 + 0] = 0.5F
* ret
[COL_BACKGROUND
* 3 + 0];
1239 ret
[COL_CURSOR
* 3 + 1] = 0.5F
* ret
[COL_BACKGROUND
* 3 + 1];
1240 ret
[COL_CURSOR
* 3 + 2] = 0.5F
* ret
[COL_BACKGROUND
* 3 + 2];
1242 ret
[COL_ERROR
* 3 + 0] = 1.0F
;
1243 ret
[COL_ERROR
* 3 + 1] = 0.85F
* ret
[COL_BACKGROUND
* 3 + 1];
1244 ret
[COL_ERROR
* 3 + 2] = 0.85F
* ret
[COL_BACKGROUND
* 3 + 2];
1246 ret
[COL_USER
* 3 + 0] = 0.0F
;
1247 ret
[COL_USER
* 3 + 1] = 0.6F
* ret
[COL_BACKGROUND
* 3 + 1];
1248 ret
[COL_USER
* 3 + 2] = 0.0F
;
1250 *ncolours
= NCOLOURS
;
1254 static game_drawstate
*game_new_drawstate(drawing
*dr
, game_state
*state
)
1256 struct game_drawstate
*ds
= snew(struct game_drawstate
);
1259 ds
->tilesize
= PREFERRED_TILE_SIZE
;
1261 ds
->params
= state
->shared
->params
;
1262 ds
->v
= snewn(ds
->params
.w
* ds
->params
.h
, int);
1263 ds
->flags
= snewn(ds
->params
.w
* ds
->params
.h
, int);
1264 for (i
= 0; i
< ds
->params
.w
* ds
->params
.h
; i
++)
1265 ds
->v
[i
] = ds
->flags
[i
] = -1;
1266 ds
->border_scratch
= snewn(ds
->params
.w
* ds
->params
.h
, int);
1267 ds
->dsf_scratch
= NULL
;
1272 static void game_free_drawstate(drawing
*dr
, game_drawstate
*ds
)
1276 sfree(ds
->border_scratch
);
1277 sfree(ds
->dsf_scratch
);
1281 #define BORDER_U 0x001
1282 #define BORDER_D 0x002
1283 #define BORDER_L 0x004
1284 #define BORDER_R 0x008
1285 #define BORDER_UR 0x010
1286 #define BORDER_DR 0x020
1287 #define BORDER_UL 0x040
1288 #define BORDER_DL 0x080
1289 #define HIGH_BG 0x100
1290 #define CORRECT_BG 0x200
1291 #define ERROR_BG 0x400
1292 #define USER_COL 0x800
1293 #define CURSOR_SQ 0x1000
1295 static void draw_square(drawing
*dr
, game_drawstate
*ds
, int x
, int y
,
1302 * Clip to the grid square.
1304 clip(dr
, BORDER
+ x
*TILE_SIZE
, BORDER
+ y
*TILE_SIZE
,
1305 TILE_SIZE
, TILE_SIZE
);
1311 BORDER
+ x
*TILE_SIZE
,
1312 BORDER
+ y
*TILE_SIZE
,
1315 (flags
& HIGH_BG
? COL_HIGHLIGHT
:
1316 flags
& ERROR_BG
? COL_ERROR
:
1317 flags
& CORRECT_BG
? COL_CORRECT
: COL_BACKGROUND
));
1320 * Draw the grid lines.
1322 draw_line(dr
, BORDER
+ x
*TILE_SIZE
, BORDER
+ y
*TILE_SIZE
,
1323 BORDER
+ (x
+1)*TILE_SIZE
, BORDER
+ y
*TILE_SIZE
, COL_GRID
);
1324 draw_line(dr
, BORDER
+ x
*TILE_SIZE
, BORDER
+ y
*TILE_SIZE
,
1325 BORDER
+ x
*TILE_SIZE
, BORDER
+ (y
+1)*TILE_SIZE
, COL_GRID
);
1335 (x
+ 1) * TILE_SIZE
,
1336 (y
+ 1) * TILE_SIZE
,
1339 ALIGN_VCENTRE
| ALIGN_HCENTRE
,
1340 flags
& USER_COL
? COL_USER
: COL_CLUE
,
1345 * Draw bold lines around the borders.
1347 if (flags
& BORDER_L
)
1349 BORDER
+ x
*TILE_SIZE
+ 1,
1350 BORDER
+ y
*TILE_SIZE
+ 1,
1354 if (flags
& BORDER_U
)
1356 BORDER
+ x
*TILE_SIZE
+ 1,
1357 BORDER
+ y
*TILE_SIZE
+ 1,
1361 if (flags
& BORDER_R
)
1363 BORDER
+ (x
+1)*TILE_SIZE
- BORDER_WIDTH
,
1364 BORDER
+ y
*TILE_SIZE
+ 1,
1368 if (flags
& BORDER_D
)
1370 BORDER
+ x
*TILE_SIZE
+ 1,
1371 BORDER
+ (y
+1)*TILE_SIZE
- BORDER_WIDTH
,
1375 if (flags
& BORDER_UL
)
1377 BORDER
+ x
*TILE_SIZE
+ 1,
1378 BORDER
+ y
*TILE_SIZE
+ 1,
1382 if (flags
& BORDER_UR
)
1384 BORDER
+ (x
+1)*TILE_SIZE
- BORDER_WIDTH
,
1385 BORDER
+ y
*TILE_SIZE
+ 1,
1389 if (flags
& BORDER_DL
)
1391 BORDER
+ x
*TILE_SIZE
+ 1,
1392 BORDER
+ (y
+1)*TILE_SIZE
- BORDER_WIDTH
,
1396 if (flags
& BORDER_DR
)
1398 BORDER
+ (x
+1)*TILE_SIZE
- BORDER_WIDTH
,
1399 BORDER
+ (y
+1)*TILE_SIZE
- BORDER_WIDTH
,
1404 if (flags
& CURSOR_SQ
) {
1405 int coff
= TILE_SIZE
/8;
1406 draw_rect_outline(dr
,
1407 BORDER
+ x
*TILE_SIZE
+ coff
,
1408 BORDER
+ y
*TILE_SIZE
+ coff
,
1417 BORDER
+ x
*TILE_SIZE
,
1418 BORDER
+ y
*TILE_SIZE
,
1423 static void draw_grid(drawing
*dr
, game_drawstate
*ds
, game_state
*state
,
1424 game_ui
*ui
, int flashy
, int borders
, int shading
)
1426 const int w
= state
->shared
->params
.w
;
1427 const int h
= state
->shared
->params
.h
;
1432 * Build a dsf for the board in its current state, to use for
1433 * highlights and hints.
1435 ds
->dsf_scratch
= make_dsf(ds
->dsf_scratch
, state
->board
, w
, h
);
1438 * Work out where we're putting borders between the cells.
1440 for (y
= 0; y
< w
*h
; y
++)
1441 ds
->border_scratch
[y
] = 0;
1443 for (y
= 0; y
< h
; y
++)
1444 for (x
= 0; x
< w
; x
++) {
1448 for (dx
= 0; dx
<= 1; dx
++) {
1453 if (x
+dx
>= w
|| y
+dy
>= h
)
1456 v1
= state
->board
[y
*w
+x
];
1457 v2
= state
->board
[(y
+dy
)*w
+(x
+dx
)];
1458 s1
= dsf_size(ds
->dsf_scratch
, y
*w
+x
);
1459 s2
= dsf_size(ds
->dsf_scratch
, (y
+dy
)*w
+(x
+dx
));
1462 * We only ever draw a border between two cells if
1463 * they don't have the same contents.
1467 * But in that situation, we don't always draw
1468 * a border. We do if the two cells both
1469 * contain actual numbers...
1475 * ... or if at least one of them is a
1476 * completed or overfull omino.
1485 ds
->border_scratch
[y
*w
+x
] |= (dx
? 1 : 2);
1490 * Actually do the drawing.
1492 for (y
= 0; y
< h
; ++y
)
1493 for (x
= 0; x
< w
; ++x
) {
1495 * Determine what we need to draw in this square.
1497 int v
= state
->board
[y
*w
+x
];
1500 if (flashy
|| !shading
) {
1501 /* clear all background flags */
1502 } else if (ui
&& ui
->sel
&& ui
->sel
[y
*w
+x
]) {
1505 int size
= dsf_size(ds
->dsf_scratch
, y
*w
+x
);
1507 flags
|= CORRECT_BG
;
1511 if (ui
&& ui
->cur_visible
&& x
== ui
->cur_x
&& y
== ui
->cur_y
)
1515 * Borders at the very edges of the grid are
1516 * independent of the `borders' flag.
1528 if (x
== 0 || (ds
->border_scratch
[y
*w
+(x
-1)] & 1))
1530 if (y
== 0 || (ds
->border_scratch
[(y
-1)*w
+x
] & 2))
1532 if (x
== w
-1 || (ds
->border_scratch
[y
*w
+x
] & 1))
1534 if (y
== h
-1 || (ds
->border_scratch
[y
*w
+x
] & 2))
1537 if (y
> 0 && x
> 0 && (ds
->border_scratch
[(y
-1)*w
+(x
-1)]))
1539 if (y
> 0 && x
< w
-1 &&
1540 ((ds
->border_scratch
[(y
-1)*w
+x
] & 1) ||
1541 (ds
->border_scratch
[(y
-1)*w
+(x
+1)] & 2)))
1543 if (y
< h
-1 && x
> 0 &&
1544 ((ds
->border_scratch
[y
*w
+(x
-1)] & 2) ||
1545 (ds
->border_scratch
[(y
+1)*w
+(x
-1)] & 1)))
1547 if (y
< h
-1 && x
< w
-1 &&
1548 ((ds
->border_scratch
[y
*w
+(x
+1)] & 2) ||
1549 (ds
->border_scratch
[(y
+1)*w
+x
] & 1)))
1553 if (!state
->shared
->clues
[y
*w
+x
])
1556 if (ds
->v
[y
*w
+x
] != v
|| ds
->flags
[y
*w
+x
] != flags
) {
1557 draw_square(dr
, ds
, x
, y
, v
, flags
);
1559 ds
->flags
[y
*w
+x
] = flags
;
1564 static void game_redraw(drawing
*dr
, game_drawstate
*ds
, game_state
*oldstate
,
1565 game_state
*state
, int dir
, game_ui
*ui
,
1566 float animtime
, float flashtime
)
1568 const int w
= state
->shared
->params
.w
;
1569 const int h
= state
->shared
->params
.h
;
1573 (flashtime
<= FLASH_TIME
/3 || flashtime
>= FLASH_TIME
*2/3);
1577 * The initial contents of the window are not guaranteed and
1578 * can vary with front ends. To be on the safe side, all games
1579 * should start by drawing a big background-colour rectangle
1580 * covering the whole window.
1582 draw_rect(dr
, 0, 0, w
*TILE_SIZE
+ 2*BORDER
, h
*TILE_SIZE
+ 2*BORDER
,
1586 * Smaller black rectangle which is the main grid.
1588 draw_rect(dr
, BORDER
- BORDER_WIDTH
, BORDER
- BORDER_WIDTH
,
1589 w
*TILE_SIZE
+ 2*BORDER_WIDTH
+ 1,
1590 h
*TILE_SIZE
+ 2*BORDER_WIDTH
+ 1,
1593 draw_update(dr
, 0, 0, w
*TILE_SIZE
+ 2*BORDER
, h
*TILE_SIZE
+ 2*BORDER
);
1598 draw_grid(dr
, ds
, state
, ui
, flashy
, TRUE
, TRUE
);
1601 static float game_anim_length(game_state
*oldstate
, game_state
*newstate
,
1602 int dir
, game_ui
*ui
)
1607 static float game_flash_length(game_state
*oldstate
, game_state
*newstate
,
1608 int dir
, game_ui
*ui
)
1612 assert(newstate
->shared
);
1613 assert(oldstate
->shared
== newstate
->shared
);
1614 if (!oldstate
->completed
&& newstate
->completed
&&
1615 !oldstate
->cheated
&& !newstate
->cheated
)
1620 static int game_timing_state(game_state
*state
, game_ui
*ui
)
1625 static void game_print_size(game_params
*params
, float *x
, float *y
)
1630 * I'll use 6mm squares by default.
1632 game_compute_size(params
, 600, &pw
, &ph
);
1637 static void game_print(drawing
*dr
, game_state
*state
, int tilesize
)
1639 const int w
= state
->shared
->params
.w
;
1640 const int h
= state
->shared
->params
.h
;
1643 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1644 game_drawstate
*ds
= game_new_drawstate(dr
, state
);
1645 game_set_size(dr
, ds
, NULL
, tilesize
);
1647 c
= print_mono_colour(dr
, 1); assert(c
== COL_BACKGROUND
);
1648 c
= print_mono_colour(dr
, 0); assert(c
== COL_GRID
);
1649 c
= print_mono_colour(dr
, 1); assert(c
== COL_HIGHLIGHT
);
1650 c
= print_mono_colour(dr
, 1); assert(c
== COL_CORRECT
);
1651 c
= print_mono_colour(dr
, 1); assert(c
== COL_ERROR
);
1652 c
= print_mono_colour(dr
, 0); assert(c
== COL_USER
);
1657 draw_rect(dr
, BORDER
- BORDER_WIDTH
, BORDER
- BORDER_WIDTH
,
1658 w
*TILE_SIZE
+ 2*BORDER_WIDTH
+ 1,
1659 h
*TILE_SIZE
+ 2*BORDER_WIDTH
+ 1,
1663 * We'll draw borders between the ominoes iff the grid is not
1664 * pristine. So scan it to see if it is.
1667 for (i
= 0; i
< w
*h
; i
++)
1668 if (state
->board
[i
] && !state
->shared
->clues
[i
])
1674 print_line_width(dr
, TILE_SIZE
/ 64);
1675 draw_grid(dr
, ds
, state
, NULL
, FALSE
, borders
, FALSE
);
1680 game_free_drawstate(dr
, ds
);
1684 #define thegame filling
1687 const struct game thegame
= {
1688 "Filling", "games.filling", "filling",
1695 TRUE
, game_configure
, custom_params
,
1703 TRUE
, game_can_format_as_text_now
, game_text_format
,
1711 PREFERRED_TILE_SIZE
, game_compute_size
, game_set_size
,
1714 game_free_drawstate
,
1718 TRUE
, FALSE
, game_print_size
, game_print
,
1719 FALSE
, /* wants_statusbar */
1720 FALSE
, game_timing_state
,
1721 REQUIRE_NUMPAD
, /* flags */
1724 #ifdef STANDALONE_SOLVER /* solver? hah! */
1726 int main(int argc
, char **argv
) {
1728 game_params
*params
;
1733 for (par
= desc
= *argv
; *desc
!= '\0' && *desc
!= ':'; ++desc
);
1734 if (*desc
== '\0') {
1735 fprintf(stderr
, "bad puzzle id: %s", par
);
1741 params
= snew(game_params
);
1742 decode_params(params
, par
);
1743 state
= new_game(NULL
, params
, desc
);
1744 if (solver(state
->board
, params
->w
, params
->h
, NULL
))
1745 printf("%s:%s: solvable\n", par
, desc
);
1747 printf("%s:%s: not solvable\n", par
, desc
);
1754 /* vim: set shiftwidth=4 tabstop=8: */