chiark / gitweb /
Improve connectedness-error highlighting in Range.
[sgt-puzzles.git] / range.c
1 /*
2  * range.c: implementation of the Nikoli game 'Kurodoko' / 'Kuromasu'.
3  */
4
5 /*
6  * Puzzle rules: the player is given a WxH grid of white squares, some
7  * of which contain numbers. The goal is to paint some of the squares
8  * black, such that:
9  *
10  *  - no cell (err, cell = square) with a number is painted black
11  *  - no black cells have an adjacent (horz/vert) black cell
12  *  - the white cells are all connected (through other white cells)
13  *  - if a cell contains a number n, let h and v be the lengths of the
14  *    maximal horizontal and vertical white sequences containing that
15  *    cell.  Then n must equal h + v - 1.
16  */
17
18 /* example instance with its encoding:
19  *
20  * +--+--+--+--+--+--+--+
21  * |  |  |  |  | 7|  |  |
22  * +--+--+--+--+--+--+--+
23  * | 3|  |  |  |  |  | 8|
24  * +--+--+--+--+--+--+--+
25  * |  |  |  |  |  | 5|  |
26  * +--+--+--+--+--+--+--+
27  * |  |  | 7|  | 7|  |  |
28  * +--+--+--+--+--+--+--+
29  * |  |13|  |  |  |  |  |
30  * +--+--+--+--+--+--+--+
31  * | 4|  |  |  |  |  | 8|
32  * +--+--+--+--+--+--+--+
33  * |  |  | 4|  |  |  |  |
34  * +--+--+--+--+--+--+--+
35  *
36  * 7x7:d7b3e8e5c7a7c13e4d8b4d
37  */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <assert.h>
43 #include <ctype.h>
44 #include <math.h>
45
46 #include "puzzles.h"
47
48 #include <stdarg.h>
49
50 #define setmember(obj, field) ( (obj) . field = field )
51
52 static char *nfmtstr(int n, char *fmt, ...) {
53     va_list va;
54     char *ret = snewn(n+1, char);
55     va_start(va, fmt);
56     vsprintf(ret, fmt, va);
57     va_end(va);
58     return ret;
59 }
60
61 #define SWAP(type, lvar1, lvar2) do { \
62     type tmp = (lvar1); \
63     (lvar1) = (lvar2); \
64     (lvar2) = tmp; \
65 } while (0)
66
67 /* ----------------------------------------------------------------------
68  * Game parameters, presets, states
69  */
70
71 typedef signed char puzzle_size;
72
73 struct game_params {
74     puzzle_size w;
75     puzzle_size h;
76 };
77
78 struct game_state {
79     struct game_params params;
80     unsigned int has_cheated: 1;
81     unsigned int was_solved: 1;
82     puzzle_size *grid;
83 };
84
85 #define DEFAULT_PRESET 0
86 static struct game_params range_presets[] = {{9, 6}, {12, 8}, {13, 9}, {16, 11}};
87 /* rationale: I want all four combinations of {odd/even, odd/even}, as
88  * they play out differently with respect to two-way symmetry.  I also
89  * want them to be generated relatively fast yet still be large enough
90  * to be entertaining for a decent amount of time, and I want them to
91  * make good use of monitor real estate (the typical screen resolution
92  * is why I do 13x9 and not 9x13).
93  */
94
95 static game_params *default_params(void)
96 {
97     game_params *ret = snew(game_params);
98     *ret = range_presets[DEFAULT_PRESET]; /* structure copy */
99     return ret;
100 }
101
102 static game_params *dup_params(const game_params *params)
103 {
104     game_params *ret = snew(game_params);
105     *ret = *params; /* structure copy */
106     return ret;
107 }
108
109 static int game_fetch_preset(int i, char **name, game_params **params)
110 {
111     game_params *ret;
112
113     if (i < 0 || i >= lenof(range_presets)) return FALSE;
114
115     ret = default_params();
116     *ret = range_presets[i]; /* struct copy */
117     *params = ret;
118
119     *name = nfmtstr(40, "%d x %d", range_presets[i].w, range_presets[i].h);
120
121     return TRUE;
122 }
123
124 static void free_params(game_params *params)
125 {
126     sfree(params);
127 }
128
129 static void decode_params(game_params *params, char const *string)
130 {
131     /* FIXME check for puzzle_size overflow and decoding issues */
132     params->w = params->h = atoi(string);
133     while (*string && isdigit((unsigned char) *string)) ++string;
134     if (*string == 'x') {
135         string++;
136         params->h = atoi(string);
137         while (*string && isdigit((unsigned char)*string)) string++;
138     }
139 }
140
141 static char *encode_params(const game_params *params, int full)
142 {
143     char str[80];
144     sprintf(str, "%dx%d", params->w, params->h);
145     return dupstr(str);
146 }
147
148 static config_item *game_configure(const game_params *params)
149 {
150     config_item *ret;
151
152     ret = snewn(3, config_item);
153
154     ret[0].name = "Width";
155     ret[0].type = C_STRING;
156     ret[0].sval = nfmtstr(10, "%d", params->w);
157     ret[0].ival = 0;
158
159     ret[1].name = "Height";
160     ret[1].type = C_STRING;
161     ret[1].sval = nfmtstr(10, "%d", params->h);
162     ret[1].ival = 0;
163
164     ret[2].name = NULL;
165     ret[2].type = C_END;
166     ret[2].sval = NULL;
167     ret[2].ival = 0;
168
169     return ret;
170 }
171
172 static game_params *custom_params(const config_item *configuration)
173 {
174     game_params *ret = snew(game_params);
175     ret->w = atoi(configuration[0].sval);
176     ret->h = atoi(configuration[1].sval);
177     return ret;
178 }
179
180 #define memdup(dst, src, n, type) do { \
181     dst = snewn(n, type); \
182     memcpy(dst, src, n * sizeof (type)); \
183 } while (0)
184
185 static game_state *dup_game(const game_state *state)
186 {
187     game_state *ret = snew(game_state);
188     int const n = state->params.w * state->params.h;
189
190     *ret = *state; /* structure copy */
191
192     /* copy the poin_tee_, set a new value of the poin_ter_ */
193     memdup(ret->grid, state->grid, n, puzzle_size);
194
195     return ret;
196 }
197
198 static void free_game(game_state *state)
199 {
200     sfree(state->grid);
201     sfree(state);
202 }
203
204
205 /* ----------------------------------------------------------------------
206  * The solver subsystem.
207  *
208  * The solver is used for two purposes:
209  *  - To solve puzzles when the user selects `Solve'.
210  *  - To test solubility of a grid as clues are being removed from it
211  *    during the puzzle generation.
212  *
213  * It supports the following ways of reasoning:
214  *
215  *  - A cell adjacent to a black cell must be white.
216  *
217  *  - If painting a square black would bisect the white regions, that
218  *    square is white (by finding biconnected components' cut points)
219  *
220  *  - A cell with number n, covering at most k white squares in three
221  *    directions must white-cover n-k squares in the last direction.
222  *
223  *  - A cell with number n known to cover k squares, if extending the
224  *    cover by one square in a given direction causes the cell to
225  *    cover _more_ than n squares, that extension cell must be black.
226  *
227  *    (either if the square already covers n, or if it extends into a
228  *    chunk of size > n - k)
229  *
230  *  - Recursion.  Pick any cell and see if this leads to either a
231  *    contradiction or a solution (and then act appropriately).
232  *
233  *
234  * TODO:
235  *
236  * (propagation upper limit)
237  *  - If one has two numbers on the same line, the smaller limits the
238  *    larger.  Example: in |b|_|_|8|4|_|_|b|, only two _'s can be both
239  *    white and connected to the "8" cell; so that cell will propagate
240  *    at least four cells orthogonally to the displayed line (which is
241  *    better than the current "at least 2").
242  *
243  * (propagation upper limit)
244  *  - cells can't propagate into other cells if doing so exceeds that
245  *    number.  Example: in |b|4|.|.|2|b|, at most one _ can be white;
246  *    otherwise, the |2| would have too many reaching white cells.
247  *
248  * (propagation lower and upper limit)
249  *  - `Full Combo': in each four directions d_1 ... d_4, find a set of
250  *    possible propagation distances S_1 ... S_4.  For each i=1..4,
251  *    for each x in S_i: if not exists (y, z, w) in the other sets
252  *    such that (x+y+z+w+1 == clue value): then remove x from S_i.
253  *    Repeat until this stabilizes.  If any cell would contradict
254  */
255
256 #define idx(i, j, w) ((i)*(w) + (j))
257 #define out_of_bounds(r, c, w, h) \
258    ((r) < 0 || (r) >= h || (c) < 0 || (c) >= w)
259
260 typedef struct square {
261     puzzle_size r, c;
262 } square;
263
264 enum {BLACK = -2, WHITE, EMPTY};
265 /* white is for pencil marks, empty is undecided */
266
267 static int const dr[4] = {+1,  0, -1,  0};
268 static int const dc[4] = { 0, +1,  0, -1};
269 static int const cursors[4] = /* must match dr and dc */
270 {CURSOR_DOWN, CURSOR_RIGHT, CURSOR_UP, CURSOR_LEFT};
271
272 typedef struct move {
273     square square;
274     unsigned int colour: 1;
275 } move;
276 enum {M_BLACK = 0, M_WHITE = 1};
277
278 typedef move *(reasoning)(game_state *state,
279                           int nclues,
280                           const square *clues,
281                           move *buf);
282
283 static reasoning solver_reasoning_not_too_big;
284 static reasoning solver_reasoning_adjacency;
285 static reasoning solver_reasoning_connectedness;
286 static reasoning solver_reasoning_recursion;
287
288 enum {
289     DIFF_NOT_TOO_BIG,
290     DIFF_ADJACENCY,
291     DIFF_CONNECTEDNESS,
292     DIFF_RECURSION
293 };
294
295 static move *solve_internal(const game_state *state, move *base, int diff);
296
297 static char *solve_game(const game_state *orig, const game_state *curpos,
298                         const char *aux, char **error)
299 {
300     int const n = orig->params.w * orig->params.h;
301     move *const base = snewn(n, move);
302     move *moves = solve_internal(orig, base, DIFF_RECURSION);
303
304     char *ret = NULL;
305
306     if (moves != NULL) {
307         int const k = moves - base;
308         char *str = ret = snewn(15*k + 2, char);
309         char colour[2] = "BW";
310         move *it;
311         *str++ = 'S';
312         *str = '\0';
313         for (it = base; it < moves; ++it)
314             str += sprintf(str, "%c,%d,%d", colour[it->colour],
315                            it->square.r, it->square.c);
316     } else *error = "This puzzle instance contains a contradiction";
317
318     sfree(base);
319     return ret;
320 }
321
322 static square *find_clues(const game_state *state, int *ret_nclues);
323 static move *do_solve(game_state *state,
324                       int nclues,
325                       const square *clues,
326                       move *move_buffer,
327                       int difficulty);
328
329 /* new_game_desc entry point in the solver subsystem */
330 static move *solve_internal(const game_state *state, move *base, int diff)
331 {
332     int nclues;
333     square *const clues = find_clues(state, &nclues);
334     game_state *dup = dup_game(state);
335     move *const moves = do_solve(dup, nclues, clues, base, diff);
336     free_game(dup);
337     sfree(clues);
338     return moves;
339 }
340
341 static reasoning *const reasonings[] = {
342     solver_reasoning_not_too_big,
343     solver_reasoning_adjacency,
344     solver_reasoning_connectedness,
345     solver_reasoning_recursion
346 };
347
348 static move *do_solve(game_state *state,
349                       int nclues,
350                       const square *clues,
351                       move *move_buffer,
352                       int difficulty)
353 {
354     struct move *buf = move_buffer, *oldbuf;
355     int i;
356
357     do {
358         oldbuf = buf;
359         for (i = 0; i < lenof(reasonings) && i <= difficulty; ++i) {
360             /* only recurse if all else fails */
361             if (i == DIFF_RECURSION && buf > oldbuf) continue;
362             buf = (*reasonings[i])(state, nclues, clues, buf);
363             if (buf == NULL) return NULL;
364         }
365     } while (buf > oldbuf);
366
367     return buf;
368 }
369
370 #define MASK(n) (1 << ((n) + 2))
371
372 static int runlength(puzzle_size r, puzzle_size c,
373                      puzzle_size dr, puzzle_size dc,
374                      const game_state *state, int colourmask)
375 {
376     int const w = state->params.w, h = state->params.h;
377     int sz = 0;
378     while (TRUE) {
379         int cell = idx(r, c, w);
380         if (out_of_bounds(r, c, w, h)) break;
381         if (state->grid[cell] > 0) {
382             if (!(colourmask & ~(MASK(BLACK) | MASK(WHITE) | MASK(EMPTY))))
383                 break;
384         } else if (!(MASK(state->grid[cell]) & colourmask)) break;
385         ++sz;
386         r += dr;
387         c += dc;
388     }
389     return sz;
390 }
391
392 static void solver_makemove(puzzle_size r, puzzle_size c, int colour,
393                             game_state *state, move **buffer_ptr)
394 {
395     int const cell = idx(r, c, state->params.w);
396     if (out_of_bounds(r, c, state->params.w, state->params.h)) return;
397     if (state->grid[cell] != EMPTY) return;
398     setmember((*buffer_ptr)->square, r);
399     setmember((*buffer_ptr)->square, c);
400     setmember(**buffer_ptr, colour);
401     ++*buffer_ptr;
402     state->grid[cell] = (colour == M_BLACK ? BLACK : WHITE);
403 }
404
405 static move *solver_reasoning_adjacency(game_state *state,
406                                         int nclues,
407                                         const square *clues,
408                                         move *buf)
409 {
410     int r, c, i;
411     for (r = 0; r < state->params.h; ++r)
412         for (c = 0; c < state->params.w; ++c) {
413             int const cell = idx(r, c, state->params.w);
414             if (state->grid[cell] != BLACK) continue;
415             for (i = 0; i < 4; ++i)
416                 solver_makemove(r + dr[i], c + dc[i], M_WHITE, state, &buf);
417         }
418     return buf;
419 }
420
421 enum {NOT_VISITED = -1};
422
423 static int dfs_biconnect_visit(puzzle_size r, puzzle_size c,
424                                game_state *state,
425                                square *dfs_parent, int *dfs_depth,
426                                move **buf);
427
428 static move *solver_reasoning_connectedness(game_state *state,
429                                             int nclues,
430                                             const square *clues,
431                                             move *buf)
432 {
433     int const w = state->params.w, h = state->params.h, n = w * h;
434
435     square *const dfs_parent = snewn(n, square);
436     int *const dfs_depth = snewn(n, int);
437
438     int i;
439     for (i = 0; i < n; ++i) {
440         dfs_parent[i].r = NOT_VISITED;
441         dfs_depth[i] = -n;
442     }
443
444     for (i = 0; i < n && state->grid[i] == BLACK; ++i);
445
446     dfs_parent[i].r = i / w;
447     dfs_parent[i].c = i % w; /* `dfs root`.parent == `dfs root` */
448     dfs_depth[i] = 0;
449
450     dfs_biconnect_visit(i / w, i % w, state, dfs_parent, dfs_depth, &buf);
451
452     sfree(dfs_parent);
453     sfree(dfs_depth);
454
455     return buf;
456 }
457
458 /* returns the `lowpoint` of (r, c) */
459 static int dfs_biconnect_visit(puzzle_size r, puzzle_size c,
460                                game_state *state,
461                                square *dfs_parent, int *dfs_depth,
462                                move **buf)
463 {
464     const puzzle_size w = state->params.w, h = state->params.h;
465     int const i = idx(r, c, w), mydepth = dfs_depth[i];
466     int lowpoint = mydepth, j, nchildren = 0;
467
468     for (j = 0; j < 4; ++j) {
469         const puzzle_size rr = r + dr[j], cc = c + dc[j];
470         int const cell = idx(rr, cc, w);
471
472         if (out_of_bounds(rr, cc, w, h)) continue;
473         if (state->grid[cell] == BLACK) continue;
474
475         if (dfs_parent[cell].r == NOT_VISITED) {
476             int child_lowpoint;
477             dfs_parent[cell].r = r;
478             dfs_parent[cell].c = c;
479             dfs_depth[cell] = mydepth + 1;
480             child_lowpoint = dfs_biconnect_visit(rr, cc, state, dfs_parent,
481                                                  dfs_depth, buf);
482
483             if (child_lowpoint >= mydepth && mydepth > 0)
484                 solver_makemove(r, c, M_WHITE, state, buf);
485
486             lowpoint = min(lowpoint, child_lowpoint);
487             ++nchildren;
488         } else if (rr != dfs_parent[i].r || cc != dfs_parent[i].c) {
489             lowpoint = min(lowpoint, dfs_depth[cell]);
490         }
491     }
492
493     if (mydepth == 0 && nchildren >= 2)
494         solver_makemove(r, c, M_WHITE, state, buf);
495
496     return lowpoint;
497 }
498
499 static move *solver_reasoning_not_too_big(game_state *state,
500                                           int nclues,
501                                           const square *clues,
502                                           move *buf)
503 {
504     int const w = state->params.w, runmasks[4] = {
505         ~(MASK(BLACK) | MASK(EMPTY)),
506         MASK(EMPTY),
507         ~(MASK(BLACK) | MASK(EMPTY)),
508         ~(MASK(BLACK))
509     };
510     enum {RUN_WHITE, RUN_EMPTY, RUN_BEYOND, RUN_SPACE};
511
512     int i, runlengths[4][4];
513
514     for (i = 0; i < nclues; ++i) {
515         int j, k, whites, space;
516
517         const puzzle_size row = clues[i].r, col = clues[i].c;
518         int const clue = state->grid[idx(row, col, w)];
519
520         for (j = 0; j < 4; ++j) {
521             puzzle_size r = row + dr[j], c = col + dc[j];
522             runlengths[RUN_SPACE][j] = 0;
523             for (k = 0; k <= RUN_SPACE; ++k) {
524                 int l = runlength(r, c, dr[j], dc[j], state, runmasks[k]);
525                 if (k < RUN_SPACE) {
526                     runlengths[k][j] = l;
527                     r += dr[j] * l;
528                     c += dc[j] * l;
529                 }
530                 runlengths[RUN_SPACE][j] += l;
531             }
532         }
533
534         whites = 1;
535         for (j = 0; j < 4; ++j) whites += runlengths[RUN_WHITE][j];
536
537         for (j = 0; j < 4; ++j) {
538             int const delta = 1 + runlengths[RUN_WHITE][j];
539             const puzzle_size r = row + delta * dr[j];
540             const puzzle_size c = col + delta * dc[j];
541
542             if (whites == clue) {
543                 solver_makemove(r, c, M_BLACK, state, &buf);
544                 continue;
545             }
546
547             if (runlengths[RUN_EMPTY][j] == 1 &&
548                 whites
549                 + runlengths[RUN_EMPTY][j]
550                 + runlengths[RUN_BEYOND][j]
551                 > clue) {
552                 solver_makemove(r, c, M_BLACK, state, &buf);
553                 continue;
554             }
555
556             if (whites
557                 + runlengths[RUN_EMPTY][j]
558                 + runlengths[RUN_BEYOND][j]
559                 > clue) {
560                 runlengths[RUN_SPACE][j] =
561                     runlengths[RUN_WHITE][j] +
562                     runlengths[RUN_EMPTY][j] - 1;
563
564                 if (runlengths[RUN_EMPTY][j] == 1)
565                     solver_makemove(r, c, M_BLACK, state, &buf);
566             }
567         }
568
569         space = 1;
570         for (j = 0; j < 4; ++j) space += runlengths[RUN_SPACE][j];
571         for (j = 0; j < 4; ++j) {
572             puzzle_size r = row + dr[j], c = col + dc[j];
573
574             int k = space - runlengths[RUN_SPACE][j];
575             if (k >= clue) continue;
576
577             for (; k < clue; ++k, r += dr[j], c += dc[j])
578                 solver_makemove(r, c, M_WHITE, state, &buf);
579         }
580     }
581     return buf;
582 }
583
584 static move *solver_reasoning_recursion(game_state *state,
585                                         int nclues,
586                                         const square *clues,
587                                         move *buf)
588 {
589     int const w = state->params.w, n = w * state->params.h;
590     int cell, colour;
591
592     for (cell = 0; cell < n; ++cell) {
593         int const r = cell / w, c = cell % w;
594         int i;
595         game_state *newstate;
596         move *recursive_result;
597
598         if (state->grid[cell] != EMPTY) continue;
599
600         /* FIXME: add enum alias for smallest and largest (or N) */
601         for (colour = M_BLACK; colour <= M_WHITE; ++colour) {
602             newstate = dup_game(state);
603             newstate->grid[cell] = colour;
604             recursive_result = do_solve(newstate, nclues, clues, buf,
605                                         DIFF_RECURSION);
606             free_game(newstate);
607             if (recursive_result == NULL) {
608                 solver_makemove(r, c, M_BLACK + M_WHITE - colour, state, &buf);
609                 return buf;
610             }
611             for (i = 0; i < n && newstate->grid[i] != EMPTY; ++i);
612             if (i == n) return buf;
613         }
614     }
615     return buf;
616 }
617
618 static square *find_clues(const game_state *state, int *ret_nclues)
619 {
620     int r, c, i, nclues = 0;
621     square *ret = snewn(state->params.w * state->params.h, struct square);
622
623     for (i = r = 0; r < state->params.h; ++r)
624         for (c = 0; c < state->params.w; ++c, ++i)
625             if (state->grid[i] > 0) {
626                 ret[nclues].r = r;
627                 ret[nclues].c = c;
628                 ++nclues;
629             }
630
631     *ret_nclues = nclues;
632     return sresize(ret, nclues + (nclues == 0), square);
633 }
634
635 /* ----------------------------------------------------------------------
636  * Puzzle generation
637  *
638  * Generating kurodoko instances is rather straightforward:
639  *
640  *  - Start with a white grid and add black squares at randomly chosen
641  *    locations, unless colouring that square black would violate
642  *    either the adjacency or connectedness constraints.
643  *
644  *  - For each white square, compute the number it would contain if it
645  *    were given as a clue.
646  *
647  *  - From a starting point of "give _every_ white square as a clue",
648  *    for each white square (in a random order), see if the board is
649  *    solvable when that square is not given as a clue.  If not, don't
650  *    give it as a clue, otherwise do.
651  *
652  * This never fails, but it's only _almost_ what I do.  The real final
653  * step is this:
654  *
655  *  - From a starting point of "give _every_ white square as a clue",
656  *    first remove all clues that are two-way rotationally symmetric
657  *    to a black square.  If this leaves the puzzle unsolvable, throw
658  *    it out and try again.  Otherwise, remove all _pairs_ of clues
659  *    (that are rotationally symmetric) which can be removed without
660  *    rendering the puzzle unsolvable.
661  *
662  * This can fail even if one only removes the black and symmetric
663  * clues; indeed it happens often (avg. once or twice per puzzle) when
664  * generating 1xN instances.  (If you add black cells they must be in
665  * the end, and if you only add one, it's ambiguous where).
666  */
667
668 /* forward declarations of internal calls */
669 static void newdesc_choose_black_squares(game_state *state,
670                                          const int *shuffle_1toN);
671 static void newdesc_compute_clues(game_state *state);
672 static int newdesc_strip_clues(game_state *state, int *shuffle_1toN);
673 static char *newdesc_encode_game_description(int n, puzzle_size *grid);
674
675 static char *new_game_desc(const game_params *params, random_state *rs,
676                            char **aux, int interactive)
677 {
678     int const w = params->w, h = params->h, n = w * h;
679
680     puzzle_size *const grid = snewn(n, puzzle_size);
681     int *const shuffle_1toN = snewn(n, int);
682
683     int i, clues_removed;
684
685     char *encoding;
686
687     game_state state;
688     state.params = *params;
689     state.grid = grid;
690
691     interactive = 0; /* I don't need it, I shouldn't use it*/
692
693     for (i = 0; i < n; ++i) shuffle_1toN[i] = i;
694
695     while (TRUE) {
696         shuffle(shuffle_1toN, n, sizeof (int), rs);
697         newdesc_choose_black_squares(&state, shuffle_1toN);
698
699         newdesc_compute_clues(&state);
700
701         shuffle(shuffle_1toN, n, sizeof (int), rs);
702         clues_removed = newdesc_strip_clues(&state, shuffle_1toN);
703
704         if (clues_removed < 0) continue; else break;
705     }
706
707     encoding = newdesc_encode_game_description(n, grid);
708
709     sfree(grid);
710     sfree(shuffle_1toN);
711
712     return encoding;
713 }
714
715 static int dfs_count_white(game_state *state, int cell);
716
717 static void newdesc_choose_black_squares(game_state *state,
718                                          const int *shuffle_1toN)
719 {
720     int const w = state->params.w, h = state->params.h, n = w * h;
721
722     int k, any_white_cell, n_black_cells;
723
724     for (k = 0; k < n; ++k) state->grid[k] = WHITE;
725
726     any_white_cell = shuffle_1toN[n - 1];
727     n_black_cells = 0;
728
729     /* I like the puzzles that result from n / 3, but maybe this
730      * could be made a (generation, i.e. non-full) parameter? */
731     for (k = 0; k < n / 3; ++k) {
732         int const i = shuffle_1toN[k], c = i % w, r = i / w;
733
734         int j;
735         for (j = 0; j < 4; ++j) {
736             int const rr = r + dr[j], cc = c + dc[j], cell = idx(rr, cc, w);
737             /* if you're out of bounds, we skip you */
738             if (out_of_bounds(rr, cc, w, h)) continue;
739             if (state->grid[cell] == BLACK) break; /* I can't be black */
740         } if (j < 4) continue; /* I have black neighbour: I'm white */
741
742         state->grid[i] = BLACK;
743         ++n_black_cells;
744
745         j = dfs_count_white(state, any_white_cell);
746         if (j + n_black_cells < n) {
747             state->grid[i] = WHITE;
748             --n_black_cells;
749         }
750     }
751 }
752
753 static void newdesc_compute_clues(game_state *state)
754 {
755     int const w = state->params.w, h = state->params.h;
756     int r, c;
757
758     for (r = 0; r < h; ++r) {
759         int run_size = 0, c, cc;
760         for (c = 0; c <= w; ++c) {
761             if (c == w || state->grid[idx(r, c, w)] == BLACK) {
762                 for (cc = c - run_size; cc < c; ++cc)
763                     state->grid[idx(r, cc, w)] += run_size;
764                 run_size = 0;
765             } else ++run_size;
766         }
767     }
768
769     for (c = 0; c < w; ++c) {
770         int run_size = 0, r, rr;
771         for (r = 0; r <= h; ++r) {
772             if (r == h || state->grid[idx(r, c, w)] == BLACK) {
773                 for (rr = r - run_size; rr < r; ++rr)
774                     state->grid[idx(rr, c, w)] += run_size;
775                 run_size = 0;
776             } else ++run_size;
777         }
778     }
779 }
780
781 #define rotate(x) (n - 1 - (x))
782
783 static int newdesc_strip_clues(game_state *state, int *shuffle_1toN)
784 {
785     int const w = state->params.w, n = w * state->params.h;
786
787     move *const move_buffer = snewn(n, move);
788     move *buf;
789     game_state *dupstate;
790
791     /*
792      * do a partition/pivot of shuffle_1toN into three groups:
793      * (1) squares rotationally-symmetric to (3)
794      * (2) squares not in (1) or (3)
795      * (3) black squares
796      *
797      * They go from [0, left), [left, right) and [right, n) in
798      * shuffle_1toN (and from there into state->grid[ ])
799      *
800      * Then, remove clues from the grid one by one in shuffle_1toN
801      * order, until the solver becomes unhappy.  If we didn't remove
802      * all of (1), return (-1).  Else, we're happy.
803      */
804
805     /* do the partition */
806     int clues_removed, k = 0, left = 0, right = n;
807
808     for (;; ++k) {
809         while (k < right && state->grid[shuffle_1toN[k]] == BLACK) {
810             --right;
811             SWAP(int, shuffle_1toN[right], shuffle_1toN[k]);
812             assert(state->grid[shuffle_1toN[right]] == BLACK);
813         }
814         if (k >= right) break;
815         assert (k >= left);
816         if (state->grid[rotate(shuffle_1toN[k])] == BLACK) {
817             SWAP(int, shuffle_1toN[k], shuffle_1toN[left]);
818             ++left;
819         }
820         assert (state->grid[rotate(shuffle_1toN[k])] != BLACK
821                 || k == left - 1);
822     }
823
824     for (k = 0; k < left; ++k) {
825         assert (state->grid[rotate(shuffle_1toN[k])] == BLACK);
826         state->grid[shuffle_1toN[k]] = EMPTY;
827     }
828     for (k = left; k < right; ++k) {
829         assert (state->grid[rotate(shuffle_1toN[k])] != BLACK);
830         assert (state->grid[shuffle_1toN[k]] != BLACK);
831     }
832     for (k = right; k < n; ++k) {
833         assert (state->grid[shuffle_1toN[k]] == BLACK);
834         state->grid[shuffle_1toN[k]] = EMPTY;
835     }
836
837     clues_removed = (left - 0) + (n - right);
838
839     dupstate = dup_game(state);
840     buf = solve_internal(dupstate, move_buffer, DIFF_RECURSION - 1);
841     free_game(dupstate);
842     if (buf - move_buffer < clues_removed) {
843         /* branch prediction: I don't think I'll go here */
844         clues_removed = -1;
845         goto ret;
846     }
847
848     for (k = left; k < right; ++k) {
849         const int i = shuffle_1toN[k], j = rotate(i);
850         int const clue = state->grid[i], clue_rot = state->grid[j];
851         if (clue == BLACK) continue;
852         state->grid[i] = state->grid[j] = EMPTY;
853         dupstate = dup_game(state);
854         buf = solve_internal(dupstate, move_buffer, DIFF_RECURSION - 1);
855         free_game(dupstate);
856         clues_removed += 2 - (i == j);
857         /* if i is the center square, then i == (j = rotate(i))
858          * when i and j are one, removing i and j removes only one */
859         if (buf - move_buffer == clues_removed) continue;
860         /* if the solver is sound, refilling all removed clues means
861          * we have filled all squares, i.e. solved the puzzle. */
862         state->grid[i] = clue;
863         state->grid[j] = clue_rot;
864         clues_removed -= 2 - (i == j);
865     }
866     
867 ret:
868     sfree(move_buffer);
869     return clues_removed;
870 }
871
872 static int dfs_count_rec(puzzle_size *grid, int r, int c, int w, int h)
873 {
874     int const cell = idx(r, c, w);
875     if (out_of_bounds(r, c, w, h)) return 0;
876     if (grid[cell] != WHITE) return 0;
877     grid[cell] = EMPTY;
878     return 1 +
879         dfs_count_rec(grid, r + 0, c + 1, w, h) +
880         dfs_count_rec(grid, r + 0, c - 1, w, h) +
881         dfs_count_rec(grid, r + 1, c + 0, w, h) +
882         dfs_count_rec(grid, r - 1, c + 0, w, h);
883 }
884
885 static int dfs_count_white(game_state *state, int cell)
886 {
887     int const w = state->params.w, h = state->params.h, n = w * h;
888     int const r = cell / w, c = cell % w;
889     int i, k = dfs_count_rec(state->grid, r, c, w, h);
890     for (i = 0; i < n; ++i)
891         if (state->grid[i] == EMPTY)
892             state->grid[i] = WHITE;
893     return k;
894 }
895
896 static char *validate_params(const game_params *params, int full)
897 {
898     int const w = params->w, h = params->h;
899     if (w < 1) return "Error: width is less than 1";
900     if (h < 1) return "Error: height is less than 1";
901     if (w * h < 1) return "Error: size is less than 1";
902     if (w + h - 1 > SCHAR_MAX) return "Error: w + h is too big";
903     /* I might be unable to store clues in my puzzle_size *grid; */
904     if (full) {
905         if (w == 2 && h == 2) return "Error: can't create 2x2 puzzles";
906         if (w == 1 && h == 2) return "Error: can't create 1x2 puzzles";
907         if (w == 2 && h == 1) return "Error: can't create 2x1 puzzles";
908         if (w == 1 && h == 1) return "Error: can't create 1x1 puzzles";
909     }
910     return NULL;
911 }
912
913 /* Definition: a puzzle instance is _good_ if:
914  *  - it has a unique solution
915  *  - the solver can find this solution without using recursion
916  *  - the solution contains at least one black square
917  *  - the clues are 2-way rotationally symmetric
918  *
919  * (the idea being: the generator can not output any _bad_ puzzles)
920  *
921  * Theorem: validate_params, when full != 0, discards exactly the set
922  * of parameters for which there are _no_ good puzzle instances.
923  *
924  * Proof: it's an immediate consequence of the five lemmas below.
925  *
926  * Observation: not only do puzzles on non-tiny grids exist, the
927  * generator is pretty fast about coming up with them.  On my pre-2004
928  * desktop box, it generates 100 puzzles on the highest preset (16x11)
929  * in 8.383 seconds, or <= 0.1 second per puzzle.
930  *
931  * ----------------------------------------------------------------------
932  *
933  * Lemma: On a 1x1 grid, there are no good puzzles.
934  *
935  * Proof: the one square can't be a clue because at least one square
936  * is black.  But both a white square and a black square satisfy the
937  * solution criteria, so the puzzle is ambiguous (and hence bad).
938  *
939  * Lemma: On a 1x2 grid, there are no good puzzles.
940  *
941  * Proof: let's name the squares l and r.  Note that there can be at
942  * most one black square, or adjacency is violated.  By assumption at
943  * least one square is black, so let's call that one l.  By clue
944  * symmetry, neither l nor r can be given as a clue, so the puzzle
945  * instance is blank and thus ambiguous.
946  *
947  * Corollary: On a 2x1 grid, there are no good puzzles.
948  * Proof: rotate the above proof 90 degrees ;-)
949  *
950  * ----------------------------------------------------------------------
951  *
952  * Lemma: On a 2x2 grid, there are no soluble puzzles with 2-way
953  * rotational symmetric clues and at least one black square.
954  *
955  * Proof: Let's name the squares a, b, c, and d, with a and b on the
956  * top row, a and c in the left column.  Let's consider the case where
957  * a is black.  Then no other square can be black: b and c would both
958  * violate the adjacency constraint; d would disconnect b from c.
959  *
960  * So exactly one square is black (and by 4-way rotation symmetry of
961  * the 2x2 square, it doesn't matter which one, so let's stick to a).
962  * By 2-way rotational symmetry of the clues and the rule about not
963  * painting numbers black, neither a nor d can be clues.  A blank
964  * puzzle would be ambiguous, so one of {b, c} is a clue; by symmetry,
965  * so is the other one.
966  *
967  * It is readily seen that their clue value is 2.  But "a is black"
968  * and "d is black" are both valid solutions in this case, so the
969  * puzzle is ambiguous (and hence bad).
970  *
971  * ----------------------------------------------------------------------
972  *
973  * Lemma: On a wxh grid with w, h >= 1 and (w > 2 or h > 2), there is
974  * at least one good puzzle.
975  *
976  * Proof: assume that w > h (otherwise rotate the proof again).  Paint
977  * the top left and bottom right corners black, and fill a clue into
978  * all the other squares.  Present this board to the solver code (or
979  * player, hypothetically), except with the two black squares as blank
980  * squares.
981  *
982  * For an Nx1 puzzle, observe that every clue is N - 2, and there are
983  * N - 2 of them in one connected sequence, so the remaining two
984  * squares can be deduced to be black, which solves the puzzle.
985  *
986  * For any other puzzle, let j be a cell in the same row as a black
987  * cell, but not in the same column (such a cell doesn't exist in 2x3
988  * puzzles, but we assume w > h and such cells exist in 3x2 puzzles).
989  *
990  * Note that the number of cells in axis parallel `rays' going out
991  * from j exceeds j's clue value by one.  Only one such cell is a
992  * non-clue, so it must be black.  Similarly for the other corner (let
993  * j' be a cell in the same row as the _other_ black cell, but not in
994  * the same column as _any_ black cell; repeat this argument at j').
995  *
996  * This fills the grid and satisfies all clues and the adjacency
997  * constraint and doesn't paint on top of any clues.  All that is left
998  * to see is connectedness.
999  *
1000  * Observe that the white cells in each column form a single connected
1001  * `run', and each column contains a white cell adjacent to a white
1002  * cell in the column to the right, if that column exists.
1003  *
1004  * Thus, any cell in the left-most column can reach any other cell:
1005  * first go to the target column (by repeatedly going to the cell in
1006  * your current column that lets you go right, then going right), then
1007  * go up or down to the desired cell.
1008  *
1009  * As reachability is symmetric (in undirected graphs) and transitive,
1010  * any cell can reach any left-column cell, and from there any other
1011  * cell.
1012  */
1013
1014 /* ----------------------------------------------------------------------
1015  * Game encoding and decoding
1016  */
1017
1018 #define NDIGITS_BASE '!'
1019
1020 static char *newdesc_encode_game_description(int area, puzzle_size *grid)
1021 {
1022     char *desc = NULL;
1023     int desclen = 0, descsize = 0;
1024     int run, i;
1025
1026     run = 0;
1027     for (i = 0; i <= area; i++) {
1028         int n = (i < area ? grid[i] : -1);
1029
1030         if (!n)
1031             run++;
1032         else {
1033             if (descsize < desclen + 40) {
1034                 descsize = desclen * 3 / 2 + 40;
1035                 desc = sresize(desc, descsize, char);
1036             }
1037             if (run) {
1038                 while (run > 0) {
1039                     int c = 'a' - 1 + run;
1040                     if (run > 26)
1041                         c = 'z';
1042                     desc[desclen++] = c;
1043                     run -= c - ('a' - 1);
1044                 }
1045             } else {
1046                 /*
1047                  * If there's a number in the very top left or
1048                  * bottom right, there's no point putting an
1049                  * unnecessary _ before or after it.
1050                  */
1051                 if (desclen > 0 && n > 0)
1052                     desc[desclen++] = '_';
1053             }
1054             if (n > 0)
1055                 desclen += sprintf(desc+desclen, "%d", n);
1056             run = 0;
1057         }
1058     }
1059     desc[desclen] = '\0';
1060     return desc;
1061 }
1062
1063 static char *validate_desc(const game_params *params, const char *desc)
1064 {
1065     int const n = params->w * params->h;
1066     int squares = 0;
1067     int range = params->w + params->h - 1;   /* maximum cell value */
1068
1069     while (*desc && *desc != ',') {
1070         int c = *desc++;
1071         if (c >= 'a' && c <= 'z') {
1072             squares += c - 'a' + 1;
1073         } else if (c == '_') {
1074             /* do nothing */;
1075         } else if (c > '0' && c <= '9') {
1076             int val = atoi(desc-1);
1077             if (val < 1 || val > range)
1078                 return "Out-of-range number in game description";
1079             squares++;
1080             while (*desc >= '0' && *desc <= '9')
1081                 desc++;
1082         } else
1083             return "Invalid character in game description";
1084     }
1085
1086     if (squares < n)
1087         return "Not enough data to fill grid";
1088
1089     if (squares > n)
1090         return "Too much data to fit in grid";
1091
1092     return NULL;
1093 }
1094
1095 static game_state *new_game(midend *me, const game_params *params,
1096                             const char *desc)
1097 {
1098     int i;
1099     const char *p;
1100
1101     int const n = params->w * params->h;
1102     game_state *state = snew(game_state);
1103
1104     me = NULL; /* I don't need it, I shouldn't use it */
1105
1106     state->params = *params; /* structure copy */
1107     state->grid = snewn(n, puzzle_size);
1108
1109     p = desc;
1110     i = 0;
1111     while (i < n && *p) {
1112         int c = *p++;
1113         if (c >= 'a' && c <= 'z') {
1114             int squares = c - 'a' + 1;
1115             while (squares--)
1116                 state->grid[i++] = 0;
1117         } else if (c == '_') {
1118             /* do nothing */;
1119         } else if (c > '0' && c <= '9') {
1120             int val = atoi(p-1);
1121             assert(val >= 1 && val <= params->w+params->h-1);
1122             state->grid[i++] = val;
1123             while (*p >= '0' && *p <= '9')
1124                 p++;
1125         }
1126     }
1127     assert(i == n);
1128     state->has_cheated = FALSE;
1129     state->was_solved = FALSE;
1130
1131     return state;
1132 }
1133
1134 /* ----------------------------------------------------------------------
1135  * User interface: ascii
1136  */
1137
1138 static int game_can_format_as_text_now(const game_params *params)
1139 {
1140     return TRUE;
1141 }
1142
1143 static char *game_text_format(const game_state *state)
1144 {
1145     int cellsize, r, c, i, w_string, h_string, n_string;
1146     char *ret, *buf, *gridline;
1147
1148     int const w = state->params.w, h = state->params.h;
1149
1150     cellsize = 0; /* or may be used uninitialized */
1151
1152     for (c = 0; c < w; ++c) {
1153         for (r = 1; r < h; ++r) {
1154             puzzle_size k = state->grid[idx(r, c, w)];
1155             int d;
1156             for (d = 0; k; k /= 10, ++d);
1157             cellsize = max(cellsize, d);
1158         }
1159     }
1160
1161     ++cellsize;
1162
1163     w_string = w * cellsize + 2; /* "|%d|%d|...|\n" */
1164     h_string = 2 * h + 1; /* "+--+--+...+\n%s\n+--+--+...+\n" */
1165     n_string = w_string * h_string;
1166
1167     gridline = snewn(w_string + 1, char); /* +1: NUL terminator */
1168     memset(gridline, '-', w_string);
1169     for (c = 0; c <= w; ++c) gridline[c * cellsize] = '+';
1170     gridline[w_string - 1] = '\n';
1171     gridline[w_string - 0] = '\0';
1172
1173     buf = ret = snewn(n_string + 1, char); /* +1: NUL terminator */
1174     for (i = r = 0; r < h; ++r) {
1175         memcpy(buf, gridline, w_string);
1176         buf += w_string;
1177         for (c = 0; c < w; ++c, ++i) {
1178             char ch;
1179             switch (state->grid[i]) {
1180               case BLACK: ch = '#'; break;
1181               case WHITE: ch = '.'; break;
1182               case EMPTY: ch = ' '; break;
1183               default:
1184                 buf += sprintf(buf, "|%*d", cellsize - 1, state->grid[i]);
1185                 continue;
1186             }
1187             *buf++ = '|';
1188             memset(buf, ch, cellsize - 1);
1189             buf += cellsize - 1;
1190         }
1191         buf += sprintf(buf, "|\n");
1192     }
1193     memcpy(buf, gridline, w_string);
1194     buf += w_string;
1195     assert (buf - ret == n_string);
1196     *buf = '\0';
1197
1198     sfree(gridline);
1199
1200     return ret;
1201 }
1202
1203 /* ----------------------------------------------------------------------
1204  * User interfaces: interactive
1205  */
1206
1207 struct game_ui {
1208     puzzle_size r, c; /* cursor position */
1209     unsigned int cursor_show: 1;
1210 };
1211
1212 static game_ui *new_ui(const game_state *state)
1213 {
1214     struct game_ui *ui = snew(game_ui);
1215     ui->r = ui->c = 0;
1216     ui->cursor_show = FALSE;
1217     return ui;
1218 }
1219
1220 static void free_ui(game_ui *ui)
1221 {
1222     sfree(ui);
1223 }
1224
1225 static char *encode_ui(const game_ui *ui)
1226 {
1227     return NULL;
1228 }
1229
1230 static void decode_ui(game_ui *ui, const char *encoding)
1231 {
1232 }
1233
1234 typedef struct drawcell {
1235     puzzle_size value;
1236     unsigned int error: 1;
1237     unsigned int cursor: 1;
1238     unsigned int flash: 1;
1239 } drawcell;
1240
1241 struct game_drawstate {
1242     int tilesize;
1243     drawcell *grid;
1244     unsigned int started: 1;
1245 };
1246
1247 #define TILESIZE (ds->tilesize)
1248 #define BORDER (TILESIZE / 2)
1249 #define COORD(x) ((x) * TILESIZE + BORDER)
1250 #define FROMCOORD(x) (((x) - BORDER) / TILESIZE)
1251
1252 static char *interpret_move(const game_state *state, game_ui *ui,
1253                             const game_drawstate *ds,
1254                             int x, int y, int button)
1255 {
1256     enum {none, forwards, backwards, hint};
1257     int const w = state->params.w, h = state->params.h;
1258     int r = ui->r, c = ui->c, action = none, cell;
1259
1260     if (IS_CURSOR_SELECT(button) && !ui->cursor_show) return NULL;
1261
1262     if (IS_MOUSE_DOWN(button)) {
1263         r = FROMCOORD(y + TILESIZE) - 1; /* or (x, y) < TILESIZE) */
1264         c = FROMCOORD(x + TILESIZE) - 1; /* are considered inside */
1265         if (out_of_bounds(r, c, w, h)) return NULL;
1266         ui->r = r;
1267         ui->c = c;
1268         ui->cursor_show = FALSE;
1269     }
1270
1271     if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
1272         /*
1273          * Utterly awful hack, exactly analogous to the one in Slant,
1274          * to configure the left and right mouse buttons the opposite
1275          * way round.
1276          *
1277          * The original puzzle submitter thought it would be more
1278          * useful to have the left button turn an empty square into a
1279          * dotted one, on the grounds that that was what you did most
1280          * often; I (SGT) felt instinctively that the left button
1281          * ought to place black squares and the right button place
1282          * dots, on the grounds that that was consistent with many
1283          * other puzzles in which the left button fills in the data
1284          * used by the solution checker while the right button places
1285          * pencil marks for the user's convenience.
1286          *
1287          * My first beta-player wasn't sure either, so I thought I'd
1288          * pre-emptively put in a 'configuration' mechanism just in
1289          * case.
1290          */
1291         {
1292             static int swap_buttons = -1;
1293             if (swap_buttons < 0) {
1294                 char *env = getenv("RANGE_SWAP_BUTTONS");
1295                 swap_buttons = (env && (env[0] == 'y' || env[0] == 'Y'));
1296             }
1297             if (swap_buttons) {
1298                 if (button == LEFT_BUTTON)
1299                     button = RIGHT_BUTTON;
1300                 else
1301                     button = LEFT_BUTTON;
1302             }
1303         }
1304     }
1305
1306     switch (button) {
1307       case CURSOR_SELECT : case   LEFT_BUTTON: action = backwards; break;
1308       case CURSOR_SELECT2: case  RIGHT_BUTTON: action =  forwards; break;
1309       case 'h': case 'H' :                     action =      hint; break;
1310       case CURSOR_UP: case CURSOR_DOWN:
1311       case CURSOR_LEFT: case CURSOR_RIGHT:
1312         if (ui->cursor_show) {
1313             int i;
1314             for (i = 0; i < 4 && cursors[i] != button; ++i);
1315             assert (i < 4);
1316             if (!out_of_bounds(ui->r + dr[i], ui->c + dc[i], w, h)) {
1317                 ui->r += dr[i];
1318                 ui->c += dc[i];
1319             }
1320         } else ui->cursor_show = TRUE;
1321         return "";
1322     }
1323
1324     if (action == hint) {
1325         move *end, *buf = snewn(state->params.w * state->params.h,
1326                                 struct move);
1327         char *ret = NULL;
1328         end = solve_internal(state, buf, DIFF_RECURSION);
1329         if (end != NULL && end > buf) {
1330             ret = nfmtstr(40, "%c,%d,%d",
1331                           buf->colour == M_BLACK ? 'B' : 'W',
1332                           buf->square.r, buf->square.c);
1333             /* We used to set a flag here in the game_ui indicating
1334              * that the player had used the hint function. I (SGT)
1335              * retired it, on grounds of consistency with other games
1336              * (most of these games will still flash to indicate
1337              * completion if you solved and undid it, so why not if
1338              * you got a hint?) and because the flash is as much about
1339              * checking you got it all right than about congratulating
1340              * you on a job well done. */
1341         }
1342         sfree(buf);
1343         return ret;
1344     }
1345
1346     cell = state->grid[idx(r, c, state->params.w)];
1347     if (cell > 0) return NULL;
1348
1349     if (action == forwards) switch (cell) {
1350       case EMPTY: return nfmtstr(40, "W,%d,%d", r, c);
1351       case WHITE: return nfmtstr(40, "B,%d,%d", r, c);
1352       case BLACK: return nfmtstr(40, "E,%d,%d", r, c);
1353     }
1354
1355     else if (action == backwards) switch (cell) {
1356       case BLACK: return nfmtstr(40, "W,%d,%d", r, c);
1357       case WHITE: return nfmtstr(40, "E,%d,%d", r, c);
1358       case EMPTY: return nfmtstr(40, "B,%d,%d", r, c);
1359     }
1360
1361     return NULL;
1362 }
1363
1364 static int find_errors(const game_state *state, int *report)
1365 {
1366     int const w = state->params.w, h = state->params.h, n = w * h;
1367     int *dsf;
1368
1369     int r, c, i;
1370
1371     int nblack = 0, any_white_cell = -1;
1372     game_state *dup = dup_game(state);
1373
1374     for (i = r = 0; r < h; ++r)
1375         for (c = 0; c < w; ++c, ++i) {
1376             switch (state->grid[i]) {
1377
1378               case BLACK:
1379                 {
1380                     int j;
1381                     ++nblack;
1382                     for (j = 0; j < 4; ++j) {
1383                         int const rr = r + dr[j], cc = c + dc[j];
1384                         if (out_of_bounds(rr, cc, w, h)) continue;
1385                         if (state->grid[idx(rr, cc, w)] != BLACK) continue;
1386                         if (!report) goto found_error;
1387                         report[i] = TRUE;
1388                         break;
1389                     }
1390                 }
1391                 break;
1392               default:
1393                 {
1394                     int j, runs;
1395                     for (runs = 1, j = 0; j < 4; ++j) {
1396                         int const rr = r + dr[j], cc = c + dc[j];
1397                         runs += runlength(rr, cc, dr[j], dc[j], state,
1398                                           ~MASK(BLACK));
1399                     }
1400                     if (!report) {
1401                         if (runs != state->grid[i]) goto found_error;
1402                     } else if (runs < state->grid[i]) report[i] = TRUE;
1403                     else {
1404                         for (runs = 1, j = 0; j < 4; ++j) {
1405                             int const rr = r + dr[j], cc = c + dc[j];
1406                             runs += runlength(rr, cc, dr[j], dc[j], state,
1407                                               ~(MASK(BLACK) | MASK(EMPTY)));
1408                         }
1409                         if (runs > state->grid[i]) report[i] = TRUE;
1410                     }
1411                 }
1412
1413                 /* note: fallthrough _into_ these cases */
1414               case EMPTY:
1415               case WHITE: any_white_cell = i;
1416             }
1417         }
1418
1419     /*
1420      * Check that all the white cells form a single connected component.
1421      */
1422     dsf = snew_dsf(n);
1423     for (r = 0; r < h-1; ++r)
1424         for (c = 0; c < w; ++c)
1425             if (state->grid[r*w+c] != BLACK &&
1426                 state->grid[(r+1)*w+c] != BLACK)
1427                 dsf_merge(dsf, r*w+c, (r+1)*w+c);
1428     for (r = 0; r < h; ++r)
1429         for (c = 0; c < w-1; ++c)
1430             if (state->grid[r*w+c] != BLACK &&
1431                 state->grid[r*w+(c+1)] != BLACK)
1432                 dsf_merge(dsf, r*w+c, r*w+(c+1));
1433     if (nblack + dsf_size(dsf, any_white_cell) < n) {
1434         int biggest, canonical;
1435
1436         if (!report) {
1437             printf("dfs fail at %d\n", any_white_cell);
1438             goto found_error;
1439         }
1440
1441         /*
1442          * Report this error by choosing one component to be the
1443          * canonical one (we pick the largest, arbitrarily
1444          * tie-breaking towards lower array indices) and highlighting
1445          * as an error any square in a different component.
1446          */
1447         canonical = -1;
1448         biggest = 0;
1449         for (i = 0; i < n; ++i)
1450             if (state->grid[i] != BLACK) {
1451                 int size = dsf_size(dsf, i);
1452                 if (size > biggest) {
1453                     biggest = size;
1454                     canonical = dsf_canonify(dsf, i);
1455                 }
1456             }
1457
1458         for (i = 0; i < n; ++i)
1459             if (state->grid[i] != BLACK && dsf_canonify(dsf, i) != canonical)
1460                 report[i] = TRUE;
1461     }
1462     sfree(dsf);
1463
1464     free_game(dup);
1465     return FALSE; /* if report != NULL, this is ignored */
1466
1467 found_error:
1468     free_game(dup);
1469     return TRUE;
1470 }
1471
1472 static game_state *execute_move(const game_state *state, const char *move)
1473 {
1474     signed int r, c, value, nchars, ntok;
1475     signed char what_to_do;
1476     game_state *ret;
1477
1478     assert (move);
1479
1480     ret = dup_game(state);
1481
1482     if (*move == 'S') {
1483         ++move;
1484         ret->has_cheated = ret->was_solved = TRUE;
1485     }
1486
1487     for (; *move; move += nchars) {
1488         ntok = sscanf(move, "%c,%d,%d%n", &what_to_do, &r, &c, &nchars);
1489         if (ntok < 3) goto failure;
1490         switch (what_to_do) {
1491           case 'W': value = WHITE; break;
1492           case 'E': value = EMPTY; break;
1493           case 'B': value = BLACK; break;
1494           default: goto failure;
1495         }
1496         if (out_of_bounds(r, c, ret->params.w, ret->params.h)) goto failure;
1497         ret->grid[idx(r, c, ret->params.w)] = value;
1498     }
1499
1500     if (ret->was_solved == FALSE)
1501         ret->was_solved = !find_errors(ret, NULL);
1502
1503     return ret;
1504
1505 failure:
1506     free_game(ret);
1507     return NULL;
1508 }
1509
1510 static void game_changed_state(game_ui *ui, const game_state *oldstate,
1511                                const game_state *newstate)
1512 {
1513 }
1514
1515 static float game_anim_length(const game_state *oldstate,
1516                               const game_state *newstate, int dir, game_ui *ui)
1517 {
1518     return 0.0F;
1519 }
1520
1521 #define FLASH_TIME 0.7F
1522
1523 static float game_flash_length(const game_state *from,
1524                                const game_state *to, int dir, game_ui *ui)
1525 {
1526     if (!from->was_solved && to->was_solved && !to->has_cheated)
1527         return FLASH_TIME;
1528     return 0.0F;
1529 }
1530
1531 static int game_status(const game_state *state)
1532 {
1533     return state->was_solved ? +1 : 0;
1534 }
1535
1536 /* ----------------------------------------------------------------------
1537  * Drawing routines.
1538  */
1539
1540 #define PREFERRED_TILE_SIZE 32
1541
1542 enum {
1543     COL_BACKGROUND = 0,
1544     COL_GRID,
1545     COL_BLACK = COL_GRID,
1546     COL_TEXT = COL_GRID,
1547     COL_USER = COL_GRID,
1548     COL_ERROR,
1549     COL_LOWLIGHT,
1550     COL_HIGHLIGHT = COL_ERROR, /* mkhighlight needs it, I don't */
1551     COL_CURSOR = COL_LOWLIGHT,
1552     NCOLOURS
1553 };
1554
1555 static void game_compute_size(const game_params *params, int tilesize,
1556                               int *x, int *y)
1557 {
1558     *x = (1 + params->w) * tilesize;
1559     *y = (1 + params->h) * tilesize;
1560 }
1561
1562 static void game_set_size(drawing *dr, game_drawstate *ds,
1563                           const game_params *params, int tilesize)
1564 {
1565     ds->tilesize = tilesize;
1566 }
1567
1568 #define COLOUR(ret, i, r, g, b) \
1569    ((ret[3*(i)+0] = (r)), (ret[3*(i)+1] = (g)), (ret[3*(i)+2] = (b)))
1570
1571 static float *game_colours(frontend *fe, int *ncolours)
1572 {
1573     float *ret = snewn(3 * NCOLOURS, float);
1574
1575     game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT);
1576     COLOUR(ret, COL_GRID,  0.0F, 0.0F, 0.0F);
1577     COLOUR(ret, COL_ERROR, 1.0F, 0.0F, 0.0F);
1578
1579     *ncolours = NCOLOURS;
1580     return ret;
1581 }
1582
1583 static drawcell makecell(puzzle_size value, int error, int cursor, int flash)
1584 {
1585     drawcell ret;
1586     setmember(ret, value);
1587     setmember(ret, error);
1588     setmember(ret, cursor);
1589     setmember(ret, flash);
1590     return ret;
1591 }
1592
1593 static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1594 {
1595     int const w = state->params.w, h = state->params.h, n = w * h;
1596     struct game_drawstate *ds = snew(struct game_drawstate);
1597     int i;
1598
1599     ds->tilesize = 0;
1600     ds->started = FALSE;
1601
1602     ds->grid = snewn(n, drawcell);
1603     for (i = 0; i < n; ++i)
1604         ds->grid[i] = makecell(w + h, FALSE, FALSE, FALSE);
1605
1606     return ds;
1607 }
1608
1609 static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1610 {
1611     sfree(ds->grid);
1612     sfree(ds);
1613 }
1614
1615 #define cmpmember(a, b, field) ((a) . field == (b) . field)
1616
1617 static int cell_eq(drawcell a, drawcell b)
1618 {
1619     return
1620         cmpmember(a, b, value) &&
1621         cmpmember(a, b, error) &&
1622         cmpmember(a, b, cursor) &&
1623         cmpmember(a, b, flash);
1624 }
1625
1626 static void draw_cell(drawing *dr, game_drawstate *ds, int r, int c,
1627                       drawcell cell);
1628
1629 static void game_redraw(drawing *dr, game_drawstate *ds,
1630                         const game_state *oldstate, const game_state *state,
1631                         int dir, const game_ui *ui,
1632                         float animtime, float flashtime)
1633 {
1634     int const w = state->params.w, h = state->params.h, n = w * h;
1635     int const wpx = (w+1) * ds->tilesize, hpx = (h+1) * ds->tilesize;
1636     int const flash = ((int) (flashtime * 5 / FLASH_TIME)) % 2;
1637
1638     int r, c, i;
1639
1640     int *errors = snewn(n, int);
1641     memset(errors, FALSE, n * sizeof (int));
1642     find_errors(state, errors);
1643
1644     assert (oldstate == NULL); /* only happens if animating moves */
1645
1646     if (!ds->started) {
1647         ds->started = TRUE;
1648         draw_rect(dr, 0, 0, wpx, hpx, COL_BACKGROUND);
1649         draw_rect(dr, BORDER-1, BORDER-1,
1650                   ds->tilesize*w+2, ds->tilesize*h+2, COL_GRID);
1651         draw_update(dr, 0, 0, wpx, hpx);
1652     }
1653
1654     for (i = r = 0; r < h; ++r) {
1655         for (c = 0; c < w; ++c, ++i) {
1656             drawcell cell = makecell(state->grid[i], errors[i], FALSE, flash);
1657             if (r == ui->r && c == ui->c && ui->cursor_show)
1658                 cell.cursor = TRUE;
1659             if (!cell_eq(cell, ds->grid[i])) {
1660                 draw_cell(dr, ds, r, c, cell);
1661                 ds->grid[i] = cell;
1662             }
1663         }
1664     }
1665
1666     sfree(errors);
1667 }
1668
1669 static void draw_cell(drawing *draw, game_drawstate *ds, int r, int c,
1670                       drawcell cell)
1671 {
1672     int const ts = ds->tilesize;
1673     int const y = BORDER + ts * r, x = BORDER + ts * c;
1674     int const tx = x + (ts / 2), ty = y + (ts / 2);
1675     int const dotsz = (ds->tilesize + 9) / 10;
1676
1677     int const colour = (cell.value == BLACK ?
1678                         cell.error ? COL_ERROR : COL_BLACK :
1679                         cell.flash || cell.cursor ?
1680                         COL_LOWLIGHT : COL_BACKGROUND);
1681
1682     draw_rect        (draw, x, y, ts, ts, colour);
1683     draw_rect_outline(draw, x, y, ts, ts, COL_GRID);
1684
1685     switch (cell.value) {
1686       case WHITE: draw_rect(draw, tx - dotsz / 2, ty - dotsz / 2, dotsz, dotsz,
1687                             cell.error ? COL_ERROR : COL_USER);
1688       case BLACK: break;
1689       case EMPTY:
1690         if (cell.error)
1691             draw_circle(draw, tx, ty, dotsz / 2, COL_ERROR, COL_GRID);
1692         break;
1693       default:
1694         {
1695             int const colour = (cell.error ? COL_ERROR : COL_GRID);
1696             char *msg = nfmtstr(10, "%d", cell.value);
1697             draw_text(draw, tx, ty, FONT_VARIABLE, ts * 3 / 5,
1698                       ALIGN_VCENTRE | ALIGN_HCENTRE, colour, msg);
1699             sfree(msg);
1700         }
1701     }
1702
1703     draw_update(draw, x, y, ts, ts);
1704 }
1705
1706 static int game_timing_state(const game_state *state, game_ui *ui)
1707 {
1708     puts("warning: game_timing_state was called (this shouldn't happen)");
1709     return FALSE; /* the (non-existing) timer should not be running */
1710 }
1711
1712 /* ----------------------------------------------------------------------
1713  * User interface: print
1714  */
1715
1716 static void game_print_size(const game_params *params, float *x, float *y)
1717 {
1718     int print_width, print_height;
1719     game_compute_size(params, 800, &print_width, &print_height);
1720     *x = print_width  / 100.0F;
1721     *y = print_height / 100.0F;
1722 }
1723
1724 static void game_print(drawing *dr, const game_state *state, int tilesize)
1725 {
1726     int const w = state->params.w, h = state->params.h;
1727     game_drawstate ds_obj, *ds = &ds_obj;
1728     int r, c, i, colour;
1729
1730     ds->tilesize = tilesize;
1731
1732     colour = print_mono_colour(dr, 1); assert(colour == COL_BACKGROUND);
1733     colour = print_mono_colour(dr, 0); assert(colour == COL_GRID);
1734     colour = print_mono_colour(dr, 1); assert(colour == COL_ERROR);
1735     colour = print_mono_colour(dr, 0); assert(colour == COL_LOWLIGHT);
1736     colour = print_mono_colour(dr, 0); assert(colour == NCOLOURS);
1737
1738     for (i = r = 0; r < h; ++r)
1739         for (c = 0; c < w; ++c, ++i)
1740             draw_cell(dr, ds, r, c,
1741                       makecell(state->grid[i], FALSE, FALSE, FALSE));
1742
1743     print_line_width(dr, 3 * tilesize / 40);
1744     draw_rect_outline(dr, BORDER, BORDER, w*TILESIZE, h*TILESIZE, COL_GRID);
1745 }
1746
1747 /* And that's about it ;-) **************************************************/
1748
1749 #ifdef COMBINED
1750 #define thegame range
1751 #endif
1752
1753 struct game const thegame = {
1754     "Range", "games.range", "range",
1755     default_params,
1756     game_fetch_preset,
1757     decode_params,
1758     encode_params,
1759     free_params,
1760     dup_params,
1761     TRUE, game_configure, custom_params,
1762     validate_params,
1763     new_game_desc,
1764     validate_desc,
1765     new_game,
1766     dup_game,
1767     free_game,
1768     TRUE, solve_game,
1769     TRUE, game_can_format_as_text_now, game_text_format,
1770     new_ui,
1771     free_ui,
1772     encode_ui,
1773     decode_ui,
1774     game_changed_state,
1775     interpret_move,
1776     execute_move,
1777     PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
1778     game_colours,
1779     game_new_drawstate,
1780     game_free_drawstate,
1781     game_redraw,
1782     game_anim_length,
1783     game_flash_length,
1784     game_status,
1785     TRUE, FALSE, game_print_size, game_print,
1786     FALSE, /* wants_statusbar */
1787     FALSE, game_timing_state,
1788     0, /* flags */
1789 };