2 * undead: Implementation of Haunted Mirror Mazes
4 * http://www.janko.at/Raetsel/Spukschloss/index.htm
6 * Puzzle definition is the total number of each monster type, the
7 * grid definition, and the list of sightings (clockwise, starting
8 * from top left corner)
10 * Example: (Janko puzzle No. 1,
11 * http://www.janko.at/Raetsel/Spukschloss/001.a.htm )
13 * Ghosts: 0 Vampires: 2 Zombies: 6
22 * would be encoded into:
23 * 4x4:0,2,6,LLaRLaRaRaRdL,2,1,1,1,2,2,2,2,2,2,3,3,3,0,0,1
25 * Additionally, the game description can contain monsters fixed at a
26 * certain grid position. The internal generator does not (yet) use
27 * this feature, but this is needed to enter puzzles like Janko No.
28 * 14, which is encoded as:
29 * 8x5:12,12,0,LaRbLaRaLaRLbRaVaVaGRaRaRaLbLaRbRLb,0,2,0,2,2,1,2,1,3,1,0,1,8,4,3,0,0,2,3,2,7,2,1,6,2,1
60 #define ENUM(upper,title,lower) DIFF_ ## upper,
61 #define TITLE(upper,title,lower) #title,
62 #define ENCODE(upper,title,lower) #lower
63 #define CONFIG(upper,title,lower) ":" #title
64 enum { DIFFLIST(ENUM
) DIFFCOUNT
};
65 static char const *const undead_diffnames
[] = { DIFFLIST(TITLE
) "(count)" };
66 static char const undead_diffchars
[] = DIFFLIST(ENCODE
);
67 #define DIFFCONFIG DIFFLIST(CONFIG)
70 int w
; /* Grid width */
71 int h
; /* Grid height */
72 int diff
; /* Puzzle difficulty */
75 static const struct game_params undead_presets
[] = {
77 { 4, 4, DIFF_NORMAL
},
78 { 4, 4, DIFF_TRICKY
},
80 { 5, 5, DIFF_NORMAL
},
81 { 5, 5, DIFF_TRICKY
},
86 #define DEFAULT_PRESET 1
88 static game_params
*default_params(void) {
89 game_params
*ret
= snew(game_params
);
91 *ret
= undead_presets
[DEFAULT_PRESET
];
95 static int game_fetch_preset(int i
, char **name
, game_params
**params
) {
99 if (i
< 0 || i
>= lenof(undead_presets
)) return FALSE
;
101 ret
= default_params();
102 *ret
= undead_presets
[i
]; /* struct copy */
105 sprintf(buf
, "%dx%d %s",
106 undead_presets
[i
].w
, undead_presets
[i
].h
,
107 undead_diffnames
[undead_presets
[i
].diff
]);
113 static void free_params(game_params
*params
) {
117 static game_params
*dup_params(const game_params
*params
)
119 game_params
*ret
= snew(game_params
);
120 *ret
= *params
; /* structure copy */
124 static void decode_params(game_params
*params
, char const *string
) {
125 params
->w
= params
->h
= atoi(string
);
127 while (*string
&& isdigit((unsigned char) *string
)) ++string
;
128 if (*string
== 'x') {
130 params
->h
= atoi(string
);
131 while (*string
&& isdigit((unsigned char)*string
)) string
++;
134 params
->diff
= DIFF_NORMAL
;
135 if (*string
== 'd') {
138 for (i
= 0; i
< DIFFCOUNT
; i
++)
139 if (*string
== undead_diffchars
[i
])
141 if (*string
) string
++;
147 static char *encode_params(const game_params
*params
, int full
)
150 sprintf(buf
, "%dx%d", params
->w
, params
->h
);
152 sprintf(buf
+ strlen(buf
), "d%c", undead_diffchars
[params
->diff
]);
156 static config_item
*game_configure(const game_params
*params
)
161 ret
= snewn(4, config_item
);
163 ret
[0].name
= "Width";
164 ret
[0].type
= C_STRING
;
165 sprintf(buf
, "%d", params
->w
);
166 ret
[0].sval
= dupstr(buf
);
169 ret
[1].name
= "Height";
170 ret
[1].type
= C_STRING
;
171 sprintf(buf
, "%d", params
->h
);
172 ret
[1].sval
= dupstr(buf
);
175 ret
[2].name
= "Difficulty";
176 ret
[2].type
= C_CHOICES
;
177 ret
[2].sval
= DIFFCONFIG
;
178 ret
[2].ival
= params
->diff
;
188 static game_params
*custom_params(const config_item
*cfg
)
190 game_params
*ret
= snew(game_params
);
192 ret
->w
= atoi(cfg
[0].sval
);
193 ret
->h
= atoi(cfg
[1].sval
);
194 ret
->diff
= cfg
[2].ival
;
198 static char *validate_params(const game_params
*params
, int full
)
200 if ((params
->w
* params
->h
) > 54) return "Grid is too big";
201 if (params
->w
< 3) return "Width must be at least 3";
202 if (params
->h
< 3) return "Height must be at least 3";
203 if (params
->diff
>= DIFFCOUNT
) return "Unknown difficulty rating";
207 /* --------------------------------------------------------------- */
208 /* Game state allocation, deallocation. */
224 struct game_params params
;
226 int num_ghosts
,num_vampires
,num_zombies
,num_total
;
236 struct game_common
*common
;
238 unsigned char *pencils
;
239 unsigned char *cell_errors
;
240 unsigned char *hint_errors
;
241 unsigned char *hints_done
;
242 unsigned char count_errors
[3];
247 static game_state
*new_state(const game_params
*params
) {
249 game_state
*state
= snew(game_state
);
250 state
->common
= snew(struct game_common
);
252 state
->common
->refcount
= 1;
253 state
->common
->params
.w
= params
->w
;
254 state
->common
->params
.h
= params
->h
;
255 state
->common
->params
.diff
= params
->diff
;
257 state
->common
->wh
= (state
->common
->params
.w
+2) * (state
->common
->params
.h
+2);
259 state
->common
->num_ghosts
= 0;
260 state
->common
->num_vampires
= 0;
261 state
->common
->num_zombies
= 0;
262 state
->common
->num_total
= 0;
264 state
->common
->grid
= snewn(state
->common
->wh
, int);
265 state
->common
->xinfo
= snewn(state
->common
->wh
, int);
266 state
->common
->fixed
= NULL
;
267 state
->common
->solved
= FALSE
;
269 state
->common
->num_paths
=
270 state
->common
->params
.w
+ state
->common
->params
.h
;
271 state
->common
->paths
= snewn(state
->common
->num_paths
, struct path
);
273 for (i
=0;i
<state
->common
->num_paths
;i
++) {
274 state
->common
->paths
[i
].length
= 0;
275 state
->common
->paths
[i
].grid_start
= -1;
276 state
->common
->paths
[i
].grid_end
= -1;
277 state
->common
->paths
[i
].num_monsters
= 0;
278 state
->common
->paths
[i
].sightings_start
= 0;
279 state
->common
->paths
[i
].sightings_end
= 0;
280 state
->common
->paths
[i
].p
= snewn(state
->common
->wh
,int);
281 state
->common
->paths
[i
].xy
= snewn(state
->common
->wh
,int);
282 state
->common
->paths
[i
].mapping
= snewn(state
->common
->wh
,int);
286 state
->pencils
= NULL
;
288 state
->cell_errors
= snewn(state
->common
->wh
, unsigned char);
289 for (i
=0;i
<state
->common
->wh
;i
++)
290 state
->cell_errors
[i
] = FALSE
;
291 state
->hint_errors
= snewn(2*state
->common
->num_paths
, unsigned char);
292 for (i
=0;i
<2*state
->common
->num_paths
;i
++)
293 state
->hint_errors
[i
] = FALSE
;
294 state
->hints_done
= snewn(2 * state
->common
->num_paths
, unsigned char);
295 memset(state
->hints_done
, 0,
296 2 * state
->common
->num_paths
* sizeof(unsigned char));
298 state
->count_errors
[i
] = FALSE
;
300 state
->solved
= FALSE
;
301 state
->cheated
= FALSE
;
306 static game_state
*dup_game(const game_state
*state
)
308 game_state
*ret
= snew(game_state
);
310 ret
->common
= state
->common
;
311 ret
->common
->refcount
++;
313 if (state
->guess
!= NULL
) {
314 ret
->guess
= snewn(ret
->common
->num_total
,int);
315 memcpy(ret
->guess
, state
->guess
, ret
->common
->num_total
*sizeof(int));
317 else ret
->guess
= NULL
;
319 if (state
->pencils
!= NULL
) {
320 ret
->pencils
= snewn(ret
->common
->num_total
,unsigned char);
321 memcpy(ret
->pencils
, state
->pencils
,
322 ret
->common
->num_total
*sizeof(unsigned char));
324 else ret
->pencils
= NULL
;
326 if (state
->cell_errors
!= NULL
) {
327 ret
->cell_errors
= snewn(ret
->common
->wh
,unsigned char);
328 memcpy(ret
->cell_errors
, state
->cell_errors
,
329 ret
->common
->wh
*sizeof(unsigned char));
331 else ret
->cell_errors
= NULL
;
333 if (state
->hint_errors
!= NULL
) {
334 ret
->hint_errors
= snewn(2*ret
->common
->num_paths
,unsigned char);
335 memcpy(ret
->hint_errors
, state
->hint_errors
,
336 2*ret
->common
->num_paths
*sizeof(unsigned char));
338 else ret
->hint_errors
= NULL
;
340 if (state
->hints_done
!= NULL
) {
341 ret
->hints_done
= snewn(2 * state
->common
->num_paths
, unsigned char);
342 memcpy(ret
->hints_done
, state
->hints_done
,
343 2 * state
->common
->num_paths
* sizeof(unsigned char));
345 else ret
->hints_done
= NULL
;
347 ret
->count_errors
[0] = state
->count_errors
[0];
348 ret
->count_errors
[1] = state
->count_errors
[1];
349 ret
->count_errors
[2] = state
->count_errors
[2];
351 ret
->solved
= state
->solved
;
352 ret
->cheated
= state
->cheated
;
357 static void free_game(game_state
*state
) {
360 state
->common
->refcount
--;
361 if (state
->common
->refcount
== 0) {
362 for (i
=0;i
<state
->common
->num_paths
;i
++) {
363 sfree(state
->common
->paths
[i
].mapping
);
364 sfree(state
->common
->paths
[i
].xy
);
365 sfree(state
->common
->paths
[i
].p
);
367 sfree(state
->common
->paths
);
368 sfree(state
->common
->xinfo
);
369 sfree(state
->common
->grid
);
370 if (state
->common
->fixed
!= NULL
) sfree(state
->common
->fixed
);
371 sfree(state
->common
);
373 if (state
->hints_done
!= NULL
) sfree(state
->hints_done
);
374 if (state
->hint_errors
!= NULL
) sfree(state
->hint_errors
);
375 if (state
->cell_errors
!= NULL
) sfree(state
->cell_errors
);
376 if (state
->pencils
!= NULL
) sfree(state
->pencils
);
377 if (state
->guess
!= NULL
) sfree(state
->guess
);
383 /* --------------------------------------------------------------- */
384 /* Puzzle generator */
397 /* grid walk directions */
406 int range2grid(int rangeno
, int width
, int height
, int *x
, int *y
) {
409 *x
= 0; *y
= 0; return DIRECTION_NONE
;
411 if (rangeno
< width
) {
412 *x
= rangeno
+1; *y
= 0; return DIRECTION_DOWN
;
414 rangeno
= rangeno
- width
;
415 if (rangeno
< height
) {
416 *x
= width
+1; *y
= rangeno
+1; return DIRECTION_LEFT
;
418 rangeno
= rangeno
- height
;
419 if (rangeno
< width
) {
420 *x
= width
-rangeno
; *y
= height
+1; return DIRECTION_UP
;
422 rangeno
= rangeno
- width
;
423 if (rangeno
< height
) {
424 *x
= 0; *y
= height
-rangeno
; return DIRECTION_RIGHT
;
427 return DIRECTION_NONE
;
430 int grid2range(int x
, int y
, int w
, int h
) {
431 if (x
>0 && x
<w
+1 && y
>0 && y
<h
+1) return -1;
432 if (x
<0 || x
>w
+1 || y
<0 || y
>h
+1) return -1;
433 if ((x
== 0 || x
==w
+1) && (y
==0 || y
==h
+1)) return -1;
434 if (y
==0) return x
-1;
435 if (x
==(w
+1)) return y
-1+w
;
436 if (y
==(h
+1)) return 2*w
+ h
- x
;
440 void make_paths(game_state
*state
) {
444 for (i
=0;i
<2*(state
->common
->params
.w
+ state
->common
->params
.h
);i
++) {
446 int j
,k
,num_monsters
;
450 /* Check whether inverse path is already in list */
451 for (j
=0;j
<count
;j
++) {
452 if (i
== state
->common
->paths
[j
].grid_end
) {
459 /* We found a new path through the mirror maze */
460 state
->common
->paths
[count
].grid_start
= i
;
461 dir
= range2grid(i
, state
->common
->params
.w
,
462 state
->common
->params
.h
,&x
,&y
);
463 state
->common
->paths
[count
].sightings_start
=
464 state
->common
->grid
[x
+y
*(state
->common
->params
.w
+2)];
468 if (dir
== DIRECTION_DOWN
) y
++;
469 else if (dir
== DIRECTION_LEFT
) x
--;
470 else if (dir
== DIRECTION_UP
) y
--;
471 else if (dir
== DIRECTION_RIGHT
) x
++;
473 r
= grid2range(x
, y
, state
->common
->params
.w
,
474 state
->common
->params
.h
);
476 state
->common
->paths
[count
].grid_end
= r
;
477 state
->common
->paths
[count
].sightings_end
=
478 state
->common
->grid
[x
+y
*(state
->common
->params
.w
+2)];
482 c
= state
->common
->grid
[x
+y
*(state
->common
->params
.w
+2)];
483 state
->common
->paths
[count
].xy
[state
->common
->paths
[count
].length
] =
484 x
+y
*(state
->common
->params
.w
+2);
485 if (c
== CELL_MIRROR_L
) {
486 state
->common
->paths
[count
].p
[state
->common
->paths
[count
].length
] = -1;
487 if (dir
== DIRECTION_DOWN
) dir
= DIRECTION_RIGHT
;
488 else if (dir
== DIRECTION_LEFT
) dir
= DIRECTION_UP
;
489 else if (dir
== DIRECTION_UP
) dir
= DIRECTION_LEFT
;
490 else if (dir
== DIRECTION_RIGHT
) dir
= DIRECTION_DOWN
;
492 else if (c
== CELL_MIRROR_R
) {
493 state
->common
->paths
[count
].p
[state
->common
->paths
[count
].length
] = -1;
494 if (dir
== DIRECTION_DOWN
) dir
= DIRECTION_LEFT
;
495 else if (dir
== DIRECTION_LEFT
) dir
= DIRECTION_DOWN
;
496 else if (dir
== DIRECTION_UP
) dir
= DIRECTION_RIGHT
;
497 else if (dir
== DIRECTION_RIGHT
) dir
= DIRECTION_UP
;
500 state
->common
->paths
[count
].p
[state
->common
->paths
[count
].length
] =
501 state
->common
->xinfo
[x
+y
*(state
->common
->params
.w
+2)];
503 state
->common
->paths
[count
].length
++;
505 /* Count unique monster entries in each path */
506 state
->common
->paths
[count
].num_monsters
= 0;
507 for (j
=0;j
<state
->common
->num_total
;j
++) {
509 for (k
=0;k
<state
->common
->paths
[count
].length
;k
++)
510 if (state
->common
->paths
[count
].p
[k
] == j
)
512 if (num_monsters
> 0)
513 state
->common
->paths
[count
].num_monsters
++;
516 /* Generate mapping vector */
518 for (p
=0;p
<state
->common
->paths
[count
].length
;p
++) {
520 m
= state
->common
->paths
[count
].p
[p
];
521 if (m
== -1) continue;
524 if (state
->common
->paths
[count
].mapping
[j
] == m
) found
= TRUE
;
525 if (!found
) state
->common
->paths
[count
].mapping
[c
++] = m
;
538 int next_list(struct guess
*g
, int pos
) {
541 if ((g
->guess
[pos
] == 1 && g
->possible
[pos
] == 1) ||
542 (g
->guess
[pos
] == 2 && (g
->possible
[pos
] == 3 ||
543 g
->possible
[pos
] == 2)) ||
546 if (g
->guess
[pos
] == 1 && (g
->possible
[pos
] == 3 ||
547 g
->possible
[pos
] == 7)) {
548 g
->guess
[pos
] = 2; return TRUE
;
550 if (g
->guess
[pos
] == 1 && g
->possible
[pos
] == 5) {
551 g
->guess
[pos
] = 4; return TRUE
;
553 if (g
->guess
[pos
] == 2 && (g
->possible
[pos
] == 6 || g
->possible
[pos
] == 7)) {
554 g
->guess
[pos
] = 4; return TRUE
;
558 if (g
->guess
[pos
] == 1) {
559 if (g
->possible
[pos
] == 1) {
560 return next_list(g
,pos
-1);
562 if (g
->possible
[pos
] == 3 || g
->possible
[pos
] == 7) {
563 g
->guess
[pos
] = 2; return TRUE
;
565 if (g
->possible
[pos
] == 5) {
566 g
->guess
[pos
] = 4; return TRUE
;
570 if (g
->guess
[pos
] == 2) {
571 if (g
->possible
[pos
] == 2) {
572 return next_list(g
,pos
-1);
574 if (g
->possible
[pos
] == 3) {
575 g
->guess
[pos
] = 1; return next_list(g
,pos
-1);
577 if (g
->possible
[pos
] == 6 || g
->possible
[pos
] == 7) {
578 g
->guess
[pos
] = 4; return TRUE
;
582 if (g
->guess
[pos
] == 4) {
583 if (g
->possible
[pos
] == 5 || g
->possible
[pos
] == 7) {
584 g
->guess
[pos
] = 1; return next_list(g
,pos
-1);
586 if (g
->possible
[pos
] == 6) {
587 g
->guess
[pos
] = 2; return next_list(g
,pos
-1);
589 if (g
->possible
[pos
] == 4) {
590 return next_list(g
,pos
-1);
596 void get_unique(game_state
*state
, int counter
, random_state
*rs
) {
598 int p
,i
,c
,pathlimit
,count_uniques
;
599 struct guess path_guess
;
612 } views
, single_views
, test_views
;
614 struct entry test_entry
;
616 path_guess
.length
= state
->common
->paths
[counter
].num_monsters
;
617 path_guess
.guess
= snewn(path_guess
.length
,int);
618 path_guess
.possible
= snewn(path_guess
.length
,int);
619 for (i
=0;i
<path_guess
.length
;i
++)
620 path_guess
.guess
[i
] = path_guess
.possible
[i
] = 0;
622 for (p
=0;p
<path_guess
.length
;p
++) {
623 path_guess
.possible
[p
] =
624 state
->guess
[state
->common
->paths
[counter
].mapping
[p
]];
625 switch (path_guess
.possible
[p
]) {
626 case 1: path_guess
.guess
[p
] = 1; break;
627 case 2: path_guess
.guess
[p
] = 2; break;
628 case 3: path_guess
.guess
[p
] = 1; break;
629 case 4: path_guess
.guess
[p
] = 4; break;
630 case 5: path_guess
.guess
[p
] = 1; break;
631 case 6: path_guess
.guess
[p
] = 2; break;
632 case 7: path_guess
.guess
[p
] = 1; break;
639 pathlimit
= state
->common
->paths
[counter
].length
+ 1;
640 view_count
= snewn(pathlimit
*pathlimit
, int);
641 for (i
= 0; i
< pathlimit
*pathlimit
; i
++)
645 int mirror
, start_view
, end_view
;
649 for (p
=0;p
<state
->common
->paths
[counter
].length
;p
++) {
650 if (state
->common
->paths
[counter
].p
[p
] == -1) mirror
= TRUE
;
652 for (i
=0;i
<path_guess
.length
;i
++) {
653 if (state
->common
->paths
[counter
].p
[p
] ==
654 state
->common
->paths
[counter
].mapping
[i
]) {
655 if (path_guess
.guess
[i
] == 1 && mirror
== TRUE
)
657 if (path_guess
.guess
[i
] == 2 && mirror
== FALSE
)
659 if (path_guess
.guess
[i
] == 4)
668 for (p
=state
->common
->paths
[counter
].length
-1;p
>=0;p
--) {
669 if (state
->common
->paths
[counter
].p
[p
] == -1) mirror
= TRUE
;
671 for (i
=0;i
<path_guess
.length
;i
++) {
672 if (state
->common
->paths
[counter
].p
[p
] ==
673 state
->common
->paths
[counter
].mapping
[i
]) {
674 if (path_guess
.guess
[i
] == 1 && mirror
== TRUE
)
676 if (path_guess
.guess
[i
] == 2 && mirror
== FALSE
)
678 if (path_guess
.guess
[i
] == 4)
686 assert(start_view
>= 0 && start_view
< pathlimit
);
687 assert(end_view
>= 0 && end_view
< pathlimit
);
688 i
= start_view
* pathlimit
+ end_view
;
690 if (view_count
[i
] == 1) {
691 views
.node
= snewn(1,struct entry
);
692 views
.node
->link
= views
.head
;
693 views
.node
->guess
= snewn(path_guess
.length
,int);
694 views
.head
= views
.node
;
695 views
.node
->start_view
= start_view
;
696 views
.node
->end_view
= end_view
;
697 memcpy(views
.node
->guess
, path_guess
.guess
,
698 path_guess
.length
*sizeof(int));
700 } while (next_list(&path_guess
, path_guess
.length
-1));
702 /* extract single entries from view list */
704 test_views
.head
= views
.head
;
705 test_views
.node
= views
.node
;
707 test_entry
.guess
= snewn(path_guess
.length
,int);
709 single_views
.head
= NULL
;
710 single_views
.node
= NULL
;
713 while (test_views
.head
!= NULL
) {
714 test_views
.node
= test_views
.head
;
715 test_views
.head
= test_views
.head
->link
;
716 i
= test_views
.node
->start_view
* pathlimit
+ test_views
.node
->end_view
;
717 if (view_count
[i
] == 1) {
718 single_views
.node
= snewn(1,struct entry
);
719 single_views
.node
->link
= single_views
.head
;
720 single_views
.node
->guess
= snewn(path_guess
.length
,int);
721 single_views
.head
= single_views
.node
;
722 single_views
.node
->start_view
= test_views
.node
->start_view
;
723 single_views
.node
->end_view
= test_views
.node
->end_view
;
724 memcpy(single_views
.node
->guess
, test_views
.node
->guess
,
725 path_guess
.length
*sizeof(int));
732 if (count_uniques
> 0) {
733 test_entry
.start_view
= 0;
734 test_entry
.end_view
= 0;
735 /* Choose one unique guess per random */
736 /* While we are busy with looping through single_views, we
737 * conveniently free the linked list single_view */
738 c
= random_upto(rs
,count_uniques
);
739 while(single_views
.head
!= NULL
) {
740 single_views
.node
= single_views
.head
;
741 single_views
.head
= single_views
.head
->link
;
743 memcpy(test_entry
.guess
, single_views
.node
->guess
,
744 path_guess
.length
*sizeof(int));
745 test_entry
.start_view
= single_views
.node
->start_view
;
746 test_entry
.end_view
= single_views
.node
->end_view
;
748 sfree(single_views
.node
->guess
);
749 sfree(single_views
.node
);
752 /* Modify state_guess according to path_guess.mapping */
753 for (i
=0;i
<path_guess
.length
;i
++)
754 state
->guess
[state
->common
->paths
[counter
].mapping
[i
]] =
758 sfree(test_entry
.guess
);
760 while (views
.head
!= NULL
) {
761 views
.node
= views
.head
;
762 views
.head
= views
.head
->link
;
763 sfree(views
.node
->guess
);
767 sfree(path_guess
.possible
);
768 sfree(path_guess
.guess
);
773 int count_monsters(game_state
*state
,
774 int *cGhost
, int *cVampire
, int *cZombie
) {
778 *cGhost
= *cVampire
= *cZombie
= cNone
= 0;
780 for (i
=0;i
<state
->common
->num_total
;i
++) {
781 if (state
->guess
[i
] == 1) (*cGhost
)++;
782 else if (state
->guess
[i
] == 2) (*cVampire
)++;
783 else if (state
->guess
[i
] == 4) (*cZombie
)++;
790 int check_numbers(game_state
*state
, int *guess
) {
793 int count_ghosts
, count_vampires
, count_zombies
;
795 count_ghosts
= count_vampires
= count_zombies
= 0;
796 for (i
=0;i
<state
->common
->num_total
;i
++) {
797 if (guess
[i
] == 1) count_ghosts
++;
798 if (guess
[i
] == 2) count_vampires
++;
799 if (guess
[i
] == 4) count_zombies
++;
804 if (count_ghosts
> state
->common
->num_ghosts
) valid
= FALSE
;
805 if (count_vampires
> state
->common
->num_vampires
) valid
= FALSE
;
806 if (count_zombies
> state
->common
->num_zombies
) valid
= FALSE
;
811 int check_solution(int *g
, struct path path
) {
818 for (i
=0;i
<path
.length
;i
++) {
819 if (path
.p
[i
] == -1) mirror
= TRUE
;
821 if (g
[path
.p
[i
]] == 1 && mirror
) count
++;
822 else if (g
[path
.p
[i
]] == 2 && !mirror
) count
++;
823 else if (g
[path
.p
[i
]] == 4) count
++;
826 if (count
!= path
.sightings_start
) return FALSE
;
830 for (i
=path
.length
-1;i
>=0;i
--) {
831 if (path
.p
[i
] == -1) mirror
= TRUE
;
833 if (g
[path
.p
[i
]] == 1 && mirror
) count
++;
834 else if (g
[path
.p
[i
]] == 2 && !mirror
) count
++;
835 else if (g
[path
.p
[i
]] == 4) count
++;
838 if (count
!= path
.sightings_end
) return FALSE
;
843 int solve_iterative(game_state
*state
, struct path
*paths
) {
853 loop
.length
= state
->common
->num_total
;
854 guess
= snewn(state
->common
->num_total
,int);
855 possible
= snewn(state
->common
->num_total
,int);
857 for (i
=0;i
<state
->common
->num_total
;i
++) {
858 guess
[i
] = state
->guess
[i
];
862 for (p
=0;p
<state
->common
->num_paths
;p
++) {
863 if (paths
[p
].num_monsters
> 0) {
864 loop
.length
= paths
[p
].num_monsters
;
865 loop
.guess
= snewn(paths
[p
].num_monsters
,int);
866 loop
.possible
= snewn(paths
[p
].num_monsters
,int);
868 for (i
=0;i
<paths
[p
].num_monsters
;i
++) {
869 switch (state
->guess
[paths
[p
].mapping
[i
]]) {
870 case 1: loop
.guess
[i
] = 1; break;
871 case 2: loop
.guess
[i
] = 2; break;
872 case 3: loop
.guess
[i
] = 1; break;
873 case 4: loop
.guess
[i
] = 4; break;
874 case 5: loop
.guess
[i
] = 1; break;
875 case 6: loop
.guess
[i
] = 2; break;
876 case 7: loop
.guess
[i
] = 1; break;
878 loop
.possible
[i
] = state
->guess
[paths
[p
].mapping
[i
]];
879 possible
[paths
[p
].mapping
[i
]] = 0;
883 for (i
=0;i
<state
->common
->num_total
;i
++) {
884 guess
[i
] = state
->guess
[i
];
887 for (i
=0;i
<paths
[p
].num_monsters
;i
++)
888 guess
[paths
[p
].mapping
[i
]] = loop
.guess
[count
++];
889 if (check_numbers(state
,guess
) &&
890 check_solution(guess
,paths
[p
]))
891 for (j
=0;j
<paths
[p
].num_monsters
;j
++)
892 possible
[paths
[p
].mapping
[j
]] |= loop
.guess
[j
];
893 if (!next_list(&loop
,loop
.length
-1)) break;
895 for (i
=0;i
<paths
[p
].num_monsters
;i
++)
896 state
->guess
[paths
[p
].mapping
[i
]] &=
897 possible
[paths
[p
].mapping
[i
]];
898 sfree(loop
.possible
);
903 for (i
=0;i
<state
->common
->num_total
;i
++) {
904 if (state
->guess
[i
] == 3 || state
->guess
[i
] == 5 ||
905 state
->guess
[i
] == 6 || state
->guess
[i
] == 7) {
906 solved
= FALSE
; break;
916 int solve_bruteforce(game_state
*state
, struct path
*paths
) {
918 int number_solutions
;
923 loop
.guess
= snewn(state
->common
->num_total
,int);
924 loop
.possible
= snewn(state
->common
->num_total
,int);
926 for (i
=0;i
<state
->common
->num_total
;i
++) {
927 loop
.possible
[i
] = state
->guess
[i
];
928 switch (state
->guess
[i
]) {
929 case 1: loop
.guess
[i
] = 1; break;
930 case 2: loop
.guess
[i
] = 2; break;
931 case 3: loop
.guess
[i
] = 1; break;
932 case 4: loop
.guess
[i
] = 4; break;
933 case 5: loop
.guess
[i
] = 1; break;
934 case 6: loop
.guess
[i
] = 2; break;
935 case 7: loop
.guess
[i
] = 1; break;
940 number_solutions
= 0;
945 if (!check_numbers(state
,loop
.guess
)) correct
= FALSE
;
947 for (p
=0;p
<state
->common
->num_paths
;p
++)
948 if (!check_solution(loop
.guess
,paths
[p
])) {
949 correct
= FALSE
; break;
954 if(number_solutions
> 1) {
958 for (i
=0;i
<state
->common
->num_total
;i
++)
959 state
->guess
[i
] = loop
.guess
[i
];
961 if (!next_list(&loop
,state
->common
->num_total
-1)) {
966 sfree(loop
.possible
);
972 int path_cmp(const void *a
, const void *b
) {
973 const struct path
*pa
= (const struct path
*)a
;
974 const struct path
*pb
= (const struct path
*)b
;
975 return pa
->num_monsters
- pb
->num_monsters
;
978 static char *new_game_desc(const game_params
*params
, random_state
*rs
,
979 char **aux
, int interactive
) {
980 int i
,count
,c
,w
,h
,r
,p
,g
;
983 /* Variables for puzzle generation algorithm */
986 int count_ghosts
, count_vampires
, count_zombies
;
990 /* Variables for solver algorithm */
991 int solved_iterative
, solved_bruteforce
, contains_inconsistency
,
996 /* Variables for game description generation */
1003 new = new_state(params
);
1006 /* Fill grid with random mirrors and (later to be populated)
1007 * empty monster cells */
1009 for (h
=1;h
<new->common
->params
.h
+1;h
++)
1010 for (w
=1;w
<new->common
->params
.w
+1;w
++) {
1011 c
= random_upto(rs
,5);
1013 new->common
->grid
[w
+h
*(new->common
->params
.w
+2)] = CELL_EMPTY
;
1014 new->common
->xinfo
[w
+h
*(new->common
->params
.w
+2)] = count
++;
1017 new->common
->grid
[w
+h
*(new->common
->params
.w
+2)] =
1019 new->common
->xinfo
[w
+h
*(new->common
->params
.w
+2)] = -1;
1022 new->common
->grid
[w
+h
*(new->common
->params
.w
+2)] =
1024 new->common
->xinfo
[w
+h
*(new->common
->params
.w
+2)] = -1;
1027 new->common
->num_total
= count
; /* Total number of monsters in maze */
1029 /* Puzzle is boring if it has too few monster cells. Discard
1030 * grid, make new grid */
1031 if (new->common
->num_total
<= 4) {
1036 /* Monsters / Mirrors ratio should be balanced */
1037 ratio
= (float)new->common
->num_total
/
1038 (float)(new->common
->params
.w
* new->common
->params
.h
);
1039 if (ratio
< 0.48 || ratio
> 0.78) {
1044 /* Assign clue identifiers */
1045 for (r
=0;r
<2*(new->common
->params
.w
+new->common
->params
.h
);r
++) {
1047 gridno
= range2grid(r
,new->common
->params
.w
,new->common
->params
.h
,
1049 new->common
->grid
[x
+y
*(new->common
->params
.w
+2)] = gridno
;
1050 new->common
->xinfo
[x
+y
*(new->common
->params
.w
+2)] = 0;
1052 /* The four corners don't matter at all for the game. Set them
1053 * all to zero, just to have a nice data structure */
1054 new->common
->grid
[0] = 0;
1055 new->common
->xinfo
[0] = 0;
1056 new->common
->grid
[new->common
->params
.w
+1] = 0;
1057 new->common
->xinfo
[new->common
->params
.w
+1] = 0;
1058 new->common
->grid
[new->common
->params
.w
+1 + (new->common
->params
.h
+1)*(new->common
->params
.w
+2)] = 0;
1059 new->common
->xinfo
[new->common
->params
.w
+1 + (new->common
->params
.h
+1)*(new->common
->params
.w
+2)] = 0;
1060 new->common
->grid
[(new->common
->params
.h
+1)*(new->common
->params
.w
+2)] = 0;
1061 new->common
->xinfo
[(new->common
->params
.h
+1)*(new->common
->params
.w
+2)] = 0;
1063 /* Initialize solution vector */
1064 new->guess
= snewn(new->common
->num_total
,int);
1065 for (g
=0;g
<new->common
->num_total
;g
++) new->guess
[g
] = 7;
1067 /* Initialize fixed flag from common. Not needed for the
1068 * puzzle generator; initialize it for having clean code */
1069 new->common
->fixed
= snewn(new->common
->num_total
,int);
1070 for (g
=0;g
<new->common
->num_total
;g
++)
1071 new->common
->fixed
[g
] = FALSE
;
1073 /* paths generation */
1076 /* Grid is invalid if max. path length > threshold. Discard
1077 * grid, make new one */
1078 switch (new->common
->params
.diff
) {
1079 case DIFF_EASY
: max_length
= min(new->common
->params
.w
,new->common
->params
.h
) + 1; break;
1080 case DIFF_NORMAL
: max_length
= (max(new->common
->params
.w
,new->common
->params
.h
) * 3) / 2; break;
1081 case DIFF_TRICKY
: max_length
= 9; break;
1082 default: max_length
= 9; break;
1085 for (p
=0;p
<new->common
->num_paths
;p
++) {
1086 if (new->common
->paths
[p
].num_monsters
> max_length
) {
1095 qsort(new->common
->paths
, new->common
->num_paths
,
1096 sizeof(struct path
), path_cmp
);
1098 /* Grid monster initialization */
1099 /* For easy puzzles, we try to fill nearly the whole grid
1100 with unique solution paths (up to 2) For more difficult
1101 puzzles, we fill only roughly half the grid, and choose
1102 random monsters for the rest For hard puzzles, we fill
1103 even less paths with unique solutions */
1105 switch (new->common
->params
.diff
) {
1106 case DIFF_EASY
: filling
= 2; break;
1107 case DIFF_NORMAL
: filling
= min( (new->common
->params
.w
+new->common
->params
.h
) , (new->common
->num_total
)/2 ); break;
1108 case DIFF_TRICKY
: filling
= max( (new->common
->params
.w
+new->common
->params
.h
) , (new->common
->num_total
)/2 ); break;
1109 default: filling
= 0; break;
1113 while ( (count_monsters(new, &count_ghosts
, &count_vampires
,
1114 &count_zombies
)) > filling
) {
1115 if ((count
) >= new->common
->num_paths
) break;
1116 if (new->common
->paths
[count
].num_monsters
== 0) {
1120 get_unique(new,count
,rs
);
1124 /* Fill any remaining ambiguous entries with random monsters */
1125 for(g
=0;g
<new->common
->num_total
;g
++) {
1126 if (new->guess
[g
] == 7) {
1127 r
= random_upto(rs
,3);
1128 new->guess
[g
] = (r
== 0) ? 1 : ( (r
== 1) ? 2 : 4 );
1132 /* Determine all hints */
1133 count_monsters(new, &new->common
->num_ghosts
,
1134 &new->common
->num_vampires
, &new->common
->num_zombies
);
1136 /* Puzzle is trivial if it has only one type of monster. Discard. */
1137 if ((new->common
->num_ghosts
== 0 && new->common
->num_vampires
== 0) ||
1138 (new->common
->num_ghosts
== 0 && new->common
->num_zombies
== 0) ||
1139 (new->common
->num_vampires
== 0 && new->common
->num_zombies
== 0)) {
1144 /* Discard puzzle if difficulty Tricky, and it has only 1
1145 * member of any monster type */
1146 if (new->common
->params
.diff
== DIFF_TRICKY
&&
1147 (new->common
->num_ghosts
<= 1 ||
1148 new->common
->num_vampires
<= 1 || new->common
->num_zombies
<= 1)) {
1153 for (w
=1;w
<new->common
->params
.w
+1;w
++)
1154 for (h
=1;h
<new->common
->params
.h
+1;h
++) {
1155 c
= new->common
->xinfo
[w
+h
*(new->common
->params
.w
+2)];
1157 if (new->guess
[c
] == 1) new->common
->grid
[w
+h
*(new->common
->params
.w
+2)] = CELL_GHOST
;
1158 if (new->guess
[c
] == 2) new->common
->grid
[w
+h
*(new->common
->params
.w
+2)] = CELL_VAMPIRE
;
1159 if (new->guess
[c
] == 4) new->common
->grid
[w
+h
*(new->common
->params
.w
+2)] = CELL_ZOMBIE
;
1163 /* Prepare path information needed by the solver (containing all hints) */
1164 for (p
=0;p
<new->common
->num_paths
;p
++) {
1167 new->common
->paths
[p
].sightings_start
= 0;
1168 new->common
->paths
[p
].sightings_end
= 0;
1171 for (g
=0;g
<new->common
->paths
[p
].length
;g
++) {
1173 if (new->common
->paths
[p
].p
[g
] == -1) mirror
= TRUE
;
1175 if (new->guess
[new->common
->paths
[p
].p
[g
]] == 1 && mirror
== TRUE
) (new->common
->paths
[p
].sightings_start
)++;
1176 else if (new->guess
[new->common
->paths
[p
].p
[g
]] == 2 && mirror
== FALSE
) (new->common
->paths
[p
].sightings_start
)++;
1177 else if (new->guess
[new->common
->paths
[p
].p
[g
]] == 4) (new->common
->paths
[p
].sightings_start
)++;
1182 for (g
=new->common
->paths
[p
].length
-1;g
>=0;g
--) {
1183 if (new->common
->paths
[p
].p
[g
] == -1) mirror
= TRUE
;
1185 if (new->guess
[new->common
->paths
[p
].p
[g
]] == 1 && mirror
== TRUE
) (new->common
->paths
[p
].sightings_end
)++;
1186 else if (new->guess
[new->common
->paths
[p
].p
[g
]] == 2 && mirror
== FALSE
) (new->common
->paths
[p
].sightings_end
)++;
1187 else if (new->guess
[new->common
->paths
[p
].p
[g
]] == 4) (new->common
->paths
[p
].sightings_end
)++;
1191 range2grid(new->common
->paths
[p
].grid_start
,
1192 new->common
->params
.w
,new->common
->params
.h
,&x
,&y
);
1193 new->common
->grid
[x
+y
*(new->common
->params
.w
+2)] =
1194 new->common
->paths
[p
].sightings_start
;
1195 range2grid(new->common
->paths
[p
].grid_end
,
1196 new->common
->params
.w
,new->common
->params
.h
,&x
,&y
);
1197 new->common
->grid
[x
+y
*(new->common
->params
.w
+2)] =
1198 new->common
->paths
[p
].sightings_end
;
1201 /* Try to solve the puzzle with the iterative solver */
1202 old_guess
= snewn(new->common
->num_total
,int);
1203 for (p
=0;p
<new->common
->num_total
;p
++) {
1207 iterative_depth
= 0;
1208 solved_iterative
= FALSE
;
1209 contains_inconsistency
= FALSE
;
1210 count_ambiguous
= 0;
1215 solved_iterative
= solve_iterative(new,new->common
->paths
);
1217 for (p
=0;p
<new->common
->num_total
;p
++) {
1218 if (new->guess
[p
] != old_guess
[p
]) no_change
= FALSE
;
1219 old_guess
[p
] = new->guess
[p
];
1220 if (new->guess
[p
] == 0) contains_inconsistency
= TRUE
;
1222 if (solved_iterative
|| no_change
) break;
1225 /* If necessary, try to solve the puzzle with the brute-force solver */
1226 solved_bruteforce
= FALSE
;
1227 if (new->common
->params
.diff
!= DIFF_EASY
&&
1228 !solved_iterative
&& !contains_inconsistency
) {
1229 for (p
=0;p
<new->common
->num_total
;p
++)
1230 if (new->guess
[p
] != 1 && new->guess
[p
] != 2 &&
1231 new->guess
[p
] != 4) count_ambiguous
++;
1233 solved_bruteforce
= solve_bruteforce(new, new->common
->paths
);
1236 /* Determine puzzle difficulty level */
1237 if (new->common
->params
.diff
== DIFF_EASY
&& solved_iterative
&&
1238 iterative_depth
<= 3 && !contains_inconsistency
) {
1239 /* printf("Puzzle level: EASY Level %d Ratio %f Ambiguous %d (Found after %i tries)\n",iterative_depth, ratio, count_ambiguous, i); */
1243 if (new->common
->params
.diff
== DIFF_NORMAL
&&
1244 ((solved_iterative
&& iterative_depth
> 3) ||
1245 (solved_bruteforce
&& count_ambiguous
< 4)) &&
1246 !contains_inconsistency
) {
1247 /* printf("Puzzle level: NORMAL Level %d Ratio %f Ambiguous %d (Found after %d tries)\n", iterative_depth, ratio, count_ambiguous, i); */
1250 if (new->common
->params
.diff
== DIFF_TRICKY
&&
1251 solved_bruteforce
&& iterative_depth
> 0 &&
1252 count_ambiguous
>= 4 && !contains_inconsistency
) {
1253 /* printf("Puzzle level: TRICKY Level %d Ratio %f Ambiguous %d (Found after %d tries)\n", iterative_depth, ratio, count_ambiguous, i); */
1257 /* If puzzle is not solvable or does not satisfy the desired
1258 * difficulty level, free memory and start from scratch */
1264 /* We have a valid puzzle! */
1266 desc
= snewn(10 + new->common
->wh
+
1267 6*(new->common
->params
.w
+ new->common
->params
.h
), char);
1270 /* Encode monster counts */
1271 e
+= sprintf(e
, "%d,", new->common
->num_ghosts
);
1272 e
+= sprintf(e
, "%d,", new->common
->num_vampires
);
1273 e
+= sprintf(e
, "%d,", new->common
->num_zombies
);
1277 for (y
=1;y
<new->common
->params
.h
+1;y
++)
1278 for (x
=1;x
<new->common
->params
.w
+1;x
++) {
1279 c
= new->common
->grid
[x
+y
*(new->common
->params
.w
+2)];
1284 if (c
!= CELL_MIRROR_L
&& c
!= CELL_MIRROR_R
) {
1287 else if (c
== CELL_MIRROR_L
) {
1288 if (count
> 0) *e
++ = (count
-1 + 'a');
1293 if (count
> 0) *e
++ = (count
-1 + 'a');
1298 if (count
> 0) *e
++ = (count
-1 + 'a');
1301 for (p
=0;p
<2*(new->common
->params
.w
+ new->common
->params
.h
);p
++) {
1302 range2grid(p
,new->common
->params
.w
,new->common
->params
.h
,&x
,&y
);
1303 e
+= sprintf(e
, ",%d", new->common
->grid
[x
+y
*(new->common
->params
.w
+2)]);
1307 desc
= sresize(desc
, e
- desc
, char);
1315 void num2grid(int num
, int width
, int height
, int *x
, int *y
) {
1321 static game_state
*new_game(midend
*me
, const game_params
*params
,
1328 game_state
*state
= new_state(params
);
1330 state
->common
->num_ghosts
= atoi(desc
);
1331 while (*desc
&& isdigit((unsigned char)*desc
)) desc
++;
1333 state
->common
->num_vampires
= atoi(desc
);
1334 while (*desc
&& isdigit((unsigned char)*desc
)) desc
++;
1336 state
->common
->num_zombies
= atoi(desc
);
1337 while (*desc
&& isdigit((unsigned char)*desc
)) desc
++;
1340 state
->common
->num_total
= state
->common
->num_ghosts
+ state
->common
->num_vampires
+ state
->common
->num_zombies
;
1342 state
->guess
= snewn(state
->common
->num_total
,int);
1343 state
->pencils
= snewn(state
->common
->num_total
,unsigned char);
1344 state
->common
->fixed
= snewn(state
->common
->num_total
,int);
1345 for (i
=0;i
<state
->common
->num_total
;i
++) {
1346 state
->guess
[i
] = 7;
1347 state
->pencils
[i
] = 0;
1348 state
->common
->fixed
[i
] = FALSE
;
1350 for (i
=0;i
<state
->common
->wh
;i
++)
1351 state
->cell_errors
[i
] = FALSE
;
1352 for (i
=0;i
<2*state
->common
->num_paths
;i
++)
1353 state
->hint_errors
[i
] = FALSE
;
1355 state
->count_errors
[i
] = FALSE
;
1359 while (*desc
!= ',') {
1364 num2grid(n
,state
->common
->params
.w
,state
->common
->params
.h
,&x
,&y
);
1365 state
->common
->grid
[x
+y
*(state
->common
->params
.w
+2)] = CELL_MIRROR_L
;
1366 state
->common
->xinfo
[x
+y
*(state
->common
->params
.w
+2)] = -1;
1369 else if (*desc
== 'R') {
1370 num2grid(n
,state
->common
->params
.w
,state
->common
->params
.h
,&x
,&y
);
1371 state
->common
->grid
[x
+y
*(state
->common
->params
.w
+2)] = CELL_MIRROR_R
;
1372 state
->common
->xinfo
[x
+y
*(state
->common
->params
.w
+2)] = -1;
1375 else if (*desc
== 'G') {
1376 num2grid(n
,state
->common
->params
.w
,state
->common
->params
.h
,&x
,&y
);
1377 state
->common
->grid
[x
+y
*(state
->common
->params
.w
+2)] = CELL_GHOST
;
1378 state
->common
->xinfo
[x
+y
*(state
->common
->params
.w
+2)] = count
;
1379 state
->guess
[count
] = 1;
1380 state
->common
->fixed
[count
++] = TRUE
;
1383 else if (*desc
== 'V') {
1384 num2grid(n
,state
->common
->params
.w
,state
->common
->params
.h
,&x
,&y
);
1385 state
->common
->grid
[x
+y
*(state
->common
->params
.w
+2)] = CELL_VAMPIRE
;
1386 state
->common
->xinfo
[x
+y
*(state
->common
->params
.w
+2)] = count
;
1387 state
->guess
[count
] = 2;
1388 state
->common
->fixed
[count
++] = TRUE
;
1391 else if (*desc
== 'Z') {
1392 num2grid(n
,state
->common
->params
.w
,state
->common
->params
.h
,&x
,&y
);
1393 state
->common
->grid
[x
+y
*(state
->common
->params
.w
+2)] = CELL_ZOMBIE
;
1394 state
->common
->xinfo
[x
+y
*(state
->common
->params
.w
+2)] = count
;
1395 state
->guess
[count
] = 4;
1396 state
->common
->fixed
[count
++] = TRUE
;
1400 c
= *desc
- ('a' -1);
1402 num2grid(n
,state
->common
->params
.w
,state
->common
->params
.h
,&x
,&y
);
1403 state
->common
->grid
[x
+y
*(state
->common
->params
.w
+2)] = CELL_EMPTY
;
1404 state
->common
->xinfo
[x
+y
*(state
->common
->params
.w
+2)] = count
;
1405 state
->guess
[count
] = 7;
1406 state
->common
->fixed
[count
++] = FALSE
;
1414 for (i
=0;i
<2*(state
->common
->params
.w
+ state
->common
->params
.h
);i
++) {
1418 sights
= atoi(desc
);
1419 while (*desc
&& isdigit((unsigned char)*desc
)) desc
++;
1423 range2grid(i
,state
->common
->params
.w
,state
->common
->params
.h
,&x
,&y
);
1424 state
->common
->grid
[x
+y
*(state
->common
->params
.w
+2)] = sights
;
1425 state
->common
->xinfo
[x
+y
*(state
->common
->params
.w
+2)] = -2;
1428 state
->common
->grid
[0] = 0;
1429 state
->common
->xinfo
[0] = -2;
1430 state
->common
->grid
[state
->common
->params
.w
+1] = 0;
1431 state
->common
->xinfo
[state
->common
->params
.w
+1] = -2;
1432 state
->common
->grid
[state
->common
->params
.w
+1 + (state
->common
->params
.h
+1)*(state
->common
->params
.w
+2)] = 0;
1433 state
->common
->xinfo
[state
->common
->params
.w
+1 + (state
->common
->params
.h
+1)*(state
->common
->params
.w
+2)] = -2;
1434 state
->common
->grid
[(state
->common
->params
.h
+1)*(state
->common
->params
.w
+2)] = 0;
1435 state
->common
->xinfo
[(state
->common
->params
.h
+1)*(state
->common
->params
.w
+2)] = -2;
1438 qsort(state
->common
->paths
, state
->common
->num_paths
, sizeof(struct path
), path_cmp
);
1443 static char *validate_desc(const game_params
*params
, const char *desc
)
1446 int w
= params
->w
, h
= params
->h
;
1451 const char *desc_s
= desc
;
1454 if (!*desc
) return "Faulty game description";
1455 while (*desc
&& isdigit((unsigned char)*desc
)) { desc
++; }
1456 if (*desc
!= ',') return "Invalid character in number list";
1461 area
= monsters
= monster_count
= 0;
1463 monster_count
+= atoi(desc
);
1464 while (*desc
&& isdigit((unsigned char)*desc
)) desc
++;
1467 while (*desc
&& *desc
!= ',') {
1468 if (*desc
>= 'a' && *desc
<= 'z') {
1469 area
+= *desc
- 'a' +1; monsters
+= *desc
- 'a' +1;
1470 } else if (*desc
== 'G' || *desc
== 'V' || *desc
== 'Z') {
1472 } else if (*desc
== 'L' || *desc
== 'R') {
1475 return "Invalid character in grid specification";
1478 if (area
< wh
) return "Not enough data to fill grid";
1479 else if (area
> wh
) return "Too much data to fill grid";
1480 if (monsters
!= monster_count
)
1481 return "Monster numbers do not match grid spaces";
1483 for (i
= 0; i
< 2*(w
+h
); i
++) {
1484 if (!*desc
) return "Not enough numbers given after grid specification";
1485 else if (*desc
!= ',') return "Invalid character in number list";
1487 while (*desc
&& isdigit((unsigned char)*desc
)) { desc
++; }
1490 if (*desc
) return "Unexpected additional data at end of game description";
1495 static char *solve_game(const game_state
*state_start
, const game_state
*currstate
,
1496 const char *aux
, char **error
)
1500 int iterative_depth
;
1501 int solved_iterative
, solved_bruteforce
, contains_inconsistency
,
1507 game_state
*solve_state
= dup_game(currstate
);
1509 old_guess
= snewn(solve_state
->common
->num_total
,int);
1510 for (p
=0;p
<solve_state
->common
->num_total
;p
++) {
1511 if (solve_state
->common
->fixed
[p
]) {
1512 old_guess
[p
] = solve_state
->guess
[p
] = state_start
->guess
[p
];
1515 old_guess
[p
] = solve_state
->guess
[p
] = 7;
1518 iterative_depth
= 0;
1519 solved_iterative
= FALSE
;
1520 contains_inconsistency
= FALSE
;
1521 count_ambiguous
= 0;
1523 /* Try to solve the puzzle with the iterative solver */
1528 solve_iterative(solve_state
,solve_state
->common
->paths
);
1530 for (p
=0;p
<solve_state
->common
->num_total
;p
++) {
1531 if (solve_state
->guess
[p
] != old_guess
[p
]) no_change
= FALSE
;
1532 old_guess
[p
] = solve_state
->guess
[p
];
1533 if (solve_state
->guess
[p
] == 0) contains_inconsistency
= TRUE
;
1535 if (solved_iterative
|| no_change
|| contains_inconsistency
) break;
1538 if (contains_inconsistency
) {
1539 *error
= "Puzzle is inconsistent";
1541 free_game(solve_state
);
1545 /* If necessary, try to solve the puzzle with the brute-force solver */
1546 solved_bruteforce
= FALSE
;
1547 if (!solved_iterative
) {
1548 for (p
=0;p
<solve_state
->common
->num_total
;p
++)
1549 if (solve_state
->guess
[p
] != 1 && solve_state
->guess
[p
] != 2 &&
1550 solve_state
->guess
[p
] != 4) count_ambiguous
++;
1552 solve_bruteforce(solve_state
, solve_state
->common
->paths
);
1555 if (!solved_iterative
&& !solved_bruteforce
) {
1556 *error
= "Puzzle is unsolvable";
1558 free_game(solve_state
);
1562 /* printf("Puzzle solved at level %s, iterations %d, ambiguous %d\n", (solved_bruteforce ? "TRICKY" : "NORMAL"), iterative_depth, count_ambiguous); */
1564 move
= snewn(solve_state
->common
->num_total
* 4 +2, char);
1567 for (i
= 0; i
< solve_state
->common
->num_total
; i
++) {
1568 if (solve_state
->guess
[i
] == 1) c
+= sprintf(c
, ";G%d", i
);
1569 if (solve_state
->guess
[i
] == 2) c
+= sprintf(c
, ";V%d", i
);
1570 if (solve_state
->guess
[i
] == 4) c
+= sprintf(c
, ";Z%d", i
);
1573 move
= sresize(move
, c
- move
, char);
1576 free_game(solve_state
);
1580 static int game_can_format_as_text_now(const game_params
*params
)
1585 static char *game_text_format(const game_state
*state
)
1591 ret
= snewn(50 + 6*(state
->common
->params
.w
+2) +
1592 6*(state
->common
->params
.h
+2) +
1593 3*(state
->common
->params
.w
* state
->common
->params
.h
), char);
1595 sprintf(ret
,"G: %d V: %d Z: %d\n\n",state
->common
->num_ghosts
,
1596 state
->common
->num_vampires
, state
->common
->num_zombies
);
1598 for (h
=0;h
<state
->common
->params
.h
+2;h
++) {
1599 for (w
=0;w
<state
->common
->params
.w
+2;w
++) {
1600 c
= state
->common
->grid
[w
+h
*(state
->common
->params
.w
+2)];
1601 xi
= state
->common
->xinfo
[w
+h
*(state
->common
->params
.w
+2)];
1602 r
= grid2range(w
,h
,state
->common
->params
.w
,state
->common
->params
.h
);
1604 sprintf(buf
,"%2d", c
); strcat(ret
,buf
);
1605 } else if (c
== CELL_MIRROR_L
) {
1606 sprintf(buf
," \\"); strcat(ret
,buf
);
1607 } else if (c
== CELL_MIRROR_R
) {
1608 sprintf(buf
," /"); strcat(ret
,buf
);
1609 } else if (xi
>= 0) {
1610 g
= state
->guess
[xi
];
1611 if (g
== 1) { sprintf(buf
," G"); strcat(ret
,buf
); }
1612 else if (g
== 2) { sprintf(buf
," V"); strcat(ret
,buf
); }
1613 else if (g
== 4) { sprintf(buf
," Z"); strcat(ret
,buf
); }
1614 else { sprintf(buf
," ."); strcat(ret
,buf
); }
1616 sprintf(buf
," "); strcat(ret
,buf
);
1619 sprintf(buf
,"\n"); strcat(ret
,buf
);
1626 int hx
, hy
; /* as for solo.c, highlight pos */
1627 int hshow
, hpencil
, hcursor
; /* show state, type, and ?cursor. */
1631 static game_ui
*new_ui(const game_state
*state
)
1633 game_ui
*ui
= snew(game_ui
);
1634 ui
->hx
= ui
->hy
= 0;
1635 ui
->hpencil
= ui
->hshow
= ui
->hcursor
= 0;
1640 static void free_ui(game_ui
*ui
) {
1645 static char *encode_ui(const game_ui
*ui
)
1650 static void decode_ui(game_ui
*ui
, const char *encoding
)
1655 static void game_changed_state(game_ui
*ui
, const game_state
*oldstate
,
1656 const game_state
*newstate
)
1658 /* See solo.c; if we were pencil-mode highlighting and
1659 * somehow a square has just been properly filled, cancel
1661 if (ui
->hshow
&& ui
->hpencil
&& !ui
->hcursor
) {
1662 int g
= newstate
->guess
[newstate
->common
->xinfo
[ui
->hx
+ ui
->hy
*(newstate
->common
->params
.w
+2)]];
1663 if (g
== 1 || g
== 2 || g
== 4)
1668 struct game_drawstate
{
1669 int tilesize
, started
, solved
;
1673 unsigned char *pencils
;
1675 unsigned char count_errors
[3];
1676 unsigned char *cell_errors
;
1677 unsigned char *hint_errors
;
1678 unsigned char *hints_done
;
1680 int hx
, hy
, hshow
, hpencil
; /* as for game_ui. */
1685 static int is_clue(const game_state
*state
, int x
, int y
)
1687 int h
= state
->common
->params
.h
, w
= state
->common
->params
.w
;
1689 if (((x
== 0 || x
== w
+ 1) && y
> 0 && y
<= h
) ||
1690 ((y
== 0 || y
== h
+ 1) && x
> 0 && x
<= w
))
1696 static int clue_index(const game_state
*state
, int x
, int y
)
1698 int h
= state
->common
->params
.h
, w
= state
->common
->params
.w
;
1702 else if (x
== w
+ 1)
1704 else if (y
== h
+ 1)
1705 return 2 * w
+ h
- x
;
1707 return 2 * (w
+ h
) - y
;
1712 #define TILESIZE (ds->tilesize)
1713 #define BORDER (TILESIZE/4)
1715 static char *interpret_move(const game_state
*state
, game_ui
*ui
,
1716 const game_drawstate
*ds
,
1717 int x
, int y
, int button
)
1723 gx
= ((x
-BORDER
-1) / TILESIZE
);
1724 gy
= ((y
-BORDER
-2) / TILESIZE
) - 1;
1726 if (button
== 'a' || button
== 'A') {
1727 ui
->ascii
= !ui
->ascii
;
1731 if (button
== 'm' || button
== 'M') {
1735 if (ui
->hshow
== 1 && ui
->hpencil
== 0) {
1736 xi
= state
->common
->xinfo
[ui
->hx
+ ui
->hy
*(state
->common
->params
.w
+2)];
1737 if (xi
>= 0 && !state
->common
->fixed
[xi
]) {
1738 if (button
== 'g' || button
== 'G' || button
== '1') {
1739 if (!ui
->hcursor
) ui
->hshow
= 0;
1740 sprintf(buf
,"G%d",xi
);
1743 if (button
== 'v' || button
== 'V' || button
== '2') {
1744 if (!ui
->hcursor
) ui
->hshow
= 0;
1745 sprintf(buf
,"V%d",xi
);
1748 if (button
== 'z' || button
== 'Z' || button
== '3') {
1749 if (!ui
->hcursor
) ui
->hshow
= 0;
1750 sprintf(buf
,"Z%d",xi
);
1753 if (button
== 'e' || button
== 'E' || button
== CURSOR_SELECT2
||
1754 button
== '0' || button
== '\b' ) {
1755 if (!ui
->hcursor
) ui
->hshow
= 0;
1756 sprintf(buf
,"E%d",xi
);
1762 if (IS_CURSOR_MOVE(button
)) {
1763 if (ui
->hx
== 0 && ui
->hy
== 0) {
1767 else switch (button
) {
1768 case CURSOR_UP
: ui
->hy
-= (ui
->hy
> 1) ? 1 : 0; break;
1769 case CURSOR_DOWN
: ui
->hy
+= (ui
->hy
< ds
->h
) ? 1 : 0; break;
1770 case CURSOR_RIGHT
: ui
->hx
+= (ui
->hx
< ds
->w
) ? 1 : 0; break;
1771 case CURSOR_LEFT
: ui
->hx
-= (ui
->hx
> 1) ? 1 : 0; break;
1773 ui
->hshow
= ui
->hcursor
= 1;
1776 if (ui
->hshow
&& button
== CURSOR_SELECT
) {
1777 ui
->hpencil
= 1 - ui
->hpencil
;
1782 if (ui
->hshow
== 1 && ui
->hpencil
== 1) {
1783 xi
= state
->common
->xinfo
[ui
->hx
+ ui
->hy
*(state
->common
->params
.w
+2)];
1784 if (xi
>= 0 && !state
->common
->fixed
[xi
]) {
1785 if (button
== 'g' || button
== 'G' || button
== '1') {
1786 sprintf(buf
,"g%d",xi
);
1787 if (!ui
->hcursor
) ui
->hpencil
= ui
->hshow
= 0;
1790 if (button
== 'v' || button
== 'V' || button
== '2') {
1791 sprintf(buf
,"v%d",xi
);
1792 if (!ui
->hcursor
) ui
->hpencil
= ui
->hshow
= 0;
1795 if (button
== 'z' || button
== 'Z' || button
== '3') {
1796 sprintf(buf
,"z%d",xi
);
1797 if (!ui
->hcursor
) ui
->hpencil
= ui
->hshow
= 0;
1800 if (button
== 'e' || button
== 'E' || button
== CURSOR_SELECT2
||
1801 button
== '0' || button
== '\b') {
1802 sprintf(buf
,"E%d",xi
);
1803 if (!ui
->hcursor
) ui
->hpencil
= ui
->hshow
= 0;
1809 if (gx
> 0 && gx
< ds
->w
+1 && gy
> 0 && gy
< ds
->h
+1) {
1810 xi
= state
->common
->xinfo
[gx
+gy
*(state
->common
->params
.w
+2)];
1811 if (xi
>= 0 && !state
->common
->fixed
[xi
]) {
1812 g
= state
->guess
[xi
];
1813 if (ui
->hshow
== 0) {
1814 if (button
== LEFT_BUTTON
) {
1815 ui
->hshow
= 1; ui
->hpencil
= 0; ui
->hcursor
= 0;
1816 ui
->hx
= gx
; ui
->hy
= gy
;
1819 else if (button
== RIGHT_BUTTON
&& g
== 7) {
1820 ui
->hshow
= 1; ui
->hpencil
= 1; ui
->hcursor
= 0;
1821 ui
->hx
= gx
; ui
->hy
= gy
;
1825 else if (ui
->hshow
== 1) {
1826 if (button
== LEFT_BUTTON
) {
1827 if (ui
->hpencil
== 0) {
1828 if (gx
== ui
->hx
&& gy
== ui
->hy
) {
1829 ui
->hshow
= 0; ui
->hpencil
= 0; ui
->hcursor
= 0;
1830 ui
->hx
= 0; ui
->hy
= 0;
1834 ui
->hshow
= 1; ui
->hpencil
= 0; ui
->hcursor
= 0;
1835 ui
->hx
= gx
; ui
->hy
= gy
;
1840 ui
->hshow
= 1; ui
->hpencil
= 0; ui
->hcursor
= 0;
1841 ui
->hx
= gx
; ui
->hy
= gy
;
1845 else if (button
== RIGHT_BUTTON
) {
1846 if (ui
->hpencil
== 0 && g
== 7) {
1847 ui
->hshow
= 1; ui
->hpencil
= 1; ui
->hcursor
= 0;
1848 ui
->hx
= gx
; ui
->hy
= gy
;
1852 if (gx
== ui
->hx
&& gy
== ui
->hy
) {
1853 ui
->hshow
= 0; ui
->hpencil
= 0; ui
->hcursor
= 0;
1854 ui
->hx
= 0; ui
->hy
= 0;
1858 ui
->hshow
= 1; ui
->hpencil
= 1; ui
->hcursor
= 0;
1859 ui
->hx
= gx
; ui
->hy
= gy
;
1866 } else if (button
== LEFT_BUTTON
) {
1867 if (is_clue(state
, gx
, gy
)) {
1868 sprintf(buf
, "D%d,%d", gx
, gy
);
1876 int check_numbers_draw(game_state
*state
, int *guess
) {
1879 int count_ghosts
, count_vampires
, count_zombies
;
1881 count_ghosts
= count_vampires
= count_zombies
= 0;
1882 for (i
=0;i
<state
->common
->num_total
;i
++) {
1883 if (guess
[i
] == 1) count_ghosts
++;
1884 if (guess
[i
] == 2) count_vampires
++;
1885 if (guess
[i
] == 4) count_zombies
++;
1889 filled
= (count_ghosts
+ count_vampires
+ count_zombies
>=
1890 state
->common
->num_total
);
1892 if (count_ghosts
> state
->common
->num_ghosts
||
1893 (filled
&& count_ghosts
!= state
->common
->num_ghosts
) ) {
1895 state
->count_errors
[0] = TRUE
;
1896 for (x
=1;x
<state
->common
->params
.w
+1;x
++)
1897 for (y
=1;y
<state
->common
->params
.h
+1;y
++) {
1898 xy
= x
+y
*(state
->common
->params
.w
+2);
1899 if (state
->common
->xinfo
[xy
] >= 0 &&
1900 guess
[state
->common
->xinfo
[xy
]] == 1)
1901 state
->cell_errors
[xy
] = TRUE
;
1904 if (count_vampires
> state
->common
->num_vampires
||
1905 (filled
&& count_vampires
!= state
->common
->num_vampires
) ) {
1907 state
->count_errors
[1] = TRUE
;
1908 for (x
=1;x
<state
->common
->params
.w
+1;x
++)
1909 for (y
=1;y
<state
->common
->params
.h
+1;y
++) {
1910 xy
= x
+y
*(state
->common
->params
.w
+2);
1911 if (state
->common
->xinfo
[xy
] >= 0 &&
1912 guess
[state
->common
->xinfo
[xy
]] == 2)
1913 state
->cell_errors
[xy
] = TRUE
;
1916 if (count_zombies
> state
->common
->num_zombies
||
1917 (filled
&& count_zombies
!= state
->common
->num_zombies
) ) {
1919 state
->count_errors
[2] = TRUE
;
1920 for (x
=1;x
<state
->common
->params
.w
+1;x
++)
1921 for (y
=1;y
<state
->common
->params
.h
+1;y
++) {
1922 xy
= x
+y
*(state
->common
->params
.w
+2);
1923 if (state
->common
->xinfo
[xy
] >= 0 &&
1924 guess
[state
->common
->xinfo
[xy
]] == 4)
1925 state
->cell_errors
[xy
] = TRUE
;
1932 int check_path_solution(game_state
*state
, int p
) {
1944 for (i
=0;i
<state
->common
->paths
[p
].length
;i
++) {
1945 if (state
->common
->paths
[p
].p
[i
] == -1) mirror
= TRUE
;
1947 if (state
->guess
[state
->common
->paths
[p
].p
[i
]] == 1 && mirror
)
1949 else if (state
->guess
[state
->common
->paths
[p
].p
[i
]] == 2 && !mirror
)
1951 else if (state
->guess
[state
->common
->paths
[p
].p
[i
]] == 4)
1953 else if (state
->guess
[state
->common
->paths
[p
].p
[i
]] == 7)
1958 if (count
> state
->common
->paths
[p
].sightings_start
||
1959 count
+ unfilled
< state
->common
->paths
[p
].sightings_start
)
1962 state
->hint_errors
[state
->common
->paths
[p
].grid_start
] = TRUE
;
1968 for (i
=state
->common
->paths
[p
].length
-1;i
>=0;i
--) {
1969 if (state
->common
->paths
[p
].p
[i
] == -1) mirror
= TRUE
;
1971 if (state
->guess
[state
->common
->paths
[p
].p
[i
]] == 1 && mirror
)
1973 else if (state
->guess
[state
->common
->paths
[p
].p
[i
]] == 2 && !mirror
)
1975 else if (state
->guess
[state
->common
->paths
[p
].p
[i
]] == 4)
1977 else if (state
->guess
[state
->common
->paths
[p
].p
[i
]] == 7)
1982 if (count
> state
->common
->paths
[p
].sightings_end
||
1983 count
+ unfilled
< state
->common
->paths
[p
].sightings_end
)
1986 state
->hint_errors
[state
->common
->paths
[p
].grid_end
] = TRUE
;
1990 for (i
=0;i
<state
->common
->paths
[p
].length
;i
++)
1991 state
->cell_errors
[state
->common
->paths
[p
].xy
[i
]] = TRUE
;
1997 static game_state
*execute_move(const game_state
*state
, const char *move
)
2004 game_state
*ret
= dup_game(state
);
2013 if (c
== 'G' || c
== 'V' || c
== 'Z' || c
== 'E' ||
2014 c
== 'g' || c
== 'v' || c
== 'z') {
2016 sscanf(move
, "%d%n", &x
, &n
);
2017 if (c
== 'G') ret
->guess
[x
] = 1;
2018 if (c
== 'V') ret
->guess
[x
] = 2;
2019 if (c
== 'Z') ret
->guess
[x
] = 4;
2020 if (c
== 'E') { ret
->guess
[x
] = 7; ret
->pencils
[x
] = 0; }
2021 if (c
== 'g') ret
->pencils
[x
] ^= 1;
2022 if (c
== 'v') ret
->pencils
[x
] ^= 2;
2023 if (c
== 'z') ret
->pencils
[x
] ^= 4;
2026 if (c
== 'D' && sscanf(move
+ 1, "%d,%d%n", &x
, &y
, &n
) == 2 &&
2027 is_clue(ret
, x
, y
)) {
2028 ret
->hints_done
[clue_index(ret
, x
, y
)] ^= 1;
2033 * Fill in absolutely all pencil marks in unfilled
2034 * squares, for those who like to play by the rigorous
2035 * approach of starting off in that state and eliminating
2038 for (i
= 0; i
< ret
->common
->wh
; i
++)
2039 if (ret
->guess
[i
] == 7)
2040 ret
->pencils
[i
] = 7;
2043 if (*move
== ';') move
++;
2048 for (i
=0;i
<ret
->common
->wh
;i
++) ret
->cell_errors
[i
] = FALSE
;
2049 for (i
=0;i
<2*ret
->common
->num_paths
;i
++) ret
->hint_errors
[i
] = FALSE
;
2050 for (i
=0;i
<3;i
++) ret
->count_errors
[i
] = FALSE
;
2052 if (!check_numbers_draw(ret
,ret
->guess
)) correct
= FALSE
;
2054 for (p
=0;p
<state
->common
->num_paths
;p
++)
2055 if (!check_path_solution(ret
,p
)) correct
= FALSE
;
2057 for (i
=0;i
<state
->common
->num_total
;i
++)
2058 if (!(ret
->guess
[i
] == 1 || ret
->guess
[i
] == 2 ||
2059 ret
->guess
[i
] == 4)) correct
= FALSE
;
2061 if (correct
&& !solver
) ret
->solved
= TRUE
;
2062 if (solver
) ret
->cheated
= TRUE
;
2067 /* ----------------------------------------------------------------------
2071 #define PREFERRED_TILE_SIZE 64
2073 static void game_compute_size(const game_params
*params
, int tilesize
,
2076 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2077 struct { int tilesize
; } ads
, *ds
= &ads
;
2078 ads
.tilesize
= tilesize
;
2080 *x
= 2*BORDER
+(params
->w
+2)*TILESIZE
;
2081 *y
= 2*BORDER
+(params
->h
+3)*TILESIZE
;
2085 static void game_set_size(drawing
*dr
, game_drawstate
*ds
,
2086 const game_params
*params
, int tilesize
)
2088 ds
->tilesize
= tilesize
;
2092 #define COLOUR(ret, i, r, g, b) ((ret[3*(i)+0] = (r)), (ret[3*(i)+1] = (g)), (ret[3*(i)+2] = (b)))
2094 static float *game_colours(frontend
*fe
, int *ncolours
)
2096 float *ret
= snewn(3 * NCOLOURS
, float);
2098 frontend_default_colour(fe
, &ret
[COL_BACKGROUND
* 3]);
2100 ret
[COL_GRID
* 3 + 0] = 0.0F
;
2101 ret
[COL_GRID
* 3 + 1] = 0.0F
;
2102 ret
[COL_GRID
* 3 + 2] = 0.0F
;
2104 ret
[COL_TEXT
* 3 + 0] = 0.0F
;
2105 ret
[COL_TEXT
* 3 + 1] = 0.0F
;
2106 ret
[COL_TEXT
* 3 + 2] = 0.0F
;
2108 ret
[COL_ERROR
* 3 + 0] = 1.0F
;
2109 ret
[COL_ERROR
* 3 + 1] = 0.0F
;
2110 ret
[COL_ERROR
* 3 + 2] = 0.0F
;
2112 ret
[COL_HIGHLIGHT
* 3 + 0] = 0.78F
* ret
[COL_BACKGROUND
* 3 + 0];
2113 ret
[COL_HIGHLIGHT
* 3 + 1] = 0.78F
* ret
[COL_BACKGROUND
* 3 + 1];
2114 ret
[COL_HIGHLIGHT
* 3 + 2] = 0.78F
* ret
[COL_BACKGROUND
* 3 + 2];
2116 ret
[COL_FLASH
* 3 + 0] = 1.0F
;
2117 ret
[COL_FLASH
* 3 + 1] = 1.0F
;
2118 ret
[COL_FLASH
* 3 + 2] = 1.0F
;
2120 ret
[COL_GHOST
* 3 + 0] = ret
[COL_BACKGROUND
* 3 + 0] * 0.5F
;
2121 ret
[COL_GHOST
* 3 + 1] = ret
[COL_BACKGROUND
* 3 + 0];
2122 ret
[COL_GHOST
* 3 + 2] = ret
[COL_BACKGROUND
* 3 + 0];
2124 ret
[COL_ZOMBIE
* 3 + 0] = ret
[COL_BACKGROUND
* 3 + 0] * 0.5F
;
2125 ret
[COL_ZOMBIE
* 3 + 1] = ret
[COL_BACKGROUND
* 3 + 0];
2126 ret
[COL_ZOMBIE
* 3 + 2] = ret
[COL_BACKGROUND
* 3 + 0] * 0.5F
;
2128 ret
[COL_VAMPIRE
* 3 + 0] = ret
[COL_BACKGROUND
* 3 + 0];
2129 ret
[COL_VAMPIRE
* 3 + 1] = ret
[COL_BACKGROUND
* 3 + 0] * 0.9F
;
2130 ret
[COL_VAMPIRE
* 3 + 2] = ret
[COL_BACKGROUND
* 3 + 0] * 0.9F
;
2132 ret
[COL_DONE
* 3 + 0] = ret
[COL_BACKGROUND
* 3 + 0] / 1.5F
;
2133 ret
[COL_DONE
* 3 + 1] = ret
[COL_BACKGROUND
* 3 + 1] / 1.5F
;
2134 ret
[COL_DONE
* 3 + 2] = ret
[COL_BACKGROUND
* 3 + 2] / 1.5F
;
2136 *ncolours
= NCOLOURS
;
2140 static game_drawstate
*game_new_drawstate(drawing
*dr
, const game_state
*state
)
2143 struct game_drawstate
*ds
= snew(struct game_drawstate
);
2146 ds
->started
= ds
->solved
= FALSE
;
2147 ds
->w
= state
->common
->params
.w
;
2148 ds
->h
= state
->common
->params
.h
;
2151 ds
->count_errors
[0] = FALSE
;
2152 ds
->count_errors
[1] = FALSE
;
2153 ds
->count_errors
[2] = FALSE
;
2155 ds
->monsters
= snewn(state
->common
->num_total
,int);
2156 for (i
=0;i
<(state
->common
->num_total
);i
++)
2157 ds
->monsters
[i
] = 7;
2158 ds
->pencils
= snewn(state
->common
->num_total
,unsigned char);
2159 for (i
=0;i
<state
->common
->num_total
;i
++)
2162 ds
->cell_errors
= snewn(state
->common
->wh
,unsigned char);
2163 for (i
=0;i
<state
->common
->wh
;i
++)
2164 ds
->cell_errors
[i
] = FALSE
;
2165 ds
->hint_errors
= snewn(2*state
->common
->num_paths
,unsigned char);
2166 for (i
=0;i
<2*state
->common
->num_paths
;i
++)
2167 ds
->hint_errors
[i
] = FALSE
;
2168 ds
->hints_done
= snewn(2 * state
->common
->num_paths
, unsigned char);
2169 memset(ds
->hints_done
, 0,
2170 2 * state
->common
->num_paths
* sizeof(unsigned char));
2172 ds
->hshow
= ds
->hpencil
= ds
->hflash
= 0;
2173 ds
->hx
= ds
->hy
= 0;
2177 static void game_free_drawstate(drawing
*dr
, game_drawstate
*ds
) {
2178 sfree(ds
->hints_done
);
2179 sfree(ds
->hint_errors
);
2180 sfree(ds
->cell_errors
);
2182 sfree(ds
->monsters
);
2187 static void draw_cell_background(drawing
*dr
, game_drawstate
*ds
,
2188 const game_state
*state
, const game_ui
*ui
,
2193 dx
= BORDER
+(x
* ds
->tilesize
)+(TILESIZE
/2);
2194 dy
= BORDER
+(y
* ds
->tilesize
)+(TILESIZE
/2)+TILESIZE
;
2196 hon
= (ui
->hshow
&& x
== ui
->hx
&& y
== ui
->hy
);
2197 draw_rect(dr
,dx
-(TILESIZE
/2)+1,dy
-(TILESIZE
/2)+1,TILESIZE
-1,TILESIZE
-1,(hon
&& !ui
->hpencil
) ? COL_HIGHLIGHT
: COL_BACKGROUND
);
2199 if (hon
&& ui
->hpencil
) {
2201 coords
[0] = dx
-(TILESIZE
/2)+1;
2202 coords
[1] = dy
-(TILESIZE
/2)+1;
2203 coords
[2] = coords
[0] + TILESIZE
/2;
2204 coords
[3] = coords
[1];
2205 coords
[4] = coords
[0];
2206 coords
[5] = coords
[1] + TILESIZE
/2;
2207 draw_polygon(dr
, coords
, 3, COL_HIGHLIGHT
, COL_HIGHLIGHT
);
2210 draw_update(dr
,dx
-(TILESIZE
/2)+1,dy
-(TILESIZE
/2)+1,TILESIZE
-1,TILESIZE
-1);
2215 static void draw_circle_or_point(drawing
*dr
, int cx
, int cy
, int radius
,
2219 draw_circle(dr
, cx
, cy
, radius
, colour
, colour
);
2221 draw_rect(dr
, cx
, cy
, 1, 1, colour
);
2224 static void draw_monster(drawing
*dr
, game_drawstate
*ds
, int x
, int y
,
2225 int tilesize
, int hflash
, int monster
)
2227 int black
= (hflash
? COL_FLASH
: COL_TEXT
);
2229 if (monster
== 1) { /* ghost */
2232 clip(dr
,x
-(tilesize
/2)+2,y
-(tilesize
/2)+2,tilesize
-3,tilesize
/2+1);
2233 draw_circle(dr
,x
,y
,2*tilesize
/5, COL_GHOST
,black
);
2237 poly
[i
++] = x
- 2*tilesize
/5;
2239 poly
[i
++] = x
- 2*tilesize
/5;
2240 poly
[i
++] = y
+ 2*tilesize
/5;
2242 for (j
= 0; j
< 3; j
++) {
2243 int total
= (2*tilesize
/5) * 2;
2244 int before
= total
* j
/ 3;
2245 int after
= total
* (j
+1) / 3;
2246 int mid
= (before
+ after
) / 2;
2247 poly
[i
++] = x
- 2*tilesize
/5 + mid
;
2248 poly
[i
++] = y
+ 2*tilesize
/5 - (total
/ 6);
2249 poly
[i
++] = x
- 2*tilesize
/5 + after
;
2250 poly
[i
++] = y
+ 2*tilesize
/5;
2253 poly
[i
++] = x
+ 2*tilesize
/5;
2256 clip(dr
,x
-(tilesize
/2)+2,y
,tilesize
-3,tilesize
-(tilesize
/2)-1);
2257 draw_polygon(dr
, poly
, i
/2, COL_GHOST
, black
);
2260 draw_circle(dr
,x
-tilesize
/6,y
-tilesize
/12,tilesize
/10,
2261 COL_BACKGROUND
,black
);
2262 draw_circle(dr
,x
+tilesize
/6,y
-tilesize
/12,tilesize
/10,
2263 COL_BACKGROUND
,black
);
2265 draw_circle_or_point(dr
,x
-tilesize
/6+1+tilesize
/48,y
-tilesize
/12,
2267 draw_circle_or_point(dr
,x
+tilesize
/6+1+tilesize
/48,y
-tilesize
/12,
2270 } else if (monster
== 2) { /* vampire */
2273 clip(dr
,x
-(tilesize
/2)+2,y
-(tilesize
/2)+2,tilesize
-3,tilesize
/2);
2274 draw_circle(dr
,x
,y
,2*tilesize
/5,black
,black
);
2277 clip(dr
,x
-(tilesize
/2)+2,y
-(tilesize
/2)+2,tilesize
/2+1,tilesize
/2);
2278 draw_circle(dr
,x
-tilesize
/7,y
,2*tilesize
/5-tilesize
/7,
2281 clip(dr
,x
,y
-(tilesize
/2)+2,tilesize
/2+1,tilesize
/2);
2282 draw_circle(dr
,x
+tilesize
/7,y
,2*tilesize
/5-tilesize
/7,
2286 clip(dr
,x
-(tilesize
/2)+2,y
,tilesize
-3,tilesize
/2);
2287 draw_circle(dr
,x
,y
,2*tilesize
/5, COL_VAMPIRE
,black
);
2290 draw_circle(dr
, x
-tilesize
/7, y
-tilesize
/16, tilesize
/16,
2291 COL_BACKGROUND
, black
);
2292 draw_circle(dr
, x
+tilesize
/7, y
-tilesize
/16, tilesize
/16,
2293 COL_BACKGROUND
, black
);
2294 draw_circle_or_point(dr
, x
-tilesize
/7, y
-tilesize
/16, tilesize
/48,
2296 draw_circle_or_point(dr
, x
+tilesize
/7, y
-tilesize
/16, tilesize
/48,
2299 clip(dr
, x
-(tilesize
/2)+2, y
+tilesize
/8, tilesize
-3, tilesize
/4);
2302 poly
[i
++] = x
-3*tilesize
/16;
2303 poly
[i
++] = y
+1*tilesize
/8;
2304 poly
[i
++] = x
-2*tilesize
/16;
2305 poly
[i
++] = y
+7*tilesize
/24;
2306 poly
[i
++] = x
-1*tilesize
/16;
2307 poly
[i
++] = y
+1*tilesize
/8;
2308 draw_polygon(dr
, poly
, i
/2, COL_BACKGROUND
, black
);
2310 poly
[i
++] = x
+3*tilesize
/16;
2311 poly
[i
++] = y
+1*tilesize
/8;
2312 poly
[i
++] = x
+2*tilesize
/16;
2313 poly
[i
++] = y
+7*tilesize
/24;
2314 poly
[i
++] = x
+1*tilesize
/16;
2315 poly
[i
++] = y
+1*tilesize
/8;
2316 draw_polygon(dr
, poly
, i
/2, COL_BACKGROUND
, black
);
2318 draw_circle(dr
, x
, y
-tilesize
/5, 2*tilesize
/5, COL_VAMPIRE
, black
);
2321 } else if (monster
== 4) { /* zombie */
2322 draw_circle(dr
,x
,y
,2*tilesize
/5, COL_ZOMBIE
,black
);
2325 x
-tilesize
/7-tilesize
/16, y
-tilesize
/12-tilesize
/16,
2326 x
-tilesize
/7+tilesize
/16, y
-tilesize
/12+tilesize
/16,
2329 x
-tilesize
/7+tilesize
/16, y
-tilesize
/12-tilesize
/16,
2330 x
-tilesize
/7-tilesize
/16, y
-tilesize
/12+tilesize
/16,
2333 x
+tilesize
/7-tilesize
/16, y
-tilesize
/12-tilesize
/16,
2334 x
+tilesize
/7+tilesize
/16, y
-tilesize
/12+tilesize
/16,
2337 x
+tilesize
/7+tilesize
/16, y
-tilesize
/12-tilesize
/16,
2338 x
+tilesize
/7-tilesize
/16, y
-tilesize
/12+tilesize
/16,
2341 clip(dr
, x
-tilesize
/5, y
+tilesize
/6, 2*tilesize
/5+1, tilesize
/2);
2342 draw_circle(dr
, x
-tilesize
/15, y
+tilesize
/6, tilesize
/12,
2343 COL_BACKGROUND
, black
);
2346 draw_line(dr
, x
-tilesize
/5, y
+tilesize
/6, x
+tilesize
/5, y
+tilesize
/6,
2350 draw_update(dr
,x
-(tilesize
/2)+2,y
-(tilesize
/2)+2,tilesize
-3,tilesize
-3);
2353 static void draw_monster_count(drawing
*dr
, game_drawstate
*ds
,
2354 const game_state
*state
, int c
, int hflash
) {
2360 dx
= BORDER
+(ds
->w
+2)*TILESIZE
/2+TILESIZE
/4;
2363 sprintf(buf
,"%d",state
->common
->num_ghosts
);
2368 sprintf(buf
,"%d",state
->common
->num_vampires
);
2372 sprintf(buf
,"%d",state
->common
->num_zombies
);
2378 draw_rect(dr
, dx
-2*TILESIZE
/3, dy
, 3*TILESIZE
/2, TILESIZE
,
2381 draw_monster(dr
, ds
, dx
-TILESIZE
/3, dy
+TILESIZE
/2,
2382 2*TILESIZE
/3, hflash
, 1<<c
);
2384 draw_text(dr
, dx
-TILESIZE
/3,dy
+TILESIZE
/2,FONT_VARIABLE
,TILESIZE
/2,
2385 ALIGN_HCENTRE
|ALIGN_VCENTRE
,
2386 hflash
? COL_FLASH
: COL_TEXT
, bufm
);
2388 draw_text(dr
, dx
, dy
+TILESIZE
/2, FONT_VARIABLE
, TILESIZE
/2,
2389 ALIGN_HLEFT
|ALIGN_VCENTRE
,
2390 (state
->count_errors
[c
] ? COL_ERROR
:
2391 hflash
? COL_FLASH
: COL_TEXT
), buf
);
2392 draw_update(dr
, dx
-2*TILESIZE
/3, dy
, 3*TILESIZE
/2, TILESIZE
);
2397 static void draw_path_hint(drawing
*dr
, game_drawstate
*ds
,
2398 const struct game_params
*params
,
2399 int hint_index
, int hflash
, int hint
) {
2400 int x
, y
, color
, dx
, dy
, text_dx
, text_dy
, text_size
;
2403 if (ds
->hint_errors
[hint_index
])
2407 else if (ds
->hints_done
[hint_index
])
2412 range2grid(hint_index
, params
->w
, params
->h
, &x
, &y
);
2413 /* Upper-left corner of the "tile" */
2414 dx
= BORDER
+ x
* TILESIZE
;
2415 dy
= BORDER
+ y
* TILESIZE
+ TILESIZE
;
2416 /* Center of the "tile" */
2417 text_dx
= dx
+ TILESIZE
/ 2;
2418 text_dy
= dy
+ TILESIZE
/ 2;
2419 /* Avoid wiping out the borders of the puzzle */
2422 text_size
= TILESIZE
- 3;
2424 sprintf(buf
,"%d", hint
);
2425 draw_rect(dr
, dx
, dy
, text_size
, text_size
, COL_BACKGROUND
);
2426 draw_text(dr
, text_dx
, text_dy
, FONT_FIXED
, TILESIZE
/ 2,
2427 ALIGN_HCENTRE
| ALIGN_VCENTRE
, color
, buf
);
2428 draw_update(dr
, dx
, dy
, text_size
, text_size
);
2433 static void draw_mirror(drawing
*dr
, game_drawstate
*ds
,
2434 const game_state
*state
, int x
, int y
,
2435 int hflash
, int mirror
) {
2436 int dx
,dy
,mx1
,my1
,mx2
,my2
;
2437 dx
= BORDER
+(x
* ds
->tilesize
)+(TILESIZE
/2);
2438 dy
= BORDER
+(y
* ds
->tilesize
)+(TILESIZE
/2)+TILESIZE
;
2440 if (mirror
== CELL_MIRROR_L
) {
2441 mx1
= dx
-(TILESIZE
/4);
2442 my1
= dy
-(TILESIZE
/4);
2443 mx2
= dx
+(TILESIZE
/4);
2444 my2
= dy
+(TILESIZE
/4);
2447 mx1
= dx
-(TILESIZE
/4);
2448 my1
= dy
+(TILESIZE
/4);
2449 mx2
= dx
+(TILESIZE
/4);
2450 my2
= dy
-(TILESIZE
/4);
2452 draw_thick_line(dr
,(float)(TILESIZE
/16),mx1
,my1
,mx2
,my2
,
2453 hflash
? COL_FLASH
: COL_TEXT
);
2454 draw_update(dr
,dx
-(TILESIZE
/2)+1,dy
-(TILESIZE
/2)+1,TILESIZE
-1,TILESIZE
-1);
2459 static void draw_big_monster(drawing
*dr
, game_drawstate
*ds
,
2460 const game_state
*state
, int x
, int y
,
2461 int hflash
, int monster
)
2465 dx
= BORDER
+(x
* ds
->tilesize
)+(TILESIZE
/2);
2466 dy
= BORDER
+(y
* ds
->tilesize
)+(TILESIZE
/2)+TILESIZE
;
2468 if (monster
== 1) sprintf(buf
,"G");
2469 else if (monster
== 2) sprintf(buf
,"V");
2470 else if (monster
== 4) sprintf(buf
,"Z");
2471 else sprintf(buf
," ");
2472 draw_text(dr
,dx
,dy
,FONT_FIXED
,TILESIZE
/2,ALIGN_HCENTRE
|ALIGN_VCENTRE
,
2473 hflash
? COL_FLASH
: COL_TEXT
,buf
);
2474 draw_update(dr
,dx
-(TILESIZE
/2)+2,dy
-(TILESIZE
/2)+2,TILESIZE
-3,
2478 draw_monster(dr
, ds
, dx
, dy
, 3*TILESIZE
/4, hflash
, monster
);
2483 static void draw_pencils(drawing
*dr
, game_drawstate
*ds
,
2484 const game_state
*state
, int x
, int y
, int pencil
)
2490 dx
= BORDER
+(x
* ds
->tilesize
)+(TILESIZE
/4);
2491 dy
= BORDER
+(y
* ds
->tilesize
)+(TILESIZE
/4)+TILESIZE
;
2493 for (i
= 0, j
= 1; j
< 8; j
*= 2)
2499 for (py
= 0; py
< 2; py
++)
2500 for (px
= 0; px
< 2; px
++)
2501 if (monsters
[py
*2+px
]) {
2503 draw_monster(dr
, ds
,
2504 dx
+ TILESIZE
/2 * px
, dy
+ TILESIZE
/2 * py
,
2505 TILESIZE
/2, 0, monsters
[py
*2+px
]);
2508 switch (monsters
[py
*2+px
]) {
2509 case 1: sprintf(buf
,"G"); break;
2510 case 2: sprintf(buf
,"V"); break;
2511 case 4: sprintf(buf
,"Z"); break;
2513 draw_text(dr
,dx
+ TILESIZE
/2 * px
,dy
+ TILESIZE
/2 * py
,
2514 FONT_FIXED
,TILESIZE
/4,ALIGN_HCENTRE
|ALIGN_VCENTRE
,
2518 draw_update(dr
,dx
-(TILESIZE
/4)+2,dy
-(TILESIZE
/4)+2,
2519 (TILESIZE
/2)-3,(TILESIZE
/2)-3);
2524 #define FLASH_TIME 0.7F
2526 static int is_hint_stale(const game_drawstate
*ds
, int hflash
,
2527 const game_state
*state
, int index
)
2530 if (!ds
->started
) ret
= TRUE
;
2531 if (ds
->hflash
!= hflash
) ret
= TRUE
;
2533 if (ds
->hint_errors
[index
] != state
->hint_errors
[index
]) {
2534 ds
->hint_errors
[index
] = state
->hint_errors
[index
];
2538 if (ds
->hints_done
[index
] != state
->hints_done
[index
]) {
2539 ds
->hints_done
[index
] = state
->hints_done
[index
];
2546 static void game_redraw(drawing
*dr
, game_drawstate
*ds
,
2547 const game_state
*oldstate
, const game_state
*state
,
2548 int dir
, const game_ui
*ui
,
2549 float animtime
, float flashtime
)
2552 int stale
, xi
, c
, hflash
, hchanged
, changed_ascii
;
2554 hflash
= (int)(flashtime
* 5 / FLASH_TIME
) % 2;
2556 /* Draw static grid components at startup */
2558 draw_rect(dr
, 0, 0, 2*BORDER
+(ds
->w
+2)*TILESIZE
,
2559 2*BORDER
+(ds
->h
+3)*TILESIZE
, COL_BACKGROUND
);
2560 draw_rect(dr
, BORDER
+TILESIZE
-1, BORDER
+2*TILESIZE
-1,
2561 (ds
->w
)*TILESIZE
+3, (ds
->h
)*TILESIZE
+3, COL_GRID
);
2562 for (i
=0;i
<ds
->w
;i
++)
2563 for (j
=0;j
<ds
->h
;j
++)
2564 draw_rect(dr
, BORDER
+(ds
->tilesize
*(i
+1))+1,
2565 BORDER
+(ds
->tilesize
*(j
+2))+1, ds
->tilesize
-1,
2566 ds
->tilesize
-1, COL_BACKGROUND
);
2567 draw_update(dr
, 0, 0, 2*BORDER
+(ds
->w
+2)*TILESIZE
,
2568 2*BORDER
+(ds
->h
+3)*TILESIZE
);
2572 if (ds
->hx
!= ui
->hx
|| ds
->hy
!= ui
->hy
||
2573 ds
->hshow
!= ui
->hshow
|| ds
->hpencil
!= ui
->hpencil
)
2576 if (ds
->ascii
!= ui
->ascii
) {
2577 ds
->ascii
= ui
->ascii
;
2578 changed_ascii
= TRUE
;
2580 changed_ascii
= FALSE
;
2582 /* Draw monster count hints */
2586 if (!ds
->started
) stale
= TRUE
;
2587 if (ds
->hflash
!= hflash
) stale
= TRUE
;
2588 if (changed_ascii
) stale
= TRUE
;
2589 if (ds
->count_errors
[i
] != state
->count_errors
[i
]) {
2591 ds
->count_errors
[i
] = state
->count_errors
[i
];
2595 draw_monster_count(dr
, ds
, state
, i
, hflash
);
2599 /* Draw path count hints */
2600 for (i
=0;i
<state
->common
->num_paths
;i
++) {
2601 struct path
*path
= &state
->common
->paths
[i
];
2603 if (is_hint_stale(ds
, hflash
, state
, path
->grid_start
)) {
2604 draw_path_hint(dr
, ds
, &state
->common
->params
, path
->grid_start
,
2605 hflash
, path
->sightings_start
);
2608 if (is_hint_stale(ds
, hflash
, state
, path
->grid_end
)) {
2609 draw_path_hint(dr
, ds
, &state
->common
->params
, path
->grid_end
,
2610 hflash
, path
->sightings_end
);
2614 /* Draw puzzle grid contents */
2615 for (x
= 1; x
< ds
->w
+1; x
++)
2616 for (y
= 1; y
< ds
->h
+1; y
++) {
2618 xy
= x
+y
*(state
->common
->params
.w
+2);
2619 xi
= state
->common
->xinfo
[xy
];
2620 c
= state
->common
->grid
[xy
];
2622 if (!ds
->started
) stale
= TRUE
;
2623 if (ds
->hflash
!= hflash
) stale
= TRUE
;
2624 if (changed_ascii
) stale
= TRUE
;
2627 if ((x
== ui
->hx
&& y
== ui
->hy
) ||
2628 (x
== ds
->hx
&& y
== ds
->hy
))
2632 if (xi
>= 0 && (state
->guess
[xi
] != ds
->monsters
[xi
]) ) {
2634 ds
->monsters
[xi
] = state
->guess
[xi
];
2637 if (xi
>= 0 && (state
->pencils
[xi
] != ds
->pencils
[xi
]) ) {
2639 ds
->pencils
[xi
] = state
->pencils
[xi
];
2642 if (state
->cell_errors
[xy
] != ds
->cell_errors
[xy
]) {
2644 ds
->cell_errors
[xy
] = state
->cell_errors
[xy
];
2648 draw_cell_background(dr
, ds
, state
, ui
, x
, y
);
2650 draw_mirror(dr
, ds
, state
, x
, y
, hflash
, c
);
2651 else if (state
->guess
[xi
] == 1 || state
->guess
[xi
] == 2 ||
2652 state
->guess
[xi
] == 4)
2653 draw_big_monster(dr
, ds
, state
, x
, y
, hflash
, state
->guess
[xi
]);
2655 draw_pencils(dr
, ds
, state
, x
, y
, state
->pencils
[xi
]);
2659 ds
->hx
= ui
->hx
; ds
->hy
= ui
->hy
;
2660 ds
->hshow
= ui
->hshow
;
2661 ds
->hpencil
= ui
->hpencil
;
2662 ds
->hflash
= hflash
;
2667 static float game_anim_length(const game_state
*oldstate
,
2668 const game_state
*newstate
, int dir
, game_ui
*ui
)
2673 static float game_flash_length(const game_state
*oldstate
,
2674 const game_state
*newstate
, int dir
, game_ui
*ui
)
2676 return (!oldstate
->solved
&& newstate
->solved
&& !oldstate
->cheated
&&
2677 !newstate
->cheated
) ? FLASH_TIME
: 0.0F
;
2680 static int game_status(const game_state
*state
)
2682 return state
->solved
;
2685 static int game_timing_state(const game_state
*state
, game_ui
*ui
)
2690 static void game_print_size(const game_params
*params
, float *x
, float *y
)
2694 static void game_print(drawing
*dr
, const game_state
*state
, int tilesize
)
2699 #define thegame undead
2702 const struct game thegame
= {
2703 "Undead", "games.undead", "undead",
2705 game_fetch_preset
, NULL
,
2710 TRUE
, game_configure
, custom_params
,
2718 TRUE
, game_can_format_as_text_now
, game_text_format
,
2726 PREFERRED_TILE_SIZE
, game_compute_size
, game_set_size
,
2729 game_free_drawstate
,
2734 FALSE
, FALSE
, game_print_size
, game_print
,
2735 FALSE
, /* wants_statusbar */
2736 FALSE
, game_timing_state
,