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 */