A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/*
2 * slant.c: Puzzle from nikoli.co.jp involving drawing a diagonal
3 * line through each square of a grid.
4 */
5
6/*
7 * In this puzzle you have a grid of squares, each of which must
8 * contain a diagonal line; you also have clue numbers placed at
9 * _points_ of that grid, which means there's a (w+1) x (h+1) array
10 * of possible clue positions.
11 *
12 * I'm therefore going to adopt a rigid convention throughout this
13 * source file of using w and h for the dimensions of the grid of
14 * squares, and W and H for the dimensions of the grid of points.
15 * Thus, W == w+1 and H == h+1 always.
16 *
17 * Clue arrays will be W*H `signed char's, and the clue at each
18 * point will be a number from 0 to 4, or -1 if there's no clue.
19 *
20 * Solution arrays will be W*H `signed char's, and the number at
21 * each point will be +1 for a forward slash (/), -1 for a
22 * backslash (\), and 0 for unknown.
23 */
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <stdarg.h>
28#include <string.h>
29#include <assert.h>
30#include <ctype.h>
31#ifdef NO_TGMATH_H
32# include <math.h>
33#else
34# include <tgmath.h>
35#endif
36
37#include "puzzles.h"
38
39enum {
40 COL_BACKGROUND,
41 COL_GRID,
42 COL_INK,
43 COL_SLANT1,
44 COL_SLANT2,
45 COL_ERROR,
46 COL_CURSOR,
47 COL_FILLEDSQUARE,
48 COL_GROUNDED,
49 NCOLOURS
50};
51
52enum {
53 PREF_MOUSE_BUTTON_ORDER,
54 PREF_FADE_GROUNDED,
55 N_PREF_ITEMS
56};
57
58/*
59 * In standalone solver mode, `verbose' is a variable which can be
60 * set by command-line option; in debugging mode it's simply always
61 * true.
62 */
63#if defined STANDALONE_SOLVER
64#define SOLVER_DIAGNOSTICS
65static bool verbose = false;
66#elif defined SOLVER_DIAGNOSTICS
67#define verbose true
68#endif
69
70/*
71 * Difficulty levels. I do some macro ickery here to ensure that my
72 * enum and the various forms of my name list always match up.
73 */
74#define DIFFLIST(A) \
75 A(EASY,Easy,e) \
76 A(HARD,Hard,h)
77#define ENUM(upper,title,lower) DIFF_ ## upper,
78#define TITLE(upper,title,lower) #title,
79#define ENCODE(upper,title,lower) #lower
80#define CONFIG(upper,title,lower) ":" #title
81enum { DIFFLIST(ENUM) DIFFCOUNT };
82static char const *const slant_diffnames[] = { DIFFLIST(TITLE) };
83static char const slant_diffchars[] = DIFFLIST(ENCODE);
84#define DIFFCONFIG DIFFLIST(CONFIG)
85
86struct game_params {
87 int w, h, diff;
88};
89
90typedef struct game_clues {
91 int w, h;
92 signed char *clues;
93 int *tmpdsf;
94 int refcount;
95} game_clues;
96
97#define ERR_VERTEX 1
98#define ERR_SQUARE 2
99#define BORDER_EDGE 4 /* kind of an abuse: not an error */
100
101struct game_state {
102 struct game_params p;
103 game_clues *clues;
104 signed char *soln;
105 unsigned char *errors;
106 bool completed;
107 bool used_solve; /* used to suppress completion flash */
108};
109
110static game_params *default_params(void)
111{
112 game_params *ret = snew(game_params);
113
114 ret->w = ret->h = 8;
115 ret->diff = DIFF_EASY;
116
117 return ret;
118}
119
120static const struct game_params slant_presets[] = {
121 {5, 5, DIFF_EASY},
122 {5, 5, DIFF_HARD},
123 {8, 8, DIFF_EASY},
124 {8, 8, DIFF_HARD},
125 {12, 10, DIFF_EASY},
126 {12, 10, DIFF_HARD},
127};
128
129static bool game_fetch_preset(int i, char **name, game_params **params)
130{
131 game_params *ret;
132 char str[80];
133
134 if (i < 0 || i >= lenof(slant_presets))
135 return false;
136
137 ret = snew(game_params);
138 *ret = slant_presets[i];
139
140 sprintf(str, "%dx%d %s", ret->w, ret->h, slant_diffnames[ret->diff]);
141
142 *name = dupstr(str);
143 *params = ret;
144 return true;
145}
146
147static void free_params(game_params *params)
148{
149 sfree(params);
150}
151
152static game_params *dup_params(const game_params *params)
153{
154 game_params *ret = snew(game_params);
155 *ret = *params; /* structure copy */
156 return ret;
157}
158
159static void decode_params(game_params *ret, char const *string)
160{
161 ret->w = ret->h = atoi(string);
162 while (*string && isdigit((unsigned char)*string)) string++;
163 if (*string == 'x') {
164 string++;
165 ret->h = atoi(string);
166 while (*string && isdigit((unsigned char)*string)) string++;
167 }
168 if (*string == 'd') {
169 int i;
170 string++;
171 for (i = 0; i < DIFFCOUNT; i++)
172 if (*string == slant_diffchars[i])
173 ret->diff = i;
174 if (*string) string++;
175 }
176}
177
178static char *encode_params(const game_params *params, bool full)
179{
180 char data[256];
181
182 sprintf(data, "%dx%d", params->w, params->h);
183 if (full)
184 sprintf(data + strlen(data), "d%c", slant_diffchars[params->diff]);
185
186 return dupstr(data);
187}
188
189static config_item *game_configure(const game_params *params)
190{
191 config_item *ret;
192 char buf[80];
193
194 ret = snewn(4, config_item);
195
196 ret[0].name = "Width";
197 ret[0].type = C_STRING;
198 sprintf(buf, "%d", params->w);
199 ret[0].u.string.sval = dupstr(buf);
200
201 ret[1].name = "Height";
202 ret[1].type = C_STRING;
203 sprintf(buf, "%d", params->h);
204 ret[1].u.string.sval = dupstr(buf);
205
206 ret[2].name = "Difficulty";
207 ret[2].type = C_CHOICES;
208 ret[2].u.choices.choicenames = DIFFCONFIG;
209 ret[2].u.choices.selected = params->diff;
210
211 ret[3].name = NULL;
212 ret[3].type = C_END;
213
214 return ret;
215}
216
217static game_params *custom_params(const config_item *cfg)
218{
219 game_params *ret = snew(game_params);
220
221 ret->w = atoi(cfg[0].u.string.sval);
222 ret->h = atoi(cfg[1].u.string.sval);
223 ret->diff = cfg[2].u.choices.selected;
224
225 return ret;
226}
227
228static const char *validate_params(const game_params *params, bool full)
229{
230 /*
231 * (At least at the time of writing this comment) The grid
232 * generator is actually capable of handling even zero grid
233 * dimensions without crashing. Puzzles with a zero-area grid
234 * are a bit boring, though, because they're already solved :-)
235 * And puzzles with a dimension of 1 can't be made Hard, which
236 * means the simplest thing is to forbid them altogether.
237 */
238
239 if (params->w < 2 || params->h < 2)
240 return "Width and height must both be at least two";
241 if (params->w > INT_MAX / params->h)
242 return "Width times height must not be unreasonably large";
243
244 return NULL;
245}
246
247/*
248 * Scratch space for solver.
249 */
250struct solver_scratch {
251 /*
252 * Disjoint set forest which tracks the connected sets of
253 * points.
254 */
255 DSF *connected;
256
257 /*
258 * Counts the number of possible exits from each connected set
259 * of points. (That is, the number of possible _simultaneous_
260 * exits: an unconnected point labelled 2 has an exit count of
261 * 2 even if all four possible edges are still under
262 * consideration.)
263 */
264 int *exits;
265
266 /*
267 * Tracks whether each connected set of points includes a
268 * border point.
269 */
270 bool *border;
271
272 /*
273 * Another disjoint set forest. This one tracks _squares_ which
274 * are known to slant in the same direction.
275 */
276 DSF *equiv;
277
278 /*
279 * Stores slash values which we know for an equivalence class.
280 * When we fill in a square, we set slashval[canonify(x)] to
281 * the same value as soln[x], so that we can then spot other
282 * squares equivalent to it and fill them in immediately via
283 * their known equivalence.
284 */
285 signed char *slashval;
286
287 /*
288 * Stores possible v-shapes. This array is w by h in size, but
289 * not every bit of every entry is meaningful. The bits mean:
290 *
291 * - bit 0 for a square means that that square and the one to
292 * its right might form a v-shape between them
293 * - bit 1 for a square means that that square and the one to
294 * its right might form a ^-shape between them
295 * - bit 2 for a square means that that square and the one
296 * below it might form a >-shape between them
297 * - bit 3 for a square means that that square and the one
298 * below it might form a <-shape between them
299 *
300 * Any starting 1 or 3 clue rules out four bits in this array
301 * immediately; a 2 clue propagates any ruled-out bit past it
302 * (if the two squares on one side of a 2 cannot be a v-shape,
303 * then neither can the two on the other side be the same
304 * v-shape); we can rule out further bits during play using
305 * partially filled 2 clues; whenever a pair of squares is
306 * known not to be _either_ kind of v-shape, we can mark them
307 * as equivalent.
308 */
309 unsigned char *vbitmap;
310
311 /*
312 * Useful to have this information automatically passed to
313 * solver subroutines. (This pointer is not dynamically
314 * allocated by new_scratch and free_scratch.)
315 */
316 const signed char *clues;
317};
318
319static struct solver_scratch *new_scratch(int w, int h)
320{
321 int W = w+1, H = h+1;
322 struct solver_scratch *ret = snew(struct solver_scratch);
323 ret->connected = dsf_new(W*H);
324 ret->exits = snewn(W*H, int);
325 ret->border = snewn(W*H, bool);
326 ret->equiv = dsf_new(w*h);
327 ret->slashval = snewn(w*h, signed char);
328 ret->vbitmap = snewn(w*h, unsigned char);
329 return ret;
330}
331
332static void free_scratch(struct solver_scratch *sc)
333{
334 sfree(sc->vbitmap);
335 sfree(sc->slashval);
336 dsf_free(sc->equiv);
337 sfree(sc->border);
338 sfree(sc->exits);
339 dsf_free(sc->connected);
340 sfree(sc);
341}
342
343/*
344 * Wrapper on dsf_merge() which updates the `exits' and `border'
345 * arrays.
346 */
347static void merge_vertices(DSF *connected,
348 struct solver_scratch *sc, int i, int j)
349{
350 int exits = -1;
351 bool border = false; /* initialise to placate optimiser */
352
353 if (sc) {
354 i = dsf_canonify(connected, i);
355 j = dsf_canonify(connected, j);
356
357 /*
358 * We have used one possible exit from each of the two
359 * classes. Thus, the viable exit count of the new class is
360 * the sum of the old exit counts minus two.
361 */
362 exits = sc->exits[i] + sc->exits[j] - 2;
363
364 border = sc->border[i] || sc->border[j];
365 }
366
367 dsf_merge(connected, i, j);
368
369 if (sc) {
370 i = dsf_canonify(connected, i);
371 sc->exits[i] = exits;
372 sc->border[i] = border;
373 }
374}
375
376/*
377 * Called when we have just blocked one way out of a particular
378 * point. If that point is a non-clue point (thus has a variable
379 * number of exits), we have therefore decreased its potential exit
380 * count, so we must decrement the exit count for the group as a
381 * whole.
382 */
383static void decr_exits(struct solver_scratch *sc, int i)
384{
385 if (sc->clues[i] < 0) {
386 i = dsf_canonify(sc->connected, i);
387 sc->exits[i]--;
388 }
389}
390
391static bool fill_square(int w, int h, int x, int y, int v,
392 signed char *soln,
393 DSF *connected, struct solver_scratch *sc)
394{
395 int W = w+1 /*, H = h+1 */;
396 int ci1, ci2; /* indices of the vertices of the square we're connecting */
397 int di1, di2; /* the other two vertices, which we're disconnecting */
398
399 assert(x >= 0 && x < w && y >= 0 && y < h);
400
401 if (soln[y*w+x] == v) {
402 return true; /* do nothing */
403 }
404
405#ifdef SOLVER_DIAGNOSTICS
406 if (verbose)
407 printf(" placing %c in %d,%d\n", v == -1 ? '\\' : '/', x, y);
408#endif
409
410 if (soln[y*w+x] != 0) {
411#ifdef SOLVER_DIAGNOSTICS
412 if (verbose)
413 printf(" but there's already a %c in it!\n",
414 soln[y*w+x] == -1 ? '\\' : '/');
415 return false;
416#endif
417 }
418
419 if (v < 0) {
420 ci1 = y*W+x;
421 ci2 = (y+1)*W+(x+1);
422 di1 = y*W+(x+1);
423 di2 = (y+1)*W+x;
424 } else {
425 ci1 = y*W+(x+1);
426 ci2 = (y+1)*W+x;
427 di1 = y*W+x;
428 di2 = (y+1)*W+(x+1);
429 }
430
431 if (dsf_equivalent(connected, ci1, ci2)) {
432#ifdef SOLVER_DIAGNOSTICS
433 if (verbose)
434 printf(" but it would make a loop!\n");
435 return false;
436#endif
437 }
438
439 soln[y*w+x] = v;
440
441 if (sc) {
442 int c = dsf_canonify(sc->equiv, y*w+x);
443 sc->slashval[c] = v;
444 }
445
446 merge_vertices(connected, sc, ci1, ci2);
447 if (sc) {
448 decr_exits(sc, di1);
449 decr_exits(sc, di2);
450 }
451 return true;
452}
453
454static bool vbitmap_clear(int w, int h, struct solver_scratch *sc,
455 int x, int y, int vbits, const char *reason, ...)
456{
457 bool done_something = false;
458 int vbit;
459
460 for (vbit = 1; vbit <= 8; vbit <<= 1)
461 if (vbits & sc->vbitmap[y*w+x] & vbit) {
462 done_something = true;
463#ifdef SOLVER_DIAGNOSTICS
464 if (verbose) {
465 va_list ap;
466
467 printf("ruling out %c shape at (%d,%d)-(%d,%d) (",
468 "!v^!>!!!<"[vbit], x, y,
469 x+((vbit&0x3)!=0), y+((vbit&0xC)!=0));
470
471 va_start(ap, reason);
472 vprintf(reason, ap);
473 va_end(ap);
474
475 printf(")\n");
476 }
477#endif
478 sc->vbitmap[y*w+x] &= ~vbit;
479 }
480
481 return done_something;
482}
483
484/*
485 * Solver. Returns 0 for impossibility, 1 for success, 2 for
486 * ambiguity or failure to converge.
487 */
488static int slant_solve(int w, int h, const signed char *clues,
489 signed char *soln, struct solver_scratch *sc,
490 int difficulty)
491{
492 int W = w+1, H = h+1;
493 int x, y, i, j;
494 bool done_something;
495
496 /*
497 * Clear the output.
498 */
499 memset(soln, 0, w*h);
500
501 sc->clues = clues;
502
503 /*
504 * Establish a disjoint set forest for tracking connectedness
505 * between grid points.
506 */
507 dsf_reinit(sc->connected);
508
509 /*
510 * Establish a disjoint set forest for tracking which squares
511 * are known to slant in the same direction.
512 */
513 dsf_reinit(sc->equiv);
514
515 /*
516 * Clear the slashval array.
517 */
518 memset(sc->slashval, 0, w*h);
519
520 /*
521 * Set up the vbitmap array. Initially all types of v are possible.
522 */
523 memset(sc->vbitmap, 0xF, w*h);
524
525 /*
526 * Initialise the `exits' and `border' arrays. These are used
527 * to do second-order loop avoidance: the dual of the no loops
528 * constraint is that every point must be somehow connected to
529 * the border of the grid (otherwise there would be a solid
530 * loop around it which prevented this).
531 *
532 * I define a `dead end' to be a connected group of points
533 * which contains no border point, and which can form at most
534 * one new connection outside itself. Then I forbid placing an
535 * edge so that it connects together two dead-end groups, since
536 * this would yield a non-border-connected isolated subgraph
537 * with no further scope to extend it.
538 */
539 for (y = 0; y < H; y++)
540 for (x = 0; x < W; x++) {
541 if (y == 0 || y == H-1 || x == 0 || x == W-1)
542 sc->border[y*W+x] = true;
543 else
544 sc->border[y*W+x] = false;
545
546 if (clues[y*W+x] < 0)
547 sc->exits[y*W+x] = 4;
548 else
549 sc->exits[y*W+x] = clues[y*W+x];
550 }
551
552 /*
553 * Repeatedly try to deduce something until we can't.
554 */
555 do {
556 done_something = false;
557
558 /*
559 * Any clue point with the number of remaining lines equal
560 * to zero or to the number of remaining undecided
561 * neighbouring squares can be filled in completely.
562 */
563 for (y = 0; y < H; y++)
564 for (x = 0; x < W; x++) {
565 struct {
566 int pos, slash;
567 } neighbours[4];
568 int nneighbours;
569 int nu, nl, c, s, eq, eq2, last, meq, mj1, mj2;
570
571 if ((c = clues[y*W+x]) < 0)
572 continue;
573
574 /*
575 * We have a clue point. Start by listing its
576 * neighbouring squares, in order around the point,
577 * together with the type of slash that would be
578 * required in that square to connect to the point.
579 */
580 nneighbours = 0;
581 if (x > 0 && y > 0) {
582 neighbours[nneighbours].pos = (y-1)*w+(x-1);
583 neighbours[nneighbours].slash = -1;
584 nneighbours++;
585 }
586 if (x > 0 && y < h) {
587 neighbours[nneighbours].pos = y*w+(x-1);
588 neighbours[nneighbours].slash = +1;
589 nneighbours++;
590 }
591 if (x < w && y < h) {
592 neighbours[nneighbours].pos = y*w+x;
593 neighbours[nneighbours].slash = -1;
594 nneighbours++;
595 }
596 if (x < w && y > 0) {
597 neighbours[nneighbours].pos = (y-1)*w+x;
598 neighbours[nneighbours].slash = +1;
599 nneighbours++;
600 }
601
602 /*
603 * Count up the number of undecided neighbours, and
604 * also the number of lines already present.
605 *
606 * If we're not on DIFF_EASY, then in this loop we
607 * also track whether we've seen two adjacent empty
608 * squares belonging to the same equivalence class
609 * (meaning they have the same type of slash). If
610 * so, we count them jointly as one line.
611 */
612 nu = 0;
613 nl = c;
614 last = neighbours[nneighbours-1].pos;
615 if (soln[last] == 0)
616 eq = dsf_canonify(sc->equiv, last);
617 else
618 eq = -1;
619 meq = mj1 = mj2 = -1;
620 for (i = 0; i < nneighbours; i++) {
621 j = neighbours[i].pos;
622 s = neighbours[i].slash;
623 if (soln[j] == 0) {
624 nu++; /* undecided */
625 if (meq < 0 && difficulty > DIFF_EASY) {
626 eq2 = dsf_canonify(sc->equiv, j);
627 if (eq == eq2 && last != j) {
628 /*
629 * We've found an equivalent pair.
630 * Mark it. This also inhibits any
631 * further equivalence tracking
632 * around this square, since we can
633 * only handle one pair (and in
634 * particular we want to avoid
635 * being misled by two overlapping
636 * equivalence pairs).
637 */
638 meq = eq;
639 mj1 = last;
640 mj2 = j;
641 nl--; /* count one line */
642 nu -= 2; /* and lose two undecideds */
643 } else
644 eq = eq2;
645 }
646 } else {
647 eq = -1;
648 if (soln[j] == s)
649 nl--; /* here's a line */
650 }
651 last = j;
652 }
653
654 /*
655 * Check the counts.
656 */
657 if (nl < 0 || nl > nu) {
658 /*
659 * No consistent value for this at all!
660 */
661#ifdef SOLVER_DIAGNOSTICS
662 if (verbose)
663 printf("need %d / %d lines around clue point at %d,%d!\n",
664 nl, nu, x, y);
665#endif
666 return 0; /* impossible */
667 }
668
669 if (nu > 0 && (nl == 0 || nl == nu)) {
670#ifdef SOLVER_DIAGNOSTICS
671 if (verbose) {
672 if (meq >= 0)
673 printf("partially (since %d,%d == %d,%d) ",
674 mj1%w, mj1/w, mj2%w, mj2/w);
675 printf("%s around clue point at %d,%d\n",
676 nl ? "filling" : "emptying", x, y);
677 }
678#endif
679 for (i = 0; i < nneighbours; i++) {
680 j = neighbours[i].pos;
681 s = neighbours[i].slash;
682 if (soln[j] == 0 && j != mj1 && j != mj2) {
683 if (!fill_square(w, h, j%w, j/w, (nl ? s : -s),
684 soln, sc->connected, sc))
685 return 0; /* impossible */
686 }
687 }
688
689 done_something = true;
690 } else if (nu == 2 && nl == 1 && difficulty > DIFF_EASY) {
691 /*
692 * If we have precisely two undecided squares
693 * and precisely one line to place between
694 * them, _and_ those squares are adjacent, then
695 * we can mark them as equivalent to one
696 * another.
697 *
698 * This even applies if meq >= 0: if we have a
699 * 2 clue point and two of its neighbours are
700 * already marked equivalent, we can indeed
701 * mark the other two as equivalent.
702 *
703 * We don't bother with this on DIFF_EASY,
704 * since we wouldn't have used the results
705 * anyway.
706 */
707 last = -1;
708 for (i = 0; i < nneighbours; i++) {
709 j = neighbours[i].pos;
710 if (soln[j] == 0 && j != mj1 && j != mj2) {
711 if (last < 0)
712 last = i;
713 else if (last == i-1 || (last == 0 && i == 3))
714 break; /* found a pair */
715 }
716 }
717 if (i < nneighbours) {
718 int sv1, sv2;
719
720 assert(last >= 0);
721 /*
722 * neighbours[last] and neighbours[i] are
723 * the pair. Mark them equivalent.
724 */
725#ifdef SOLVER_DIAGNOSTICS
726 if (verbose) {
727 if (meq >= 0)
728 printf("since %d,%d == %d,%d, ",
729 mj1%w, mj1/w, mj2%w, mj2/w);
730 }
731#endif
732 mj1 = neighbours[last].pos;
733 mj2 = neighbours[i].pos;
734#ifdef SOLVER_DIAGNOSTICS
735 if (verbose)
736 printf("clue point at %d,%d implies %d,%d == %d,"
737 "%d\n", x, y, mj1%w, mj1/w, mj2%w, mj2/w);
738#endif
739 mj1 = dsf_canonify(sc->equiv, mj1);
740 sv1 = sc->slashval[mj1];
741 mj2 = dsf_canonify(sc->equiv, mj2);
742 sv2 = sc->slashval[mj2];
743 if (sv1 != 0 && sv2 != 0 && sv1 != sv2) {
744#ifdef SOLVER_DIAGNOSTICS
745 if (verbose)
746 printf("merged two equivalence classes with"
747 " different slash values!\n");
748#endif
749 return 0;
750 }
751 sv1 = sv1 ? sv1 : sv2;
752 dsf_merge(sc->equiv, mj1, mj2);
753 mj1 = dsf_canonify(sc->equiv, mj1);
754 sc->slashval[mj1] = sv1;
755 }
756 }
757 }
758
759 if (done_something)
760 continue;
761
762 /*
763 * Failing that, we now apply the second condition, which
764 * is that no square may be filled in such a way as to form
765 * a loop. Also in this loop (since it's over squares
766 * rather than points), we check slashval to see if we've
767 * already filled in another square in the same equivalence
768 * class.
769 *
770 * The slashval check is disabled on DIFF_EASY, as is dead
771 * end avoidance. Only _immediate_ loop avoidance remains.
772 */
773 for (y = 0; y < h; y++)
774 for (x = 0; x < w; x++) {
775 bool fs, bs;
776 int v, c1, c2;
777#ifdef SOLVER_DIAGNOSTICS
778 const char *reason = "<internal error>";
779#endif
780
781 if (soln[y*w+x])
782 continue; /* got this one already */
783
784 fs = false;
785 bs = false;
786
787 if (difficulty > DIFF_EASY)
788 v = sc->slashval[dsf_canonify(sc->equiv, y*w+x)];
789 else
790 v = 0;
791
792 /*
793 * Try to rule out connectivity between (x,y) and
794 * (x+1,y+1); if successful, we will deduce that we
795 * must have a forward slash.
796 */
797 c1 = dsf_canonify(sc->connected, y*W+x);
798 c2 = dsf_canonify(sc->connected, (y+1)*W+(x+1));
799 if (c1 == c2) {
800 fs = true;
801#ifdef SOLVER_DIAGNOSTICS
802 reason = "simple loop avoidance";
803#endif
804 }
805 if (difficulty > DIFF_EASY &&
806 !sc->border[c1] && !sc->border[c2] &&
807 sc->exits[c1] <= 1 && sc->exits[c2] <= 1) {
808 fs = true;
809#ifdef SOLVER_DIAGNOSTICS
810 reason = "dead end avoidance";
811#endif
812 }
813 if (v == +1) {
814 fs = true;
815#ifdef SOLVER_DIAGNOSTICS
816 reason = "equivalence to an already filled square";
817#endif
818 }
819
820 /*
821 * Now do the same between (x+1,y) and (x,y+1), to
822 * see if we are required to have a backslash.
823 */
824 c1 = dsf_canonify(sc->connected, y*W+(x+1));
825 c2 = dsf_canonify(sc->connected, (y+1)*W+x);
826 if (c1 == c2) {
827 bs = true;
828#ifdef SOLVER_DIAGNOSTICS
829 reason = "simple loop avoidance";
830#endif
831 }
832 if (difficulty > DIFF_EASY &&
833 !sc->border[c1] && !sc->border[c2] &&
834 sc->exits[c1] <= 1 && sc->exits[c2] <= 1) {
835 bs = true;
836#ifdef SOLVER_DIAGNOSTICS
837 reason = "dead end avoidance";
838#endif
839 }
840 if (v == -1) {
841 bs = true;
842#ifdef SOLVER_DIAGNOSTICS
843 reason = "equivalence to an already filled square";
844#endif
845 }
846
847 if (fs && bs) {
848 /*
849 * No consistent value for this at all!
850 */
851#ifdef SOLVER_DIAGNOSTICS
852 if (verbose)
853 printf("%d,%d has no consistent slash!\n", x, y);
854#endif
855 return 0; /* impossible */
856 }
857
858 if (fs) {
859#ifdef SOLVER_DIAGNOSTICS
860 if (verbose)
861 printf("employing %s\n", reason);
862#endif
863 if (!fill_square(w, h, x, y, +1, soln, sc->connected, sc))
864 return 0; /* impossible */
865 done_something = true;
866 } else if (bs) {
867#ifdef SOLVER_DIAGNOSTICS
868 if (verbose)
869 printf("employing %s\n", reason);
870#endif
871 if (!fill_square(w, h, x, y, -1, soln, sc->connected, sc))
872 return 0; /* impossible */
873 done_something = true;
874 }
875 }
876
877 if (done_something)
878 continue;
879
880 /*
881 * Now see what we can do with the vbitmap array. All
882 * vbitmap deductions are disabled at Easy level.
883 */
884 if (difficulty <= DIFF_EASY)
885 continue;
886
887 for (y = 0; y < h; y++)
888 for (x = 0; x < w; x++) {
889 int s, c;
890
891 /*
892 * Any line already placed in a square must rule
893 * out any type of v which contradicts it.
894 */
895 if ((s = soln[y*w+x]) != 0) {
896 if (x > 0)
897 done_something |=
898 vbitmap_clear(w, h, sc, x-1, y, (s < 0 ? 0x1 : 0x2),
899 "contradicts known edge at (%d,%d)",x,y);
900 if (x+1 < w)
901 done_something |=
902 vbitmap_clear(w, h, sc, x, y, (s < 0 ? 0x2 : 0x1),
903 "contradicts known edge at (%d,%d)",x,y);
904 if (y > 0)
905 done_something |=
906 vbitmap_clear(w, h, sc, x, y-1, (s < 0 ? 0x4 : 0x8),
907 "contradicts known edge at (%d,%d)",x,y);
908 if (y+1 < h)
909 done_something |=
910 vbitmap_clear(w, h, sc, x, y, (s < 0 ? 0x8 : 0x4),
911 "contradicts known edge at (%d,%d)",x,y);
912 }
913
914 /*
915 * If both types of v are ruled out for a pair of
916 * adjacent squares, mark them as equivalent.
917 */
918 if (x+1 < w && !(sc->vbitmap[y*w+x] & 0x3)) {
919 int n1 = y*w+x, n2 = y*w+(x+1);
920 if (dsf_canonify(sc->equiv, n1) !=
921 dsf_canonify(sc->equiv, n2)) {
922 dsf_merge(sc->equiv, n1, n2);
923 done_something = true;
924#ifdef SOLVER_DIAGNOSTICS
925 if (verbose)
926 printf("(%d,%d) and (%d,%d) must be equivalent"
927 " because both v-shapes are ruled out\n",
928 x, y, x+1, y);
929#endif
930 }
931 }
932 if (y+1 < h && !(sc->vbitmap[y*w+x] & 0xC)) {
933 int n1 = y*w+x, n2 = (y+1)*w+x;
934 if (dsf_canonify(sc->equiv, n1) !=
935 dsf_canonify(sc->equiv, n2)) {
936 dsf_merge(sc->equiv, n1, n2);
937 done_something = true;
938#ifdef SOLVER_DIAGNOSTICS
939 if (verbose)
940 printf("(%d,%d) and (%d,%d) must be equivalent"
941 " because both v-shapes are ruled out\n",
942 x, y, x, y+1);
943#endif
944 }
945 }
946
947 /*
948 * The remaining work in this loop only works
949 * around non-edge clue points.
950 */
951 if (y == 0 || x == 0)
952 continue;
953 if ((c = clues[y*W+x]) < 0)
954 continue;
955
956 /*
957 * x,y marks a clue point not on the grid edge. See
958 * if this clue point allows us to rule out any v
959 * shapes.
960 */
961
962 if (c == 1) {
963 /*
964 * A 1 clue can never have any v shape pointing
965 * at it.
966 */
967 done_something |=
968 vbitmap_clear(w, h, sc, x-1, y-1, 0x5,
969 "points at 1 clue at (%d,%d)", x, y);
970 done_something |=
971 vbitmap_clear(w, h, sc, x-1, y, 0x2,
972 "points at 1 clue at (%d,%d)", x, y);
973 done_something |=
974 vbitmap_clear(w, h, sc, x, y-1, 0x8,
975 "points at 1 clue at (%d,%d)", x, y);
976 } else if (c == 3) {
977 /*
978 * A 3 clue can never have any v shape pointing
979 * away from it.
980 */
981 done_something |=
982 vbitmap_clear(w, h, sc, x-1, y-1, 0xA,
983 "points away from 3 clue at (%d,%d)", x, y);
984 done_something |=
985 vbitmap_clear(w, h, sc, x-1, y, 0x1,
986 "points away from 3 clue at (%d,%d)", x, y);
987 done_something |=
988 vbitmap_clear(w, h, sc, x, y-1, 0x4,
989 "points away from 3 clue at (%d,%d)", x, y);
990 } else if (c == 2) {
991 /*
992 * If a 2 clue has any kind of v ruled out on
993 * one side of it, the same v is ruled out on
994 * the other side.
995 */
996 done_something |=
997 vbitmap_clear(w, h, sc, x-1, y-1,
998 (sc->vbitmap[(y )*w+(x-1)] & 0x3) ^ 0x3,
999 "propagated by 2 clue at (%d,%d)", x, y);
1000 done_something |=
1001 vbitmap_clear(w, h, sc, x-1, y-1,
1002 (sc->vbitmap[(y-1)*w+(x )] & 0xC) ^ 0xC,
1003 "propagated by 2 clue at (%d,%d)", x, y);
1004 done_something |=
1005 vbitmap_clear(w, h, sc, x-1, y,
1006 (sc->vbitmap[(y-1)*w+(x-1)] & 0x3) ^ 0x3,
1007 "propagated by 2 clue at (%d,%d)", x, y);
1008 done_something |=
1009 vbitmap_clear(w, h, sc, x, y-1,
1010 (sc->vbitmap[(y-1)*w+(x-1)] & 0xC) ^ 0xC,
1011 "propagated by 2 clue at (%d,%d)", x, y);
1012 }
1013
1014#undef CLEARBITS
1015
1016 }
1017
1018 } while (done_something);
1019
1020 /*
1021 * Solver can make no more progress. See if the grid is full.
1022 */
1023 for (i = 0; i < w*h; i++)
1024 if (!soln[i])
1025 return 2; /* failed to converge */
1026 return 1; /* success */
1027}
1028
1029/*
1030 * Filled-grid generator.
1031 */
1032static void slant_generate(int w, int h, signed char *soln, random_state *rs)
1033{
1034 int W = w+1, H = h+1;
1035 int x, y, i;
1036 DSF *connected;
1037 int *indices;
1038
1039 /*
1040 * Clear the output.
1041 */
1042 memset(soln, 0, w*h);
1043
1044 /*
1045 * Establish a disjoint set forest for tracking connectedness
1046 * between grid points.
1047 */
1048 connected = dsf_new(W*H);
1049
1050 /*
1051 * Prepare a list of the squares in the grid, and fill them in
1052 * in a random order.
1053 */
1054 indices = snewn(w*h, int);
1055 for (i = 0; i < w*h; i++)
1056 indices[i] = i;
1057 shuffle(indices, w*h, sizeof(*indices), rs);
1058
1059 /*
1060 * Fill in each one in turn.
1061 */
1062 for (i = 0; i < w*h; i++) {
1063 bool fs, bs, ok;
1064 int v;
1065
1066 y = indices[i] / w;
1067 x = indices[i] % w;
1068
1069 fs = (dsf_canonify(connected, y*W+x) ==
1070 dsf_canonify(connected, (y+1)*W+(x+1)));
1071 bs = (dsf_canonify(connected, (y+1)*W+x) ==
1072 dsf_canonify(connected, y*W+(x+1)));
1073
1074 /*
1075 * It isn't possible to get into a situation where we
1076 * aren't allowed to place _either_ type of slash in a
1077 * square. Thus, filled-grid generation never has to
1078 * backtrack.
1079 *
1080 * Proof (thanks to Gareth Taylor):
1081 *
1082 * If it were possible, it would have to be because there
1083 * was an existing path (not using this square) between the
1084 * top-left and bottom-right corners of this square, and
1085 * another between the other two. These two paths would
1086 * have to cross at some point.
1087 *
1088 * Obviously they can't cross in the middle of a square, so
1089 * they must cross by sharing a point in common. But this
1090 * isn't possible either: if you chessboard-colour all the
1091 * points on the grid, you find that any continuous
1092 * diagonal path is entirely composed of points of the same
1093 * colour. And one of our two hypothetical paths is between
1094 * two black points, and the other is between two white
1095 * points - therefore they can have no point in common. []
1096 */
1097 assert(!(fs && bs));
1098
1099 v = fs ? +1 : bs ? -1 : 2 * random_upto(rs, 2) - 1;
1100 ok = fill_square(w, h, x, y, v, soln, connected, NULL);
1101 assert(ok);
1102 }
1103
1104 sfree(indices);
1105 dsf_free(connected);
1106}
1107
1108static char *new_game_desc(const game_params *params, random_state *rs,
1109 char **aux, bool interactive)
1110{
1111 int w = params->w, h = params->h, W = w+1, H = h+1;
1112 signed char *soln, *tmpsoln, *clues;
1113 int *clueindices;
1114 struct solver_scratch *sc;
1115 int x, y, v, i, j;
1116 char *desc;
1117
1118 soln = snewn(w*h, signed char);
1119 tmpsoln = snewn(w*h, signed char);
1120 clues = snewn(W*H, signed char);
1121 clueindices = snewn(W*H, int);
1122 sc = new_scratch(w, h);
1123
1124 do {
1125 /*
1126 * Create the filled grid.
1127 */
1128 slant_generate(w, h, soln, rs);
1129
1130 /*
1131 * Fill in the complete set of clues.
1132 */
1133 for (y = 0; y < H; y++)
1134 for (x = 0; x < W; x++) {
1135 v = 0;
1136
1137 if (x > 0 && y > 0 && soln[(y-1)*w+(x-1)] == -1) v++;
1138 if (x > 0 && y < h && soln[y*w+(x-1)] == +1) v++;
1139 if (x < w && y > 0 && soln[(y-1)*w+x] == +1) v++;
1140 if (x < w && y < h && soln[y*w+x] == -1) v++;
1141
1142 clues[y*W+x] = v;
1143 }
1144
1145 /*
1146 * With all clue points filled in, all puzzles are easy: we can
1147 * simply process the clue points in lexicographic order, and
1148 * at each clue point we will always have at most one square
1149 * undecided, which we can then fill in uniquely.
1150 */
1151 assert(slant_solve(w, h, clues, tmpsoln, sc, DIFF_EASY) == 1);
1152
1153 /*
1154 * Remove as many clues as possible while retaining solubility.
1155 *
1156 * In DIFF_HARD mode, we prioritise the removal of obvious
1157 * starting points (4s, 0s, border 2s and corner 1s), on
1158 * the grounds that having as few of these as possible
1159 * seems like a good thing. In particular, we can often get
1160 * away without _any_ completely obvious starting points,
1161 * which is even better.
1162 */
1163 for (i = 0; i < W*H; i++)
1164 clueindices[i] = i;
1165 shuffle(clueindices, W*H, sizeof(*clueindices), rs);
1166 for (j = 0; j < 2; j++) {
1167 for (i = 0; i < W*H; i++) {
1168 int pass;
1169 bool yb, xb;
1170
1171 y = clueindices[i] / W;
1172 x = clueindices[i] % W;
1173 v = clues[y*W+x];
1174
1175 /*
1176 * Identify which pass we should process this point
1177 * in. If it's an obvious start point, _or_ we're
1178 * in DIFF_EASY, then it goes in pass 0; otherwise
1179 * pass 1.
1180 */
1181 xb = (x == 0 || x == W-1);
1182 yb = (y == 0 || y == H-1);
1183 if (params->diff == DIFF_EASY || v == 4 || v == 0 ||
1184 (v == 2 && (xb||yb)) || (v == 1 && xb && yb))
1185 pass = 0;
1186 else
1187 pass = 1;
1188
1189 if (pass == j) {
1190 clues[y*W+x] = -1;
1191 if (slant_solve(w, h, clues, tmpsoln, sc,
1192 params->diff) != 1)
1193 clues[y*W+x] = v; /* put it back */
1194 }
1195 }
1196 }
1197
1198 /*
1199 * And finally, verify that the grid is of _at least_ the
1200 * requested difficulty, by running the solver one level
1201 * down and verifying that it can't manage it.
1202 */
1203 } while (params->diff > 0 &&
1204 slant_solve(w, h, clues, tmpsoln, sc, params->diff - 1) <= 1);
1205
1206 /*
1207 * Now we have the clue set as it will be presented to the
1208 * user. Encode it in a game desc.
1209 */
1210 {
1211 char *p;
1212 int run, i;
1213
1214 desc = snewn(W*H+1, char);
1215 p = desc;
1216 run = 0;
1217 for (i = 0; i <= W*H; i++) {
1218 int n = (i < W*H ? clues[i] : -2);
1219
1220 if (n == -1)
1221 run++;
1222 else {
1223 if (run) {
1224 while (run > 0) {
1225 int c = 'a' - 1 + run;
1226 if (run > 26)
1227 c = 'z';
1228 *p++ = c;
1229 run -= c - ('a' - 1);
1230 }
1231 }
1232 if (n >= 0)
1233 *p++ = '0' + n;
1234 run = 0;
1235 }
1236 }
1237 assert(p - desc <= W*H);
1238 *p++ = '\0';
1239 desc = sresize(desc, p - desc, char);
1240 }
1241
1242 /*
1243 * Encode the solution as an aux_info.
1244 */
1245 {
1246 char *auxbuf;
1247 *aux = auxbuf = snewn(w*h+1, char);
1248 for (i = 0; i < w*h; i++)
1249 auxbuf[i] = soln[i] < 0 ? '\\' : '/';
1250 auxbuf[w*h] = '\0';
1251 }
1252
1253 free_scratch(sc);
1254 sfree(clueindices);
1255 sfree(clues);
1256 sfree(tmpsoln);
1257 sfree(soln);
1258
1259 return desc;
1260}
1261
1262static const char *validate_desc(const game_params *params, const char *desc)
1263{
1264 int w = params->w, h = params->h, W = w+1, H = h+1;
1265 int area = W*H;
1266 int squares = 0;
1267
1268 while (*desc) {
1269 int n = *desc++;
1270 if (n >= 'a' && n <= 'z') {
1271 squares += n - 'a' + 1;
1272 } else if (n >= '0' && n <= '4') {
1273 squares++;
1274 } else
1275 return "Invalid character in game description";
1276 }
1277
1278 if (squares < area)
1279 return "Not enough data to fill grid";
1280
1281 if (squares > area)
1282 return "Too much data to fit in grid";
1283
1284 return NULL;
1285}
1286
1287static game_state *new_game(midend *me, const game_params *params,
1288 const char *desc)
1289{
1290 int w = params->w, h = params->h, W = w+1, H = h+1;
1291 game_state *state = snew(game_state);
1292 int area = W*H;
1293 int squares = 0;
1294
1295 state->p = *params;
1296 state->soln = snewn(w*h, signed char);
1297 memset(state->soln, 0, w*h);
1298 state->completed = state->used_solve = false;
1299 state->errors = snewn(W*H, unsigned char);
1300 memset(state->errors, 0, W*H);
1301
1302 state->clues = snew(game_clues);
1303 state->clues->w = w;
1304 state->clues->h = h;
1305 state->clues->clues = snewn(W*H, signed char);
1306 state->clues->refcount = 1;
1307 state->clues->tmpdsf = snewn(W*H*2+W+H, int);
1308 memset(state->clues->clues, -1, W*H);
1309 while (*desc) {
1310 int n = *desc++;
1311 if (n >= 'a' && n <= 'z') {
1312 squares += n - 'a' + 1;
1313 } else if (n >= '0' && n <= '4') {
1314 state->clues->clues[squares++] = n - '0';
1315 } else
1316 assert(!"can't get here");
1317 }
1318 assert(squares == area);
1319
1320 return state;
1321}
1322
1323static game_state *dup_game(const game_state *state)
1324{
1325 int w = state->p.w, h = state->p.h, W = w+1, H = h+1;
1326 game_state *ret = snew(game_state);
1327
1328 ret->p = state->p;
1329 ret->clues = state->clues;
1330 ret->clues->refcount++;
1331 ret->completed = state->completed;
1332 ret->used_solve = state->used_solve;
1333
1334 ret->soln = snewn(w*h, signed char);
1335 memcpy(ret->soln, state->soln, w*h);
1336
1337 ret->errors = snewn(W*H, unsigned char);
1338 memcpy(ret->errors, state->errors, W*H);
1339
1340 return ret;
1341}
1342
1343static void free_game(game_state *state)
1344{
1345 sfree(state->errors);
1346 sfree(state->soln);
1347 assert(state->clues);
1348 if (--state->clues->refcount <= 0) {
1349 sfree(state->clues->clues);
1350 sfree(state->clues->tmpdsf);
1351 sfree(state->clues);
1352 }
1353 sfree(state);
1354}
1355
1356/*
1357 * Utility function to return the current degree of a vertex. If
1358 * `anti' is set, it returns the number of filled-in edges
1359 * surrounding the point which _don't_ connect to it; thus 4 minus
1360 * its anti-degree is the maximum degree it could have if all the
1361 * empty spaces around it were filled in.
1362 *
1363 * (Yes, _4_ minus its anti-degree even if it's a border vertex.)
1364 *
1365 * If ret > 0, *sx and *sy are set to the coordinates of one of the
1366 * squares that contributed to it.
1367 */
1368static int vertex_degree(int w, int h, signed char *soln, int x, int y,
1369 bool anti, int *sx, int *sy)
1370{
1371 int ret = 0;
1372
1373 assert(x >= 0 && x <= w && y >= 0 && y <= h);
1374 if (x > 0 && y > 0 && soln[(y-1)*w+(x-1)] - anti < 0) {
1375 if (sx) *sx = x-1;
1376 if (sy) *sy = y-1;
1377 ret++;
1378 }
1379 if (x > 0 && y < h && soln[y*w+(x-1)] + anti > 0) {
1380 if (sx) *sx = x-1;
1381 if (sy) *sy = y;
1382 ret++;
1383 }
1384 if (x < w && y > 0 && soln[(y-1)*w+x] + anti > 0) {
1385 if (sx) *sx = x;
1386 if (sy) *sy = y-1;
1387 ret++;
1388 }
1389 if (x < w && y < h && soln[y*w+x] - anti < 0) {
1390 if (sx) *sx = x;
1391 if (sy) *sy = y;
1392 ret++;
1393 }
1394
1395 return anti ? 4 - ret : ret;
1396}
1397
1398struct slant_neighbour_ctx {
1399 const game_state *state;
1400 int i, n, neighbours[4];
1401};
1402static int slant_neighbour(int vertex, void *vctx)
1403{
1404 struct slant_neighbour_ctx *ctx = (struct slant_neighbour_ctx *)vctx;
1405
1406 if (vertex >= 0) {
1407 int w = ctx->state->p.w, h = ctx->state->p.h, W = w+1;
1408 int x = vertex % W, y = vertex / W;
1409 ctx->n = ctx->i = 0;
1410 if (x < w && y < h && ctx->state->soln[y*w+x] < 0)
1411 ctx->neighbours[ctx->n++] = (y+1)*W+(x+1);
1412 if (x > 0 && y > 0 && ctx->state->soln[(y-1)*w+(x-1)] < 0)
1413 ctx->neighbours[ctx->n++] = (y-1)*W+(x-1);
1414 if (x > 0 && y < h && ctx->state->soln[y*w+(x-1)] > 0)
1415 ctx->neighbours[ctx->n++] = (y+1)*W+(x-1);
1416 if (x < w && y > 0 && ctx->state->soln[(y-1)*w+x] > 0)
1417 ctx->neighbours[ctx->n++] = (y-1)*W+(x+1);
1418 }
1419
1420 if (ctx->i < ctx->n)
1421 return ctx->neighbours[ctx->i++];
1422 else
1423 return -1;
1424}
1425
1426static bool check_completion(game_state *state)
1427{
1428 int w = state->p.w, h = state->p.h, W = w+1, H = h+1;
1429 int x, y;
1430 bool err = false;
1431
1432 memset(state->errors, 0, W*H);
1433
1434 /*
1435 * Detect and grounded-highlight edge-connected components in the grid.
1436 */
1437 {
1438 DSF *connected = dsf_new(W*H);
1439 unsigned root_NW;
1440 int slash;
1441 int x, y;
1442
1443 for (x = 0; x <= w; x++) {
1444 dsf_merge(connected, x, 0);
1445 dsf_merge(connected, h*W+x, 0);
1446 }
1447 for (y = 0; y <= h; y++) {
1448 dsf_merge(connected, y*W, 0);
1449 dsf_merge(connected, y*W+w, 0);
1450 }
1451
1452 for (y = 0; y < h; y++) {
1453 for (x = 0; x < w; x++) {
1454 switch (state->soln[y*w+x]) {
1455 case -1:
1456 dsf_merge(connected, y*W+x, (y+1)*W+(x+1));
1457 break;
1458 case +1:
1459 dsf_merge(connected, y*W+(x+1), (y+1)*W+x);
1460 break;
1461 default:
1462 continue;
1463 }
1464 }
1465 }
1466
1467 root_NW = dsf_canonify(connected, 0);
1468 for (y = 0; y < h; y++)
1469 for (x = 0; x < w; x++)
1470 if ((slash = state->soln[y*w+x]) && dsf_canonify(
1471 connected, y*W + x + (slash == 1 ? 1 : 0)) == root_NW)
1472 state->errors[y*w+x] |= BORDER_EDGE;
1473 dsf_free(connected);
1474 }
1475
1476 /*
1477 * Detect and error-highlight loops in the grid.
1478 */
1479 {
1480 struct findloopstate *fls = findloop_new_state(W*H);
1481 struct slant_neighbour_ctx ctx;
1482 ctx.state = state;
1483
1484 if (findloop_run(fls, W*H, slant_neighbour, &ctx))
1485 err = true;
1486 for (y = 0; y < h; y++) {
1487 for (x = 0; x < w; x++) {
1488 int u, v;
1489 if (state->soln[y*w+x] == 0) {
1490 continue;
1491 } else if (state->soln[y*w+x] > 0) {
1492 u = y*W+(x+1);
1493 v = (y+1)*W+x;
1494 } else {
1495 u = (y+1)*W+(x+1);
1496 v = y*W+x;
1497 }
1498 if (findloop_is_loop_edge(fls, u, v))
1499 state->errors[y*W+x] |= ERR_SQUARE;
1500 }
1501 }
1502
1503 findloop_free_state(fls);
1504 }
1505
1506 /*
1507 * Now go through and check the degree of each clue vertex, and
1508 * mark it with ERR_VERTEX if it cannot be fulfilled.
1509 */
1510 for (y = 0; y < H; y++)
1511 for (x = 0; x < W; x++) {
1512 int c;
1513
1514 if ((c = state->clues->clues[y*W+x]) < 0)
1515 continue;
1516
1517 /*
1518 * Check to see if there are too many connections to
1519 * this vertex _or_ too many non-connections. Either is
1520 * grounds for marking the vertex as erroneous.
1521 */
1522 if (vertex_degree(w, h, state->soln, x, y,
1523 false, NULL, NULL) > c ||
1524 vertex_degree(w, h, state->soln, x, y,
1525 true, NULL, NULL) > 4-c) {
1526 state->errors[y*W+x] |= ERR_VERTEX;
1527 err = true;
1528 }
1529 }
1530
1531 /*
1532 * Now our actual victory condition is that (a) none of the
1533 * above code marked anything as erroneous, and (b) every
1534 * square has an edge in it.
1535 */
1536
1537 if (err)
1538 return false;
1539
1540 for (y = 0; y < h; y++)
1541 for (x = 0; x < w; x++)
1542 if (state->soln[y*w+x] == 0)
1543 return false;
1544
1545 return true;
1546}
1547
1548static char *solve_game(const game_state *state, const game_state *currstate,
1549 const char *aux, const char **error)
1550{
1551 int w = state->p.w, h = state->p.h;
1552 signed char *soln;
1553 int bs, ret;
1554 bool free_soln = false;
1555 char *move, buf[80];
1556 int movelen, movesize;
1557 int x, y;
1558
1559 if (aux) {
1560 /*
1561 * If we already have the solution, save ourselves some
1562 * time.
1563 */
1564 soln = (signed char *)aux;
1565 bs = (signed char)'\\';
1566 free_soln = false;
1567 } else {
1568 struct solver_scratch *sc = new_scratch(w, h);
1569 soln = snewn(w*h, signed char);
1570 bs = -1;
1571 ret = slant_solve(w, h, state->clues->clues, soln, sc, DIFF_HARD);
1572 free_scratch(sc);
1573 if (ret != 1) {
1574 sfree(soln);
1575 if (ret == 0)
1576 *error = "This puzzle is not self-consistent";
1577 else
1578 *error = "Unable to find a unique solution for this puzzle";
1579 return NULL;
1580 }
1581 free_soln = true;
1582 }
1583
1584 /*
1585 * Construct a move string which turns the current state into
1586 * the solved state.
1587 */
1588 movesize = 256;
1589 move = snewn(movesize, char);
1590 movelen = 0;
1591 move[movelen++] = 'S';
1592 move[movelen] = '\0';
1593 for (y = 0; y < h; y++)
1594 for (x = 0; x < w; x++) {
1595 int v = (soln[y*w+x] == bs ? -1 : +1);
1596 if (state->soln[y*w+x] != v) {
1597 int len = sprintf(buf, ";%c%d,%d", (int)(v < 0 ? '\\' : '/'), x, y);
1598 if (movelen + len >= movesize) {
1599 movesize = movelen + len + 256;
1600 move = sresize(move, movesize, char);
1601 }
1602 strcpy(move + movelen, buf);
1603 movelen += len;
1604 }
1605 }
1606
1607 if (free_soln)
1608 sfree(soln);
1609
1610 return move;
1611}
1612
1613static bool game_can_format_as_text_now(const game_params *params)
1614{
1615 return true;
1616}
1617
1618static char *game_text_format(const game_state *state)
1619{
1620 int w = state->p.w, h = state->p.h, W = w+1, H = h+1;
1621 int x, y, len;
1622 char *ret, *p;
1623
1624 /*
1625 * There are h+H rows of w+W columns.
1626 */
1627 len = (h+H) * (w+W+1) + 1;
1628 ret = snewn(len, char);
1629 p = ret;
1630
1631 for (y = 0; y < H; y++) {
1632 for (x = 0; x < W; x++) {
1633 if (state->clues->clues[y*W+x] >= 0)
1634 *p++ = state->clues->clues[y*W+x] + '0';
1635 else
1636 *p++ = '+';
1637 if (x < w)
1638 *p++ = '-';
1639 }
1640 *p++ = '\n';
1641 if (y < h) {
1642 for (x = 0; x < W; x++) {
1643 *p++ = '|';
1644 if (x < w) {
1645 if (state->soln[y*w+x] != 0)
1646 *p++ = (state->soln[y*w+x] < 0 ? '\\' : '/');
1647 else
1648 *p++ = ' ';
1649 }
1650 }
1651 *p++ = '\n';
1652 }
1653 }
1654 *p++ = '\0';
1655
1656 assert(p - ret == len);
1657 return ret;
1658}
1659
1660struct game_ui {
1661 int cur_x, cur_y;
1662 bool cur_visible;
1663
1664 /*
1665 * User preference option to swap the left and right mouse
1666 * buttons. There isn't a completely obvious mapping of left and
1667 * right buttons to the two directions of slash, and at least one
1668 * player turned out not to have the same intuition as me.
1669 */
1670 bool swap_buttons;
1671 bool fade_grounded;
1672};
1673
1674static void legacy_prefs_override(struct game_ui *ui_out)
1675{
1676 static bool initialised = false;
1677 static int swap_buttons = -1;
1678
1679 if (!initialised) {
1680 initialised = true;
1681 swap_buttons = getenv_bool("SLANT_SWAP_BUTTONS", -1);
1682 }
1683
1684 if (swap_buttons != -1)
1685 ui_out->swap_buttons = swap_buttons;
1686}
1687
1688static game_ui *new_ui(const game_state *state)
1689{
1690 game_ui *ui = snew(game_ui);
1691 ui->cur_x = ui->cur_y = 0;
1692 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1693
1694 ui->swap_buttons = false;
1695 ui->fade_grounded = false;
1696 legacy_prefs_override(ui);
1697
1698 return ui;
1699}
1700
1701static config_item *get_prefs(game_ui *ui)
1702{
1703 config_item *ret;
1704
1705 ret = snewn(N_PREF_ITEMS+1, config_item);
1706
1707 ret[PREF_MOUSE_BUTTON_ORDER].name = "Mouse button order";
1708 ret[PREF_MOUSE_BUTTON_ORDER].kw = "left-button";
1709 ret[PREF_MOUSE_BUTTON_ORDER].type = C_CHOICES;
1710 ret[PREF_MOUSE_BUTTON_ORDER].u.choices.choicenames =
1711 ":Left \\, right /:Left /, right \\";
1712 ret[PREF_MOUSE_BUTTON_ORDER].u.choices.choicekws = ":\\:/";
1713 ret[PREF_MOUSE_BUTTON_ORDER].u.choices.selected = ui->swap_buttons;
1714
1715 ret[PREF_FADE_GROUNDED].name = "Fade grounded components";
1716 ret[PREF_FADE_GROUNDED].kw = "fade-grounded";
1717 ret[PREF_FADE_GROUNDED].type = C_BOOLEAN;
1718 ret[PREF_FADE_GROUNDED].u.boolean.bval = ui->fade_grounded;
1719
1720 ret[N_PREF_ITEMS].name = NULL;
1721 ret[N_PREF_ITEMS].type = C_END;
1722
1723 return ret;
1724}
1725
1726static void set_prefs(game_ui *ui, const config_item *cfg)
1727{
1728 ui->swap_buttons = cfg[PREF_MOUSE_BUTTON_ORDER].u.choices.selected;
1729 ui->fade_grounded = cfg[PREF_FADE_GROUNDED].u.boolean.bval;
1730}
1731
1732static void free_ui(game_ui *ui)
1733{
1734 sfree(ui);
1735}
1736
1737static void game_changed_state(game_ui *ui, const game_state *oldstate,
1738 const game_state *newstate)
1739{
1740}
1741
1742static const char *current_key_label(const game_ui *ui,
1743 const game_state *state, int button)
1744{
1745 if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
1746 switch (state->soln[ui->cur_y*state->p.w+ui->cur_x]) {
1747 case 0:
1748 return button == CURSOR_SELECT ? "\\" : "/";
1749 case -1:
1750 return button == CURSOR_SELECT ? "/" : "Blank";
1751 case +1:
1752 return button == CURSOR_SELECT ? "Blank" : "\\";
1753 }
1754 }
1755 return "";
1756}
1757
1758#define PREFERRED_TILESIZE 32
1759#define TILESIZE (ds->tilesize)
1760#define BORDER TILESIZE
1761#define CLUE_RADIUS (TILESIZE / 3)
1762#define CLUE_TEXTSIZE (TILESIZE / 2)
1763#define COORD(x) ( (x) * TILESIZE + BORDER )
1764#define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 )
1765
1766#define FLASH_TIME 0.30F
1767
1768/*
1769 * Bit fields in the `grid' and `todraw' elements of the drawstate.
1770 */
1771#define BACKSLASH 0x00000001L
1772#define FORWSLASH 0x00000002L
1773#define L_T 0x00000004L
1774#define ERR_L_T 0x00000008L
1775#define L_B 0x00000010L
1776#define ERR_L_B 0x00000020L
1777#define T_L 0x00000040L
1778#define ERR_T_L 0x00000080L
1779#define T_R 0x00000100L
1780#define ERR_T_R 0x00000200L
1781#define C_TL 0x00000400L
1782#define ERR_C_TL 0x00000800L
1783#define FLASH 0x00001000L
1784#define ERRSLASH 0x00002000L
1785#define ERR_TL 0x00004000L
1786#define ERR_TR 0x00008000L
1787#define ERR_BL 0x00010000L
1788#define ERR_BR 0x00020000L
1789#define CURSOR 0x00040000L
1790#define GROUNDED 0x00080000L
1791
1792struct game_drawstate {
1793 int tilesize;
1794 long *grid;
1795 long *todraw;
1796};
1797
1798static char *interpret_move(const game_state *state, game_ui *ui,
1799 const game_drawstate *ds,
1800 int x, int y, int button)
1801{
1802 int w = state->p.w, h = state->p.h;
1803 int v;
1804 char buf[80];
1805 enum { CLOCKWISE, ANTICLOCKWISE, NONE } action = NONE;
1806
1807 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
1808 if (ui->swap_buttons) {
1809 if (button == LEFT_BUTTON)
1810 button = RIGHT_BUTTON;
1811 else
1812 button = LEFT_BUTTON;
1813 }
1814 action = (button == LEFT_BUTTON) ? CLOCKWISE : ANTICLOCKWISE;
1815
1816 x = FROMCOORD(x);
1817 y = FROMCOORD(y);
1818 if (x < 0 || y < 0 || x >= w || y >= h)
1819 return MOVE_UNUSED;
1820 ui->cur_visible = false;
1821 } else if (IS_CURSOR_SELECT(button)) {
1822 if (!ui->cur_visible) {
1823 ui->cur_visible = true;
1824 return MOVE_UI_UPDATE;
1825 }
1826 x = ui->cur_x;
1827 y = ui->cur_y;
1828
1829 action = (button == CURSOR_SELECT2) ? ANTICLOCKWISE : CLOCKWISE;
1830 } else if (IS_CURSOR_MOVE(button)) {
1831 return move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, false, &ui->cur_visible);
1832 } else if (button == '\\' || button == '\b' || button == '/') {
1833 int x = ui->cur_x, y = ui->cur_y;
1834 if (button == ("\\" "\b" "/")[state->soln[y*w + x] + 1])
1835 return MOVE_NO_EFFECT;
1836 sprintf(buf, "%c%d,%d", button == '\b' ? 'C' : button, x, y);
1837 return dupstr(buf);
1838 }
1839
1840 if (action != NONE) {
1841 if (action == CLOCKWISE) {
1842 /*
1843 * Left-clicking cycles blank -> \ -> / -> blank.
1844 */
1845 v = state->soln[y*w+x] - 1;
1846 if (v == -2)
1847 v = +1;
1848 } else {
1849 /*
1850 * Right-clicking cycles blank -> / -> \ -> blank.
1851 */
1852 v = state->soln[y*w+x] + 1;
1853 if (v == +2)
1854 v = -1;
1855 }
1856
1857 sprintf(buf, "%c%d,%d", (int)(v==-1 ? '\\' : v==+1 ? '/' : 'C'), x, y);
1858 return dupstr(buf);
1859 }
1860
1861 return MOVE_UNUSED;
1862}
1863
1864static game_state *execute_move(const game_state *state, const char *move)
1865{
1866 int w = state->p.w, h = state->p.h;
1867 char c;
1868 int x, y, n;
1869 game_state *ret = dup_game(state);
1870
1871 while (*move) {
1872 c = *move;
1873 if (c == 'S') {
1874 ret->used_solve = true;
1875 move++;
1876 } else if (c == '\\' || c == '/' || c == 'C') {
1877 move++;
1878 if (sscanf(move, "%d,%d%n", &x, &y, &n) != 2 ||
1879 x < 0 || y < 0 || x >= w || y >= h) {
1880 free_game(ret);
1881 return NULL;
1882 }
1883 ret->soln[y*w+x] = (c == '\\' ? -1 : c == '/' ? +1 : 0);
1884 move += n;
1885 } else {
1886 free_game(ret);
1887 return NULL;
1888 }
1889 if (*move == ';')
1890 move++;
1891 else if (*move) {
1892 free_game(ret);
1893 return NULL;
1894 }
1895 }
1896
1897 /*
1898 * We never clear the `completed' flag, but we must always
1899 * re-run the completion check because it also highlights
1900 * errors in the grid.
1901 */
1902 ret->completed = check_completion(ret) || ret->completed;
1903
1904 return ret;
1905}
1906
1907/* ----------------------------------------------------------------------
1908 * Drawing routines.
1909 */
1910
1911static void game_compute_size(const game_params *params, int tilesize,
1912 const game_ui *ui, int *x, int *y)
1913{
1914 /* fool the macros */
1915 struct dummy { int tilesize; } dummy, *ds = &dummy;
1916 dummy.tilesize = tilesize;
1917
1918 *x = 2 * BORDER + params->w * TILESIZE + 1;
1919 *y = 2 * BORDER + params->h * TILESIZE + 1;
1920}
1921
1922static void game_set_size(drawing *dr, game_drawstate *ds,
1923 const game_params *params, int tilesize)
1924{
1925 ds->tilesize = tilesize;
1926}
1927
1928static float *game_colours(frontend *fe, int *ncolours)
1929{
1930 float *ret = snewn(3 * NCOLOURS, float);
1931
1932 /* CURSOR colour is a background highlight. */
1933 game_mkhighlight(fe, ret, COL_BACKGROUND, COL_CURSOR, -1);
1934
1935 ret[COL_FILLEDSQUARE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0];
1936 ret[COL_FILLEDSQUARE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1];
1937 ret[COL_FILLEDSQUARE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2];
1938
1939 ret[COL_GRID * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.7F;
1940 ret[COL_GRID * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.7F;
1941 ret[COL_GRID * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 0.7F;
1942
1943 ret[COL_INK * 3 + 0] = 0.0F;
1944 ret[COL_INK * 3 + 1] = 0.0F;
1945 ret[COL_INK * 3 + 2] = 0.0F;
1946
1947 ret[COL_SLANT1 * 3 + 0] = 0.0F;
1948 ret[COL_SLANT1 * 3 + 1] = 0.0F;
1949 ret[COL_SLANT1 * 3 + 2] = 0.0F;
1950
1951 ret[COL_SLANT2 * 3 + 0] = 0.0F;
1952 ret[COL_SLANT2 * 3 + 1] = 0.0F;
1953 ret[COL_SLANT2 * 3 + 2] = 0.0F;
1954
1955 ret[COL_ERROR * 3 + 0] = 1.0F;
1956 ret[COL_ERROR * 3 + 1] = 0.0F;
1957 ret[COL_ERROR * 3 + 2] = 0.0F;
1958
1959 ret[COL_GROUNDED * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.8F;
1960 ret[COL_GROUNDED * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.8F;
1961 ret[COL_GROUNDED * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 0.8F;
1962
1963 *ncolours = NCOLOURS;
1964 return ret;
1965}
1966
1967static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1968{
1969 int w = state->p.w, h = state->p.h;
1970 int i;
1971 struct game_drawstate *ds = snew(struct game_drawstate);
1972
1973 ds->tilesize = 0;
1974 ds->grid = snewn((w+2)*(h+2), long);
1975 ds->todraw = snewn((w+2)*(h+2), long);
1976 for (i = 0; i < (w+2)*(h+2); i++)
1977 ds->grid[i] = ds->todraw[i] = -1;
1978
1979 return ds;
1980}
1981
1982static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1983{
1984 sfree(ds->todraw);
1985 sfree(ds->grid);
1986 sfree(ds);
1987}
1988
1989static void draw_clue(drawing *dr, game_drawstate *ds,
1990 int x, int y, long v, bool err, int bg, int colour)
1991{
1992 char p[2];
1993 int ccol = colour >= 0 ? colour : ((x ^ y) & 1) ? COL_SLANT1 : COL_SLANT2;
1994 int tcol = colour >= 0 ? colour : err ? COL_ERROR : COL_INK;
1995
1996 if (v < 0)
1997 return;
1998
1999 p[0] = (char)v + '0';
2000 p[1] = '\0';
2001 draw_circle(dr, COORD(x), COORD(y), CLUE_RADIUS,
2002 bg >= 0 ? bg : COL_BACKGROUND, ccol);
2003 draw_text(dr, COORD(x), COORD(y), FONT_VARIABLE,
2004 CLUE_TEXTSIZE, ALIGN_VCENTRE|ALIGN_HCENTRE, tcol, p);
2005}
2006
2007static void draw_tile(drawing *dr, game_drawstate *ds, game_clues *clues,
2008 int x, int y, long v)
2009{
2010 int w = clues->w, h = clues->h, W = w+1 /*, H = h+1 */;
2011 int chesscolour = (x ^ y) & 1;
2012 int fscol = chesscolour ? COL_SLANT2 : COL_SLANT1;
2013 int bscol = chesscolour ? COL_SLANT1 : COL_SLANT2;
2014
2015 clip(dr, COORD(x), COORD(y), TILESIZE, TILESIZE);
2016
2017 draw_rect(dr, COORD(x), COORD(y), TILESIZE, TILESIZE,
2018 (v & FLASH) ? COL_GRID :
2019 (v & CURSOR) ? COL_CURSOR :
2020 (v & (BACKSLASH | FORWSLASH)) ? COL_FILLEDSQUARE :
2021 COL_BACKGROUND);
2022
2023 /*
2024 * Draw the grid lines.
2025 */
2026 if (x >= 0 && x < w && y >= 0)
2027 draw_rect(dr, COORD(x), COORD(y), TILESIZE+1, 1, COL_GRID);
2028 if (x >= 0 && x < w && y < h)
2029 draw_rect(dr, COORD(x), COORD(y+1), TILESIZE+1, 1, COL_GRID);
2030 if (y >= 0 && y < h && x >= 0)
2031 draw_rect(dr, COORD(x), COORD(y), 1, TILESIZE+1, COL_GRID);
2032 if (y >= 0 && y < h && x < w)
2033 draw_rect(dr, COORD(x+1), COORD(y), 1, TILESIZE+1, COL_GRID);
2034 if (x == -1 && y == -1)
2035 draw_rect(dr, COORD(x+1), COORD(y+1), 1, 1, COL_GRID);
2036 if (x == -1 && y == h)
2037 draw_rect(dr, COORD(x+1), COORD(y), 1, 1, COL_GRID);
2038 if (x == w && y == -1)
2039 draw_rect(dr, COORD(x), COORD(y+1), 1, 1, COL_GRID);
2040 if (x == w && y == h)
2041 draw_rect(dr, COORD(x), COORD(y), 1, 1, COL_GRID);
2042
2043 /*
2044 * Draw the slash.
2045 */
2046 if (v & BACKSLASH) {
2047 int scol = ((v & ERRSLASH) ? COL_ERROR :
2048 (v & GROUNDED) ? COL_GROUNDED : bscol);
2049 draw_line(dr, COORD(x), COORD(y), COORD(x+1), COORD(y+1), scol);
2050 draw_line(dr, COORD(x)+1, COORD(y), COORD(x+1), COORD(y+1)-1,
2051 scol);
2052 draw_line(dr, COORD(x), COORD(y)+1, COORD(x+1)-1, COORD(y+1),
2053 scol);
2054 } else if (v & FORWSLASH) {
2055 int scol = ((v & ERRSLASH) ? COL_ERROR :
2056 (v & GROUNDED) ? COL_GROUNDED : fscol);
2057 draw_line(dr, COORD(x+1), COORD(y), COORD(x), COORD(y+1), scol);
2058 draw_line(dr, COORD(x+1)-1, COORD(y), COORD(x), COORD(y+1)-1,
2059 scol);
2060 draw_line(dr, COORD(x+1), COORD(y)+1, COORD(x)+1, COORD(y+1),
2061 scol);
2062 }
2063
2064 /*
2065 * Draw dots on the grid corners that appear if a slash is in a
2066 * neighbouring cell.
2067 */
2068 if (v & (L_T | BACKSLASH))
2069 draw_rect(dr, COORD(x), COORD(y)+1, 1, 1,
2070 (v & ERR_L_T ? COL_ERROR : bscol));
2071 if (v & (L_B | FORWSLASH))
2072 draw_rect(dr, COORD(x), COORD(y+1)-1, 1, 1,
2073 (v & ERR_L_B ? COL_ERROR : fscol));
2074 if (v & (T_L | BACKSLASH))
2075 draw_rect(dr, COORD(x)+1, COORD(y), 1, 1,
2076 (v & ERR_T_L ? COL_ERROR : bscol));
2077 if (v & (T_R | FORWSLASH))
2078 draw_rect(dr, COORD(x+1)-1, COORD(y), 1, 1,
2079 (v & ERR_T_R ? COL_ERROR : fscol));
2080 if (v & (C_TL | BACKSLASH))
2081 draw_rect(dr, COORD(x), COORD(y), 1, 1,
2082 (v & ERR_C_TL ? COL_ERROR : bscol));
2083
2084 /*
2085 * And finally the clues at the corners.
2086 */
2087 if (x >= 0 && y >= 0)
2088 draw_clue(dr, ds, x, y, clues->clues[y*W+x], v & ERR_TL, -1, -1);
2089 if (x < w && y >= 0)
2090 draw_clue(dr, ds, x+1, y, clues->clues[y*W+(x+1)], v & ERR_TR, -1, -1);
2091 if (x >= 0 && y < h)
2092 draw_clue(dr, ds, x, y+1, clues->clues[(y+1)*W+x], v & ERR_BL, -1, -1);
2093 if (x < w && y < h)
2094 draw_clue(dr, ds, x+1, y+1, clues->clues[(y+1)*W+(x+1)], v & ERR_BR,
2095 -1, -1);
2096
2097 unclip(dr);
2098 draw_update(dr, COORD(x), COORD(y), TILESIZE, TILESIZE);
2099}
2100
2101static void game_redraw(drawing *dr, game_drawstate *ds,
2102 const game_state *oldstate, const game_state *state,
2103 int dir, const game_ui *ui,
2104 float animtime, float flashtime)
2105{
2106 int w = state->p.w, h = state->p.h, W = w+1, H = h+1;
2107 int x, y;
2108 bool flashing;
2109
2110 if (flashtime > 0)
2111 flashing = (int)(flashtime * 3 / FLASH_TIME) != 1;
2112 else
2113 flashing = false;
2114
2115 /*
2116 * Loop over the grid and work out where all the slashes are.
2117 * We need to do this because a slash in one square affects the
2118 * drawing of the next one along.
2119 */
2120 for (y = -1; y <= h; y++)
2121 for (x = -1; x <= w; x++) {
2122 if (x >= 0 && x < w && y >= 0 && y < h)
2123 ds->todraw[(y+1)*(w+2)+(x+1)] = flashing ? FLASH : 0;
2124 else
2125 ds->todraw[(y+1)*(w+2)+(x+1)] = 0;
2126 }
2127
2128 for (y = 0; y < h; y++) {
2129 for (x = 0; x < w; x++) {
2130 bool err = state->errors[y*W+x] & ERR_SQUARE;
2131
2132 if (state->soln[y*w+x] < 0) {
2133 ds->todraw[(y+1)*(w+2)+(x+1)] |= BACKSLASH;
2134 ds->todraw[(y+2)*(w+2)+(x+1)] |= T_R;
2135 ds->todraw[(y+1)*(w+2)+(x+2)] |= L_B;
2136 ds->todraw[(y+2)*(w+2)+(x+2)] |= C_TL;
2137 if (err) {
2138 ds->todraw[(y+1)*(w+2)+(x+1)] |= ERRSLASH |
2139 ERR_T_L | ERR_L_T | ERR_C_TL;
2140 ds->todraw[(y+2)*(w+2)+(x+1)] |= ERR_T_R;
2141 ds->todraw[(y+1)*(w+2)+(x+2)] |= ERR_L_B;
2142 ds->todraw[(y+2)*(w+2)+(x+2)] |= ERR_C_TL;
2143 }
2144 } else if (state->soln[y*w+x] > 0) {
2145 ds->todraw[(y+1)*(w+2)+(x+1)] |= FORWSLASH;
2146 ds->todraw[(y+1)*(w+2)+(x+2)] |= L_T | C_TL;
2147 ds->todraw[(y+2)*(w+2)+(x+1)] |= T_L | C_TL;
2148 if (err) {
2149 ds->todraw[(y+1)*(w+2)+(x+1)] |= ERRSLASH |
2150 ERR_L_B | ERR_T_R;
2151 ds->todraw[(y+1)*(w+2)+(x+2)] |= ERR_L_T | ERR_C_TL;
2152 ds->todraw[(y+2)*(w+2)+(x+1)] |= ERR_T_L | ERR_C_TL;
2153 }
2154 }
2155 if (ui->cur_visible && ui->cur_x == x && ui->cur_y == y)
2156 ds->todraw[(y+1)*(w+2)+(x+1)] |= CURSOR;
2157 }
2158 }
2159
2160 for (y = 0; y < H; y++)
2161 for (x = 0; x < W; x++)
2162 if (state->errors[y*W+x] & ERR_VERTEX) {
2163 ds->todraw[y*(w+2)+x] |= ERR_BR;
2164 ds->todraw[y*(w+2)+(x+1)] |= ERR_BL;
2165 ds->todraw[(y+1)*(w+2)+x] |= ERR_TR;
2166 ds->todraw[(y+1)*(w+2)+(x+1)] |= ERR_TL;
2167 }
2168 if (ui->fade_grounded)
2169 for (y = 0; y < h; y++)
2170 for (x = 0; x < w; x++)
2171 if (state->errors[y*w+x] & BORDER_EDGE)
2172 // dunno why but it works this way
2173 ds->todraw[(y+1)*(W+1)+(x+1)] |= GROUNDED;
2174
2175 /*
2176 * Now go through and draw the grid squares.
2177 */
2178 for (y = -1; y <= h; y++) {
2179 for (x = -1; x <= w; x++) {
2180 if (ds->todraw[(y+1)*(w+2)+(x+1)] != ds->grid[(y+1)*(w+2)+(x+1)]) {
2181 draw_tile(dr, ds, state->clues, x, y,
2182 ds->todraw[(y+1)*(w+2)+(x+1)]);
2183 ds->grid[(y+1)*(w+2)+(x+1)] = ds->todraw[(y+1)*(w+2)+(x+1)];
2184 }
2185 }
2186 }
2187}
2188
2189static float game_anim_length(const game_state *oldstate,
2190 const game_state *newstate, int dir, game_ui *ui)
2191{
2192 return 0.0F;
2193}
2194
2195static float game_flash_length(const game_state *oldstate,
2196 const game_state *newstate, int dir, game_ui *ui)
2197{
2198 if (!oldstate->completed && newstate->completed &&
2199 !oldstate->used_solve && !newstate->used_solve)
2200 return FLASH_TIME;
2201
2202 return 0.0F;
2203}
2204
2205static void game_get_cursor_location(const game_ui *ui,
2206 const game_drawstate *ds,
2207 const game_state *state,
2208 const game_params *params,
2209 int *x, int *y, int *w, int *h)
2210{
2211 if(ui->cur_visible) {
2212 *x = COORD(ui->cur_x);
2213 *y = COORD(ui->cur_y);
2214 *w = *h = TILESIZE;
2215 }
2216}
2217
2218static int game_status(const game_state *state)
2219{
2220 return state->completed ? +1 : 0;
2221}
2222
2223static void game_print_size(const game_params *params, const game_ui *ui,
2224 float *x, float *y)
2225{
2226 int pw, ph;
2227
2228 /*
2229 * I'll use 6mm squares by default.
2230 */
2231 game_compute_size(params, 600, ui, &pw, &ph);
2232 *x = pw / 100.0F;
2233 *y = ph / 100.0F;
2234}
2235
2236static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2237 int tilesize)
2238{
2239 int w = state->p.w, h = state->p.h, W = w+1;
2240 int ink = print_mono_colour(dr, 0);
2241 int paper = print_mono_colour(dr, 1);
2242 int x, y;
2243
2244 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2245 game_drawstate ads, *ds = &ads;
2246 game_set_size(dr, ds, NULL, tilesize);
2247
2248 /*
2249 * Border.
2250 */
2251 print_line_width(dr, TILESIZE / 16);
2252 draw_rect_outline(dr, COORD(0), COORD(0), w*TILESIZE, h*TILESIZE, ink);
2253
2254 /*
2255 * Grid.
2256 */
2257 print_line_width(dr, TILESIZE / 24);
2258 for (x = 1; x < w; x++)
2259 draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), ink);
2260 for (y = 1; y < h; y++)
2261 draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), ink);
2262
2263 /*
2264 * Solution.
2265 */
2266 print_line_width(dr, TILESIZE / 12);
2267 for (y = 0; y < h; y++)
2268 for (x = 0; x < w; x++)
2269 if (state->soln[y*w+x]) {
2270 int ly, ry;
2271 /*
2272 * To prevent nasty line-ending artefacts at
2273 * corners, I'll do something slightly cunning
2274 * here.
2275 */
2276 clip(dr, COORD(x), COORD(y), TILESIZE, TILESIZE);
2277 if (state->soln[y*w+x] < 0)
2278 ly = y-1, ry = y+2;
2279 else
2280 ry = y-1, ly = y+2;
2281 draw_line(dr, COORD(x-1), COORD(ly), COORD(x+2), COORD(ry),
2282 ink);
2283 unclip(dr);
2284 }
2285
2286 /*
2287 * Clues.
2288 */
2289 print_line_width(dr, TILESIZE / 24);
2290 for (y = 0; y <= h; y++)
2291 for (x = 0; x <= w; x++)
2292 draw_clue(dr, ds, x, y, state->clues->clues[y*W+x],
2293 false, paper, ink);
2294}
2295
2296#ifdef COMBINED
2297#define thegame slant
2298#endif
2299
2300const struct game thegame = {
2301 "Slant", "games.slant", "slant",
2302 default_params,
2303 game_fetch_preset, NULL,
2304 decode_params,
2305 encode_params,
2306 free_params,
2307 dup_params,
2308 true, game_configure, custom_params,
2309 validate_params,
2310 new_game_desc,
2311 validate_desc,
2312 new_game,
2313 dup_game,
2314 free_game,
2315 true, solve_game,
2316 true, game_can_format_as_text_now, game_text_format,
2317 get_prefs, set_prefs,
2318 new_ui,
2319 free_ui,
2320 NULL, /* encode_ui */
2321 NULL, /* decode_ui */
2322 NULL, /* game_request_keys */
2323 game_changed_state,
2324 current_key_label,
2325 interpret_move,
2326 execute_move,
2327 PREFERRED_TILESIZE, game_compute_size, game_set_size,
2328 game_colours,
2329 game_new_drawstate,
2330 game_free_drawstate,
2331 game_redraw,
2332 game_anim_length,
2333 game_flash_length,
2334 game_get_cursor_location,
2335 game_status,
2336 true, false, game_print_size, game_print,
2337 false, /* wants_statusbar */
2338 false, NULL, /* timing_state */
2339 0, /* flags */
2340};
2341
2342#ifdef STANDALONE_SOLVER
2343
2344#include <stdarg.h>
2345
2346int main(int argc, char **argv)
2347{
2348 game_params *p;
2349 game_state *s;
2350 char *id = NULL, *desc;
2351 const char *err;
2352 bool grade = false;
2353 int ret, diff;
2354 bool really_verbose = false;
2355 struct solver_scratch *sc;
2356
2357 while (--argc > 0) {
2358 char *p = *++argv;
2359 if (!strcmp(p, "-v")) {
2360 really_verbose = true;
2361 } else if (!strcmp(p, "-g")) {
2362 grade = true;
2363 } else if (*p == '-') {
2364 fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
2365 return 1;
2366 } else {
2367 id = p;
2368 }
2369 }
2370
2371 if (!id) {
2372 fprintf(stderr, "usage: %s [-g | -v] <game_id>\n", argv[0]);
2373 return 1;
2374 }
2375
2376 desc = strchr(id, ':');
2377 if (!desc) {
2378 fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
2379 return 1;
2380 }
2381 *desc++ = '\0';
2382
2383 p = default_params();
2384 decode_params(p, id);
2385 err = validate_desc(p, desc);
2386 if (err) {
2387 fprintf(stderr, "%s: %s\n", argv[0], err);
2388 return 1;
2389 }
2390 s = new_game(NULL, p, desc);
2391
2392 sc = new_scratch(p->w, p->h);
2393
2394 /*
2395 * When solving an Easy puzzle, we don't want to bother the
2396 * user with Hard-level deductions. For this reason, we grade
2397 * the puzzle internally before doing anything else.
2398 */
2399 ret = -1; /* placate optimiser */
2400 for (diff = 0; diff < DIFFCOUNT; diff++) {
2401 ret = slant_solve(p->w, p->h, s->clues->clues,
2402 s->soln, sc, diff);
2403 if (ret < 2)
2404 break;
2405 }
2406
2407 if (diff == DIFFCOUNT) {
2408 if (grade)
2409 printf("Difficulty rating: harder than Hard, or ambiguous\n");
2410 else
2411 printf("Unable to find a unique solution\n");
2412 } else {
2413 if (grade) {
2414 if (ret == 0)
2415 printf("Difficulty rating: impossible (no solution exists)\n");
2416 else if (ret == 1)
2417 printf("Difficulty rating: %s\n", slant_diffnames[diff]);
2418 } else {
2419 verbose = really_verbose;
2420 ret = slant_solve(p->w, p->h, s->clues->clues,
2421 s->soln, sc, diff);
2422 if (ret == 0) {
2423 printf("Puzzle is inconsistent\n");
2424 } else {
2425 char *str = game_text_format(s);
2426 fputs(str, stdout);
2427 sfree(str);
2428 }
2429 }
2430 }
2431
2432 free_params(p);
2433 free_game(s);
2434 free_scratch(sc);
2435
2436 return 0;
2437}
2438
2439#endif
2440
2441/* vim: set shiftwidth=4 tabstop=8: */