2 * slant.c: Puzzle from nikoli.co.jp involving drawing a diagonal
3 * line through each square of a grid.
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.
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.
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.
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.
47 typedef struct game_clues {
50 int *dsf; /* scratch space for completion check */
59 int used_solve; /* used to suppress completion flash */
62 static game_params *default_params(void)
64 game_params *ret = snew(game_params);
71 static const struct game_params slant_presets[] = {
77 static int game_fetch_preset(int i, char **name, game_params **params)
82 if (i < 0 || i >= lenof(slant_presets))
85 ret = snew(game_params);
86 *ret = slant_presets[i];
88 sprintf(str, "%dx%d", ret->w, ret->h);
95 static void free_params(game_params *params)
100 static game_params *dup_params(game_params *params)
102 game_params *ret = snew(game_params);
103 *ret = *params; /* structure copy */
107 static void decode_params(game_params *ret, char const *string)
109 ret->w = ret->h = atoi(string);
110 while (*string && isdigit((unsigned char)*string)) string++;
111 if (*string == 'x') {
113 ret->h = atoi(string);
117 static char *encode_params(game_params *params, int full)
121 sprintf(data, "%dx%d", params->w, params->h);
126 static config_item *game_configure(game_params *params)
131 ret = snewn(3, config_item);
133 ret[0].name = "Width";
134 ret[0].type = C_STRING;
135 sprintf(buf, "%d", params->w);
136 ret[0].sval = dupstr(buf);
139 ret[1].name = "Height";
140 ret[1].type = C_STRING;
141 sprintf(buf, "%d", params->h);
142 ret[1].sval = dupstr(buf);
153 static game_params *custom_params(config_item *cfg)
155 game_params *ret = snew(game_params);
157 ret->w = atoi(cfg[0].sval);
158 ret->h = atoi(cfg[1].sval);
163 static char *validate_params(game_params *params, int full)
166 * (At least at the time of writing this comment) The grid
167 * generator is actually capable of handling even zero grid
168 * dimensions without crashing. Puzzles with a zero-area grid
169 * are a bit boring, though, because they're already solved :-)
172 if (params->w < 1 || params->h < 1)
173 return "Width and height must both be at least one";
179 * Utility function used by both the solver and the filled-grid
183 static void fill_square(int w, int h, int y, int x, int v,
184 signed char *soln, int *dsf)
186 int W = w+1 /*, H = h+1 */;
191 dsf_merge(dsf, y*W+x, (y+1)*W+(x+1));
193 dsf_merge(dsf, y*W+(x+1), (y+1)*W+x);
197 * Scratch space for solver.
199 struct solver_scratch {
203 static struct solver_scratch *new_scratch(int w, int h)
205 int W = w+1, H = h+1;
206 struct solver_scratch *ret = snew(struct solver_scratch);
207 ret->dsf = snewn(W*H, int);
211 static void free_scratch(struct solver_scratch *sc)
218 * Solver. Returns 0 for impossibility, 1 for success, 2 for
219 * ambiguity or failure to converge.
221 static int slant_solve(int w, int h, const signed char *clues,
222 signed char *soln, struct solver_scratch *sc)
224 int W = w+1, H = h+1;
231 memset(soln, 0, w*h);
234 * Establish a disjoint set forest for tracking connectedness
235 * between grid points.
237 for (i = 0; i < W*H; i++)
238 sc->dsf[i] = i; /* initially all distinct */
241 * Repeatedly try to deduce something until we can't.
244 done_something = FALSE;
247 * Any clue point with the number of remaining lines equal
248 * to zero or to the number of remaining undecided
249 * neighbouring squares can be filled in completely.
251 for (y = 0; y < H; y++)
252 for (x = 0; x < W; x++) {
255 if ((c = clues[y*W+x]) < 0)
259 * We have a clue point. Count up the number of
260 * undecided neighbours, and also the number of
261 * lines already present.
265 if (x > 0 && y > 0 && (v = soln[(y-1)*w+(x-1)]) != +1)
266 v == 0 ? nu++ : nl--;
267 if (x > 0 && y < h && (v = soln[y*w+(x-1)]) != -1)
268 v == 0 ? nu++ : nl--;
269 if (x < w && y > 0 && (v = soln[(y-1)*w+x]) != -1)
270 v == 0 ? nu++ : nl--;
271 if (x < w && y < h && (v = soln[y*w+x]) != +1)
272 v == 0 ? nu++ : nl--;
277 if (nl < 0 || nl > nu) {
279 * No consistent value for this at all!
281 return 0; /* impossible */
284 if (nu > 0 && (nl == 0 || nl == nu)) {
285 #ifdef SOLVER_DIAGNOSTICS
286 printf("%s around clue point at %d,%d\n",
287 nl ? "filling" : "emptying", x, y);
289 if (x > 0 && y > 0 && soln[(y-1)*w+(x-1)] == 0)
290 fill_square(w, h, y-1, x-1, (nl ? -1 : +1), soln,
292 if (x > 0 && y < h && soln[y*w+(x-1)] == 0)
293 fill_square(w, h, y, x-1, (nl ? +1 : -1), soln,
295 if (x < w && y > 0 && soln[(y-1)*w+x] == 0)
296 fill_square(w, h, y-1, x, (nl ? +1 : -1), soln,
298 if (x < w && y < h && soln[y*w+x] == 0)
299 fill_square(w, h, y, x, (nl ? -1 : +1), soln,
302 done_something = TRUE;
310 * Failing that, we now apply the second condition, which
311 * is that no square may be filled in such a way as to form
314 for (y = 0; y < h; y++)
315 for (x = 0; x < w; x++) {
319 continue; /* got this one already */
321 fs = (dsf_canonify(sc->dsf, y*W+x) ==
322 dsf_canonify(sc->dsf, (y+1)*W+(x+1)));
323 bs = (dsf_canonify(sc->dsf, (y+1)*W+x) ==
324 dsf_canonify(sc->dsf, y*W+(x+1)));
328 * Loop avoidance leaves no consistent value
331 return 0; /* impossible */
336 * Top left and bottom right corners of this
337 * square are already connected, which means we
338 * aren't allowed to put a backslash in here.
340 #ifdef SOLVER_DIAGNOSTICS
341 printf("placing / in %d,%d by loop avoidance\n", x, y);
343 fill_square(w, h, y, x, +1, soln, sc->dsf);
344 done_something = TRUE;
347 * Top right and bottom left corners of this
348 * square are already connected, which means we
349 * aren't allowed to put a forward slash in
352 #ifdef SOLVER_DIAGNOSTICS
353 printf("placing \\ in %d,%d by loop avoidance\n", x, y);
355 fill_square(w, h, y, x, -1, soln, sc->dsf);
356 done_something = TRUE;
360 } while (done_something);
363 * Solver can make no more progress. See if the grid is full.
365 for (i = 0; i < w*h; i++)
367 return 2; /* failed to converge */
368 return 1; /* success */
372 * Filled-grid generator.
374 static void slant_generate(int w, int h, signed char *soln, random_state *rs)
376 int W = w+1, H = h+1;
383 memset(soln, 0, w*h);
386 * Establish a disjoint set forest for tracking connectedness
387 * between grid points.
389 dsf = snewn(W*H, int);
390 for (i = 0; i < W*H; i++)
391 dsf[i] = i; /* initially all distinct */
394 * Prepare a list of the squares in the grid, and fill them in
397 indices = snewn(w*h, int);
398 for (i = 0; i < w*h; i++)
400 shuffle(indices, w*h, sizeof(*indices), rs);
403 * Fill in each one in turn.
405 for (i = 0; i < w*h; i++) {
411 fs = (dsf_canonify(dsf, y*W+x) ==
412 dsf_canonify(dsf, (y+1)*W+(x+1)));
413 bs = (dsf_canonify(dsf, (y+1)*W+x) ==
414 dsf_canonify(dsf, y*W+(x+1)));
417 * It isn't possible to get into a situation where we
418 * aren't allowed to place _either_ type of slash in a
421 * Proof (thanks to Gareth Taylor):
423 * If it were possible, it would have to be because there
424 * was an existing path (not using this square) between the
425 * top-left and bottom-right corners of this square, and
426 * another between the other two. These two paths would
427 * have to cross at some point.
429 * Obviously they can't cross in the middle of a square, so
430 * they must cross by sharing a point in common. But this
431 * isn't possible either: if you chessboard-colour all the
432 * points on the grid, you find that any continuous
433 * diagonal path is entirely composed of points of the same
434 * colour. And one of our two hypothetical paths is between
435 * two black points, and the other is between two white
436 * points - therefore they can have no point in common. []
440 v = fs ? +1 : bs ? -1 : 2 * random_upto(rs, 2) - 1;
441 fill_square(w, h, y, x, v, soln, dsf);
448 static char *new_game_desc(game_params *params, random_state *rs,
449 char **aux, int interactive)
451 int w = params->w, h = params->h, W = w+1, H = h+1;
452 signed char *soln, *tmpsoln, *clues;
454 struct solver_scratch *sc;
458 soln = snewn(w*h, signed char);
459 tmpsoln = snewn(w*h, signed char);
460 clues = snewn(W*H, signed char);
461 clueindices = snewn(W*H, int);
462 sc = new_scratch(w, h);
466 * Create the filled grid.
468 slant_generate(w, h, soln, rs);
471 * Fill in the complete set of clues.
473 for (y = 0; y < H; y++)
474 for (x = 0; x < W; x++) {
477 if (x > 0 && y > 0 && soln[(y-1)*w+(x-1)] == -1) v++;
478 if (x > 0 && y < h && soln[y*w+(x-1)] == +1) v++;
479 if (x < w && y > 0 && soln[(y-1)*w+x] == +1) v++;
480 if (x < w && y < h && soln[y*w+x] == -1) v++;
484 } while (slant_solve(w, h, clues, tmpsoln, sc) != 1);
487 * Remove as many clues as possible while retaining solubility.
489 for (i = 0; i < W*H; i++)
491 shuffle(clueindices, W*H, sizeof(*clueindices), rs);
492 for (i = 0; i < W*H; i++) {
493 y = clueindices[i] / W;
494 x = clueindices[i] % W;
497 if (slant_solve(w, h, clues, tmpsoln, sc) != 1)
498 clues[y*W+x] = v; /* put it back */
502 * Now we have the clue set as it will be presented to the
503 * user. Encode it in a game desc.
509 desc = snewn(W*H+1, char);
512 for (i = 0; i <= W*H; i++) {
513 int n = (i < W*H ? clues[i] : -2);
520 int c = 'a' - 1 + run;
524 run -= c - ('a' - 1);
532 assert(p - desc <= W*H);
534 desc = sresize(desc, p - desc, char);
538 * Encode the solution as an aux_info.
542 *aux = auxbuf = snewn(w*h+1, char);
543 for (i = 0; i < w*h; i++)
544 auxbuf[i] = soln[i] < 0 ? '\\' : '/';
557 static char *validate_desc(game_params *params, char *desc)
559 int w = params->w, h = params->h, W = w+1, H = h+1;
565 if (n >= 'a' && n <= 'z') {
566 squares += n - 'a' + 1;
567 } else if (n >= '0' && n <= '4') {
570 return "Invalid character in game description";
574 return "Not enough data to fill grid";
577 return "Too much data to fit in grid";
582 static game_state *new_game(midend_data *me, game_params *params, char *desc)
584 int w = params->w, h = params->h, W = w+1, H = h+1;
585 game_state *state = snew(game_state);
590 state->soln = snewn(w*h, signed char);
591 memset(state->soln, 0, w*h);
592 state->completed = state->used_solve = FALSE;
594 state->clues = snew(game_clues);
597 state->clues->clues = snewn(W*H, signed char);
598 state->clues->refcount = 1;
599 state->clues->dsf = snewn(W*H, int);
600 memset(state->clues->clues, -1, W*H);
603 if (n >= 'a' && n <= 'z') {
604 squares += n - 'a' + 1;
605 } else if (n >= '0' && n <= '4') {
606 state->clues->clues[squares++] = n - '0';
608 assert(!"can't get here");
610 assert(squares == area);
615 static game_state *dup_game(game_state *state)
617 int w = state->p.w, h = state->p.h;
618 game_state *ret = snew(game_state);
621 ret->clues = state->clues;
622 ret->clues->refcount++;
623 ret->completed = state->completed;
624 ret->used_solve = state->used_solve;
626 ret->soln = snewn(w*h, signed char);
627 memcpy(ret->soln, state->soln, w*h);
632 static void free_game(game_state *state)
635 assert(state->clues);
636 if (--state->clues->refcount <= 0) {
637 sfree(state->clues->clues);
638 sfree(state->clues->dsf);
644 static int check_completion(game_state *state)
646 int w = state->p.w, h = state->p.h, W = w+1, H = h+1;
650 * Establish a disjoint set forest for tracking connectedness
651 * between grid points. Use the dsf scratch space in the shared
652 * clues structure, to avoid mallocing too often.
654 for (i = 0; i < W*H; i++)
655 state->clues->dsf[i] = i; /* initially all distinct */
658 * Now go through the grid checking connectedness. While we're
659 * here, also check that everything is filled in.
661 for (y = 0; y < h; y++)
662 for (x = 0; x < w; x++) {
665 if (state->soln[y*w+x] == 0)
667 if (state->soln[y*w+x] < 0) {
676 * Our edge connects i1 with i2. If they're already
677 * connected, return failure. Otherwise, link them.
679 if (dsf_canonify(state->clues->dsf, i1) ==
680 dsf_canonify(state->clues->dsf, i2))
683 dsf_merge(state->clues->dsf, i1, i2);
687 * The grid is _a_ valid grid; let's see if it matches the
690 for (y = 0; y < H; y++)
691 for (x = 0; x < W; x++) {
694 if ((c = state->clues->clues[y*W+x]) < 0)
699 if (x > 0 && y > 0 && state->soln[(y-1)*w+(x-1)] == -1) v++;
700 if (x > 0 && y < h && state->soln[y*w+(x-1)] == +1) v++;
701 if (x < w && y > 0 && state->soln[(y-1)*w+x] == +1) v++;
702 if (x < w && y < h && state->soln[y*w+x] == -1) v++;
711 static char *solve_game(game_state *state, game_state *currstate,
712 char *aux, char **error)
714 int w = state->p.w, h = state->p.h;
717 int free_soln = FALSE;
719 int movelen, movesize;
724 * If we already have the solution, save ourselves some
727 soln = (signed char *)aux;
728 bs = (signed char)'\\';
731 struct solver_scratch *sc = new_scratch(w, h);
732 soln = snewn(w*h, signed char);
734 ret = slant_solve(w, h, state->clues->clues, soln, sc);
739 *error = "This puzzle is not self-consistent";
741 *error = "Unable to find a unique solution for this puzzle";
748 * Construct a move string which turns the current state into
752 move = snewn(movesize, char);
754 move[movelen++] = 'S';
755 move[movelen] = '\0';
756 for (y = 0; y < h; y++)
757 for (x = 0; x < w; x++) {
758 int v = (soln[y*w+x] == bs ? -1 : +1);
759 if (state->soln[y*w+x] != v) {
760 int len = sprintf(buf, ";%c%d,%d", (int)(v < 0 ? '\\' : '/'), x, y);
761 if (movelen + len >= movesize) {
762 movesize = movelen + len + 256;
763 move = sresize(move, movesize, char);
765 strcpy(move + movelen, buf);
776 static char *game_text_format(game_state *state)
778 int w = state->p.w, h = state->p.h, W = w+1, H = h+1;
783 * There are h+H rows of w+W columns.
785 len = (h+H) * (w+W+1) + 1;
786 ret = snewn(len, char);
789 for (y = 0; y < H; y++) {
790 for (x = 0; x < W; x++) {
791 if (state->clues->clues[y*W+x] >= 0)
792 *p++ = state->clues->clues[y*W+x] + '0';
800 for (x = 0; x < W; x++) {
803 if (state->soln[y*w+x] != 0)
804 *p++ = (state->soln[y*w+x] < 0 ? '\\' : '/');
814 assert(p - ret == len);
818 static game_ui *new_ui(game_state *state)
823 static void free_ui(game_ui *ui)
827 static char *encode_ui(game_ui *ui)
832 static void decode_ui(game_ui *ui, char *encoding)
836 static void game_changed_state(game_ui *ui, game_state *oldstate,
837 game_state *newstate)
841 #define PREFERRED_TILESIZE 32
842 #define TILESIZE (ds->tilesize)
843 #define BORDER TILESIZE
844 #define CLUE_RADIUS (TILESIZE / 3)
845 #define CLUE_TEXTSIZE (TILESIZE / 2)
846 #define COORD(x) ( (x) * TILESIZE + BORDER )
847 #define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 )
849 #define FLASH_TIME 0.30F
852 * Bit fields in the `grid' and `todraw' elements of the drawstate.
854 #define BACKSLASH 0x0001
855 #define FORWSLASH 0x0002
870 struct game_drawstate {
877 static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
878 int x, int y, int button)
880 int w = state->p.w, h = state->p.h;
882 if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
888 if (x < 0 || y < 0 || x >= w || y >= h)
891 if (button == LEFT_BUTTON) {
893 * Left-clicking cycles blank -> \ -> / -> blank.
895 v = state->soln[y*w+x] - 1;
900 * Right-clicking cycles blank -> / -> \ -> blank.
902 v = state->soln[y*w+x] + 1;
907 sprintf(buf, "%c%d,%d", (int)(v==-1 ? '\\' : v==+1 ? '/' : 'C'), x, y);
914 static game_state *execute_move(game_state *state, char *move)
916 int w = state->p.w, h = state->p.h;
919 game_state *ret = dup_game(state);
924 ret->used_solve = TRUE;
926 } else if (c == '\\' || c == '/' || c == 'C') {
928 if (sscanf(move, "%d,%d%n", &x, &y, &n) != 2 ||
929 x < 0 || y < 0 || x >= w || y >= h) {
933 ret->soln[y*w+x] = (c == '\\' ? -1 : c == '/' ? +1 : 0);
948 ret->completed = check_completion(ret);
953 /* ----------------------------------------------------------------------
957 static void game_compute_size(game_params *params, int tilesize,
960 /* fool the macros */
961 struct dummy { int tilesize; } dummy = { tilesize }, *ds = &dummy;
963 *x = 2 * BORDER + params->w * TILESIZE + 1;
964 *y = 2 * BORDER + params->h * TILESIZE + 1;
967 static void game_set_size(game_drawstate *ds, game_params *params,
970 ds->tilesize = tilesize;
973 static float *game_colours(frontend *fe, game_state *state, int *ncolours)
975 float *ret = snewn(3 * NCOLOURS, float);
977 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
979 ret[COL_GRID * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.7F;
980 ret[COL_GRID * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.7F;
981 ret[COL_GRID * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 0.7F;
983 ret[COL_INK * 3 + 0] = 0.0F;
984 ret[COL_INK * 3 + 1] = 0.0F;
985 ret[COL_INK * 3 + 2] = 0.0F;
987 ret[COL_SLANT1 * 3 + 0] = 0.0F;
988 ret[COL_SLANT1 * 3 + 1] = 0.0F;
989 ret[COL_SLANT1 * 3 + 2] = 0.0F;
991 ret[COL_SLANT2 * 3 + 0] = 0.0F;
992 ret[COL_SLANT2 * 3 + 1] = 0.0F;
993 ret[COL_SLANT2 * 3 + 2] = 0.0F;
995 *ncolours = NCOLOURS;
999 static game_drawstate *game_new_drawstate(game_state *state)
1001 int w = state->p.w, h = state->p.h;
1003 struct game_drawstate *ds = snew(struct game_drawstate);
1006 ds->started = FALSE;
1007 ds->grid = snewn(w*h, int);
1008 ds->todraw = snewn(w*h, int);
1009 for (i = 0; i < w*h; i++)
1010 ds->grid[i] = ds->todraw[i] = -1;
1015 static void game_free_drawstate(game_drawstate *ds)
1022 static void draw_clue(frontend *fe, game_drawstate *ds,
1023 int x, int y, int v)
1026 int col = ((x ^ y) & 1) ? COL_SLANT1 : COL_SLANT2;
1033 draw_circle(fe, COORD(x), COORD(y), CLUE_RADIUS, COL_BACKGROUND, col);
1034 draw_text(fe, COORD(x), COORD(y), FONT_VARIABLE,
1035 CLUE_TEXTSIZE, ALIGN_VCENTRE|ALIGN_HCENTRE,
1039 static void draw_tile(frontend *fe, game_drawstate *ds, game_clues *clues,
1040 int x, int y, int v)
1042 int w = clues->w /*, h = clues->h*/, W = w+1 /*, H = h+1 */;
1044 int chesscolour = (x ^ y) & 1;
1045 int fscol = chesscolour ? COL_SLANT2 : COL_SLANT1;
1046 int bscol = chesscolour ? COL_SLANT1 : COL_SLANT2;
1048 clip(fe, COORD(x), COORD(y), TILESIZE+1, TILESIZE+1);
1050 draw_rect(fe, COORD(x), COORD(y), TILESIZE, TILESIZE,
1051 (v & FLASH) ? COL_GRID : COL_BACKGROUND);
1054 * Draw the grid lines.
1056 draw_line(fe, COORD(x), COORD(y), COORD(x+1), COORD(y), COL_GRID);
1057 draw_line(fe, COORD(x), COORD(y+1), COORD(x+1), COORD(y+1), COL_GRID);
1058 draw_line(fe, COORD(x), COORD(y), COORD(x), COORD(y+1), COL_GRID);
1059 draw_line(fe, COORD(x+1), COORD(y), COORD(x+1), COORD(y+1), COL_GRID);
1064 if (v & BACKSLASH) {
1065 draw_line(fe, COORD(x), COORD(y), COORD(x+1), COORD(y+1), bscol);
1066 draw_line(fe, COORD(x)+1, COORD(y), COORD(x+1), COORD(y+1)-1,
1068 draw_line(fe, COORD(x), COORD(y)+1, COORD(x+1)-1, COORD(y+1),
1070 } else if (v & FORWSLASH) {
1071 draw_line(fe, COORD(x+1), COORD(y), COORD(x), COORD(y+1), fscol);
1072 draw_line(fe, COORD(x+1)-1, COORD(y), COORD(x), COORD(y+1)-1,
1074 draw_line(fe, COORD(x+1), COORD(y)+1, COORD(x)+1, COORD(y+1),
1079 * Draw dots on the grid corners that appear if a slash is in a
1080 * neighbouring cell.
1083 draw_rect(fe, COORD(x), COORD(y)+1, 1, 1, bscol);
1085 draw_rect(fe, COORD(x), COORD(y+1)-1, 1, 1, fscol);
1087 draw_rect(fe, COORD(x+1), COORD(y)+1, 1, 1, fscol);
1089 draw_rect(fe, COORD(x+1), COORD(y+1)-1, 1, 1, bscol);
1091 draw_rect(fe, COORD(x)+1, COORD(y), 1, 1, bscol);
1093 draw_rect(fe, COORD(x+1)-1, COORD(y), 1, 1, fscol);
1095 draw_rect(fe, COORD(x)+1, COORD(y+1), 1, 1, fscol);
1097 draw_rect(fe, COORD(x+1)-1, COORD(y+1), 1, 1, bscol);
1099 draw_rect(fe, COORD(x), COORD(y), 1, 1, bscol);
1101 draw_rect(fe, COORD(x+1), COORD(y), 1, 1, fscol);
1103 draw_rect(fe, COORD(x), COORD(y+1), 1, 1, fscol);
1105 draw_rect(fe, COORD(x+1), COORD(y+1), 1, 1, bscol);
1108 * And finally the clues at the corners.
1110 for (xx = x; xx <= x+1; xx++)
1111 for (yy = y; yy <= y+1; yy++)
1112 draw_clue(fe, ds, xx, yy, clues->clues[yy*W+xx]);
1115 draw_update(fe, COORD(x), COORD(y), TILESIZE+1, TILESIZE+1);
1118 static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
1119 game_state *state, int dir, game_ui *ui,
1120 float animtime, float flashtime)
1122 int w = state->p.w, h = state->p.h, W = w+1, H = h+1;
1127 flashing = (int)(flashtime * 3 / FLASH_TIME) != 1;
1133 game_compute_size(&state->p, TILESIZE, &ww, &wh);
1134 draw_rect(fe, 0, 0, ww, wh, COL_BACKGROUND);
1135 draw_update(fe, 0, 0, ww, wh);
1138 * Draw any clues on the very edges (since normal tile
1139 * redraw won't draw the bits outside the grid boundary).
1141 for (y = 0; y < H; y++) {
1142 draw_clue(fe, ds, 0, y, state->clues->clues[y*W+0]);
1143 draw_clue(fe, ds, w, y, state->clues->clues[y*W+w]);
1145 for (x = 0; x < W; x++) {
1146 draw_clue(fe, ds, x, 0, state->clues->clues[0*W+x]);
1147 draw_clue(fe, ds, x, h, state->clues->clues[h*W+x]);
1154 * Loop over the grid and work out where all the slashes are.
1155 * We need to do this because a slash in one square affects the
1156 * drawing of the next one along.
1158 for (y = 0; y < h; y++)
1159 for (x = 0; x < w; x++)
1160 ds->todraw[y*w+x] = flashing ? FLASH : 0;
1162 for (y = 0; y < h; y++) {
1163 for (x = 0; x < w; x++) {
1164 if (state->soln[y*w+x] < 0) {
1165 ds->todraw[y*w+x] |= BACKSLASH;
1167 ds->todraw[y*w+(x-1)] |= R_T | C_TR;
1169 ds->todraw[y*w+(x+1)] |= L_B | C_BL;
1171 ds->todraw[(y-1)*w+x] |= B_L | C_BL;
1173 ds->todraw[(y+1)*w+x] |= T_R | C_TR;
1175 ds->todraw[(y-1)*w+(x-1)] |= C_BR;
1176 if (x+1 < w && y+1 < h)
1177 ds->todraw[(y+1)*w+(x+1)] |= C_TL;
1178 } else if (state->soln[y*w+x] > 0) {
1179 ds->todraw[y*w+x] |= FORWSLASH;
1181 ds->todraw[y*w+(x-1)] |= R_B | C_BR;
1183 ds->todraw[y*w+(x+1)] |= L_T | C_TL;
1185 ds->todraw[(y-1)*w+x] |= B_R | C_BR;
1187 ds->todraw[(y+1)*w+x] |= T_L | C_TL;
1188 if (x > 0 && y+1 < h)
1189 ds->todraw[(y+1)*w+(x-1)] |= C_TR;
1190 if (x+1 < w && y > 0)
1191 ds->todraw[(y-1)*w+(x+1)] |= C_BL;
1197 * Now go through and draw the grid squares.
1199 for (y = 0; y < h; y++) {
1200 for (x = 0; x < w; x++) {
1201 if (ds->todraw[y*w+x] != ds->grid[y*w+x]) {
1202 draw_tile(fe, ds, state->clues, x, y, ds->todraw[y*w+x]);
1203 ds->grid[y*w+x] = ds->todraw[y*w+x];
1209 static float game_anim_length(game_state *oldstate, game_state *newstate,
1210 int dir, game_ui *ui)
1215 static float game_flash_length(game_state *oldstate, game_state *newstate,
1216 int dir, game_ui *ui)
1218 if (!oldstate->completed && newstate->completed &&
1219 !oldstate->used_solve && !newstate->used_solve)
1225 static int game_wants_statusbar(void)
1230 static int game_timing_state(game_state *state, game_ui *ui)
1236 #define thegame slant
1239 const struct game thegame = {
1240 "Slant", "games.slant",
1247 TRUE, game_configure, custom_params,
1255 TRUE, game_text_format,
1263 PREFERRED_TILESIZE, game_compute_size, game_set_size,
1266 game_free_drawstate,
1270 game_wants_statusbar,
1271 FALSE, game_timing_state,
1272 0, /* mouse_priorities */