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
59 #define ENUM(upper,title,lower) DIFF_ ## upper,
60 #define TITLE(upper,title,lower) #title,
61 #define ENCODE(upper,title,lower) #lower
62 #define CONFIG(upper,title,lower) ":" #title
63 enum { DIFFLIST(ENUM) DIFFCOUNT };
64 static char const *const undead_diffnames[] = { DIFFLIST(TITLE) "(count)" };
65 static char const undead_diffchars[] = DIFFLIST(ENCODE);
66 #define DIFFCONFIG DIFFLIST(CONFIG)
69 int w; /* Grid width */
70 int h; /* Grid height */
71 int diff; /* Puzzle difficulty */
74 static const struct game_params undead_presets[] = {
76 { 4, 4, DIFF_NORMAL },
77 { 4, 4, DIFF_TRICKY },
79 { 5, 5, DIFF_NORMAL },
80 { 5, 5, DIFF_TRICKY },
85 #define DEFAULT_PRESET 1
87 static game_params *default_params(void) {
88 game_params *ret = snew(game_params);
90 *ret = undead_presets[DEFAULT_PRESET];
94 static int game_fetch_preset(int i, char **name, game_params **params) {
98 if (i < 0 || i >= lenof(undead_presets)) return FALSE;
100 ret = default_params();
101 *ret = undead_presets[i]; /* struct copy */
104 sprintf(buf, "%dx%d %s",
105 undead_presets[i].w, undead_presets[i].h,
106 undead_diffnames[undead_presets[i].diff]);
112 static void free_params(game_params *params) {
116 static game_params *dup_params(const game_params *params)
118 game_params *ret = snew(game_params);
119 *ret = *params; /* structure copy */
123 static void decode_params(game_params *params, char const *string) {
124 params->w = params->h = atoi(string);
126 while (*string && isdigit((unsigned char) *string)) ++string;
127 if (*string == 'x') {
129 params->h = atoi(string);
130 while (*string && isdigit((unsigned char)*string)) string++;
133 params->diff = DIFF_NORMAL;
134 if (*string == 'd') {
137 for (i = 0; i < DIFFCOUNT; i++)
138 if (*string == undead_diffchars[i])
140 if (*string) string++;
146 static char *encode_params(const game_params *params, int full)
149 sprintf(buf, "%dx%d", params->w, params->h);
151 sprintf(buf + strlen(buf), "d%c", undead_diffchars[params->diff]);
155 static config_item *game_configure(const game_params *params)
160 ret = snewn(4, config_item);
162 ret[0].name = "Width";
163 ret[0].type = C_STRING;
164 sprintf(buf, "%d", params->w);
165 ret[0].sval = dupstr(buf);
168 ret[1].name = "Height";
169 ret[1].type = C_STRING;
170 sprintf(buf, "%d", params->h);
171 ret[1].sval = dupstr(buf);
174 ret[2].name = "Difficulty";
175 ret[2].type = C_CHOICES;
176 ret[2].sval = DIFFCONFIG;
177 ret[2].ival = params->diff;
187 static game_params *custom_params(const config_item *cfg)
189 game_params *ret = snew(game_params);
191 ret->w = atoi(cfg[0].sval);
192 ret->h = atoi(cfg[1].sval);
193 ret->diff = cfg[2].ival;
197 static char *validate_params(const game_params *params, int full)
199 if ((params->w * params->h ) > 54) return "Grid is too big";
200 if (params->w < 3) return "Width must be at least 3";
201 if (params->h < 3) return "Height must be at least 3";
202 if (params->diff >= DIFFCOUNT) return "Unknown difficulty rating";
206 /* --------------------------------------------------------------- */
207 /* Game state allocation, deallocation. */
223 struct game_params params;
225 int num_ghosts,num_vampires,num_zombies,num_total;
235 struct game_common *common;
237 unsigned char *pencils;
238 unsigned char *cell_errors;
239 unsigned char *hint_errors;
240 unsigned char count_errors[3];
245 static game_state *new_state(const game_params *params) {
247 game_state *state = snew(game_state);
248 state->common = snew(struct game_common);
250 state->common->refcount = 1;
251 state->common->params.w = params->w;
252 state->common->params.h = params->h;
253 state->common->params.diff = params->diff;
255 state->common->wh = (state->common->params.w +2) * (state->common->params.h +2);
257 state->common->num_ghosts = 0;
258 state->common->num_vampires = 0;
259 state->common->num_zombies = 0;
260 state->common->num_total = 0;
262 state->common->grid = snewn(state->common->wh, int);
263 state->common->xinfo = snewn(state->common->wh, int);
264 state->common->fixed = NULL;
265 state->common->solved = FALSE;
267 state->common->num_paths =
268 state->common->params.w + state->common->params.h;
269 state->common->paths = snewn(state->common->num_paths, struct path);
271 for (i=0;i<state->common->num_paths;i++) {
272 state->common->paths[i].length = 0;
273 state->common->paths[i].grid_start = -1;
274 state->common->paths[i].grid_end = -1;
275 state->common->paths[i].num_monsters = 0;
276 state->common->paths[i].sightings_start = 0;
277 state->common->paths[i].sightings_end = 0;
278 state->common->paths[i].p = snewn(state->common->wh,int);
279 state->common->paths[i].xy = snewn(state->common->wh,int);
280 state->common->paths[i].mapping = snewn(state->common->wh,int);
284 state->pencils = NULL;
286 state->cell_errors = snewn(state->common->wh, unsigned char);
287 for (i=0;i<state->common->wh;i++)
288 state->cell_errors[i] = FALSE;
289 state->hint_errors = snewn(2*state->common->num_paths, unsigned char);
290 for (i=0;i<2*state->common->num_paths;i++)
291 state->hint_errors[i] = FALSE;
293 state->count_errors[i] = FALSE;
295 state->solved = FALSE;
296 state->cheated = FALSE;
301 static game_state *dup_game(const game_state *state)
303 game_state *ret = snew(game_state);
305 ret->common = state->common;
306 ret->common->refcount++;
308 if (state->guess != NULL) {
309 ret->guess = snewn(ret->common->num_total,int);
310 memcpy(ret->guess, state->guess, ret->common->num_total*sizeof(int));
312 else ret->guess = NULL;
314 if (state->pencils != NULL) {
315 ret->pencils = snewn(ret->common->num_total,unsigned char);
316 memcpy(ret->pencils, state->pencils,
317 ret->common->num_total*sizeof(unsigned char));
319 else ret->pencils = NULL;
321 if (state->cell_errors != NULL) {
322 ret->cell_errors = snewn(ret->common->wh,unsigned char);
323 memcpy(ret->cell_errors, state->cell_errors,
324 ret->common->wh*sizeof(unsigned char));
326 else ret->cell_errors = NULL;
328 if (state->hint_errors != NULL) {
329 ret->hint_errors = snewn(2*ret->common->num_paths,unsigned char);
330 memcpy(ret->hint_errors, state->hint_errors,
331 2*ret->common->num_paths*sizeof(unsigned char));
333 else ret->hint_errors = NULL;
335 ret->count_errors[0] = state->count_errors[0];
336 ret->count_errors[1] = state->count_errors[1];
337 ret->count_errors[2] = state->count_errors[2];
339 ret->solved = state->solved;
340 ret->cheated = state->cheated;
345 static void free_game(game_state *state) {
348 state->common->refcount--;
349 if (state->common->refcount == 0) {
350 for (i=0;i<state->common->num_paths;i++) {
351 sfree(state->common->paths[i].mapping);
352 sfree(state->common->paths[i].xy);
353 sfree(state->common->paths[i].p);
355 sfree(state->common->paths);
356 sfree(state->common->xinfo);
357 sfree(state->common->grid);
358 if (state->common->fixed != NULL) sfree(state->common->fixed);
359 sfree(state->common);
361 if (state->hint_errors != NULL) sfree(state->hint_errors);
362 if (state->cell_errors != NULL) sfree(state->cell_errors);
363 if (state->pencils != NULL) sfree(state->pencils);
364 if (state->guess != NULL) sfree(state->guess);
370 /* --------------------------------------------------------------- */
371 /* Puzzle generator */
384 /* grid walk directions */
393 int range2grid(int rangeno, int width, int height, int *x, int *y) {
396 *x = 0; *y = 0; return DIRECTION_NONE;
398 if (rangeno < width) {
399 *x = rangeno+1; *y = 0; return DIRECTION_DOWN;
401 rangeno = rangeno - width;
402 if (rangeno < height) {
403 *x = width+1; *y = rangeno+1; return DIRECTION_LEFT;
405 rangeno = rangeno - height;
406 if (rangeno < width) {
407 *x = width-rangeno; *y = height+1; return DIRECTION_UP;
409 rangeno = rangeno - width;
410 if (rangeno < height) {
411 *x = 0; *y = height-rangeno; return DIRECTION_RIGHT;
414 return DIRECTION_NONE;
417 int grid2range(int x, int y, int w, int h) {
418 if (x>0 && x<w+1 && y>0 && y<h+1) return -1;
419 if (x<0 || x>w+1 || y<0 || y>h+1) return -1;
420 if ((x == 0 || x==w+1) && (y==0 || y==h+1)) return -1;
421 if (y==0) return x-1;
422 if (x==(w+1)) return y-1+w;
423 if (y==(h+1)) return 2*w + h - x;
427 void make_paths(game_state *state) {
431 for (i=0;i<2*(state->common->params.w + state->common->params.h);i++) {
433 int j,k,num_monsters;
437 /* Check whether inverse path is already in list */
438 for (j=0;j<count;j++) {
439 if (i == state->common->paths[j].grid_end) {
446 /* We found a new path through the mirror maze */
447 state->common->paths[count].grid_start = i;
448 dir = range2grid(i, state->common->params.w,
449 state->common->params.h,&x,&y);
450 state->common->paths[count].sightings_start =
451 state->common->grid[x+y*(state->common->params.w +2)];
455 if (dir == DIRECTION_DOWN) y++;
456 else if (dir == DIRECTION_LEFT) x--;
457 else if (dir == DIRECTION_UP) y--;
458 else if (dir == DIRECTION_RIGHT) x++;
460 r = grid2range(x, y, state->common->params.w,
461 state->common->params.h);
463 state->common->paths[count].grid_end = r;
464 state->common->paths[count].sightings_end =
465 state->common->grid[x+y*(state->common->params.w +2)];
469 c = state->common->grid[x+y*(state->common->params.w+2)];
470 state->common->paths[count].xy[state->common->paths[count].length] =
471 x+y*(state->common->params.w+2);
472 if (c == CELL_MIRROR_L) {
473 state->common->paths[count].p[state->common->paths[count].length] = -1;
474 if (dir == DIRECTION_DOWN) dir = DIRECTION_RIGHT;
475 else if (dir == DIRECTION_LEFT) dir = DIRECTION_UP;
476 else if (dir == DIRECTION_UP) dir = DIRECTION_LEFT;
477 else if (dir == DIRECTION_RIGHT) dir = DIRECTION_DOWN;
479 else if (c == CELL_MIRROR_R) {
480 state->common->paths[count].p[state->common->paths[count].length] = -1;
481 if (dir == DIRECTION_DOWN) dir = DIRECTION_LEFT;
482 else if (dir == DIRECTION_LEFT) dir = DIRECTION_DOWN;
483 else if (dir == DIRECTION_UP) dir = DIRECTION_RIGHT;
484 else if (dir == DIRECTION_RIGHT) dir = DIRECTION_UP;
487 state->common->paths[count].p[state->common->paths[count].length] =
488 state->common->xinfo[x+y*(state->common->params.w+2)];
490 state->common->paths[count].length++;
492 /* Count unique monster entries in each path */
493 state->common->paths[count].num_monsters = 0;
494 for (j=0;j<state->common->num_total;j++) {
496 for (k=0;k<state->common->paths[count].length;k++)
497 if (state->common->paths[count].p[k] == j)
499 if (num_monsters > 0)
500 state->common->paths[count].num_monsters++;
503 /* Generate mapping vector */
505 for (p=0;p<state->common->paths[count].length;p++) {
507 m = state->common->paths[count].p[p];
508 if (m == -1) continue;
511 if (state->common->paths[count].mapping[j] == m) found = TRUE;
512 if (!found) state->common->paths[count].mapping[c++] = m;
525 int next_list(struct guess *g, int pos) {
528 if ((g->guess[pos] == 1 && g->possible[pos] == 1) ||
529 (g->guess[pos] == 2 && (g->possible[pos] == 3 ||
530 g->possible[pos] == 2)) ||
533 if (g->guess[pos] == 1 && (g->possible[pos] == 3 ||
534 g->possible[pos] == 7)) {
535 g->guess[pos] = 2; return TRUE;
537 if (g->guess[pos] == 1 && g->possible[pos] == 5) {
538 g->guess[pos] = 4; return TRUE;
540 if (g->guess[pos] == 2 && (g->possible[pos] == 6 || g->possible[pos] == 7)) {
541 g->guess[pos] = 4; return TRUE;
545 if (g->guess[pos] == 1) {
546 if (g->possible[pos] == 1) {
547 return next_list(g,pos-1);
549 if (g->possible[pos] == 3 || g->possible[pos] == 7) {
550 g->guess[pos] = 2; return TRUE;
552 if (g->possible[pos] == 5) {
553 g->guess[pos] = 4; return TRUE;
557 if (g->guess[pos] == 2) {
558 if (g->possible[pos] == 2) {
559 return next_list(g,pos-1);
561 if (g->possible[pos] == 3) {
562 g->guess[pos] = 1; return next_list(g,pos-1);
564 if (g->possible[pos] == 6 || g->possible[pos] == 7) {
565 g->guess[pos] = 4; return TRUE;
569 if (g->guess[pos] == 4) {
570 if (g->possible[pos] == 5 || g->possible[pos] == 7) {
571 g->guess[pos] = 1; return next_list(g,pos-1);
573 if (g->possible[pos] == 6) {
574 g->guess[pos] = 2; return next_list(g,pos-1);
576 if (g->possible[pos] == 4) {
577 return next_list(g,pos-1);
583 void get_unique(game_state *state, int counter, random_state *rs) {
585 int p,i,c,pathlimit,count_uniques;
586 struct guess path_guess;
599 } views, single_views, test_views;
601 struct entry test_entry;
603 path_guess.length = state->common->paths[counter].num_monsters;
604 path_guess.guess = snewn(path_guess.length,int);
605 path_guess.possible = snewn(path_guess.length,int);
606 for (i=0;i<path_guess.length;i++)
607 path_guess.guess[i] = path_guess.possible[i] = 0;
609 for (p=0;p<path_guess.length;p++) {
610 path_guess.possible[p] =
611 state->guess[state->common->paths[counter].mapping[p]];
612 switch (path_guess.possible[p]) {
613 case 1: path_guess.guess[p] = 1; break;
614 case 2: path_guess.guess[p] = 2; break;
615 case 3: path_guess.guess[p] = 1; break;
616 case 4: path_guess.guess[p] = 4; break;
617 case 5: path_guess.guess[p] = 1; break;
618 case 6: path_guess.guess[p] = 2; break;
619 case 7: path_guess.guess[p] = 1; break;
626 pathlimit = state->common->paths[counter].length + 1;
627 view_count = snewn(pathlimit*pathlimit, int);
628 for (i = 0; i < pathlimit*pathlimit; i++)
632 int mirror, start_view, end_view;
636 for (p=0;p<state->common->paths[counter].length;p++) {
637 if (state->common->paths[counter].p[p] == -1) mirror = TRUE;
639 for (i=0;i<path_guess.length;i++) {
640 if (state->common->paths[counter].p[p] ==
641 state->common->paths[counter].mapping[i]) {
642 if (path_guess.guess[i] == 1 && mirror == TRUE)
644 if (path_guess.guess[i] == 2 && mirror == FALSE)
646 if (path_guess.guess[i] == 4)
655 for (p=state->common->paths[counter].length-1;p>=0;p--) {
656 if (state->common->paths[counter].p[p] == -1) mirror = TRUE;
658 for (i=0;i<path_guess.length;i++) {
659 if (state->common->paths[counter].p[p] ==
660 state->common->paths[counter].mapping[i]) {
661 if (path_guess.guess[i] == 1 && mirror == TRUE)
663 if (path_guess.guess[i] == 2 && mirror == FALSE)
665 if (path_guess.guess[i] == 4)
673 assert(start_view >= 0 && start_view < pathlimit);
674 assert(end_view >= 0 && end_view < pathlimit);
675 i = start_view * pathlimit + end_view;
677 if (view_count[i] == 1) {
678 views.node = snewn(1,struct entry);
679 views.node->link = views.head;
680 views.node->guess = snewn(path_guess.length,int);
681 views.head = views.node;
682 views.node->start_view = start_view;
683 views.node->end_view = end_view;
684 memcpy(views.node->guess, path_guess.guess,
685 path_guess.length*sizeof(int));
687 } while (next_list(&path_guess, path_guess.length-1));
689 /* extract single entries from view list */
691 test_views.head = views.head;
692 test_views.node = views.node;
694 test_entry.guess = snewn(path_guess.length,int);
696 single_views.head = NULL;
697 single_views.node = NULL;
700 while (test_views.head != NULL) {
701 test_views.node = test_views.head;
702 test_views.head = test_views.head->link;
703 i = test_views.node->start_view * pathlimit + test_views.node->end_view;
704 if (view_count[i] == 1) {
705 single_views.node = snewn(1,struct entry);
706 single_views.node->link = single_views.head;
707 single_views.node->guess = snewn(path_guess.length,int);
708 single_views.head = single_views.node;
709 single_views.node->start_view = test_views.node->start_view;
710 single_views.node->end_view = test_views.node->end_view;
711 memcpy(single_views.node->guess, test_views.node->guess,
712 path_guess.length*sizeof(int));
719 if (count_uniques > 0) {
720 test_entry.start_view = 0;
721 test_entry.end_view = 0;
722 /* Choose one unique guess per random */
723 /* While we are busy with looping through single_views, we
724 * conveniently free the linked list single_view */
725 c = random_upto(rs,count_uniques);
726 while(single_views.head != NULL) {
727 single_views.node = single_views.head;
728 single_views.head = single_views.head->link;
730 memcpy(test_entry.guess, single_views.node->guess,
731 path_guess.length*sizeof(int));
732 test_entry.start_view = single_views.node->start_view;
733 test_entry.end_view = single_views.node->end_view;
735 sfree(single_views.node->guess);
736 sfree(single_views.node);
739 /* Modify state_guess according to path_guess.mapping */
740 for (i=0;i<path_guess.length;i++)
741 state->guess[state->common->paths[counter].mapping[i]] =
745 sfree(test_entry.guess);
747 while (views.head != NULL) {
748 views.node = views.head;
749 views.head = views.head->link;
750 sfree(views.node->guess);
754 sfree(path_guess.possible);
755 sfree(path_guess.guess);
760 int count_monsters(game_state *state,
761 int *cGhost, int *cVampire, int *cZombie) {
765 *cGhost = *cVampire = *cZombie = cNone = 0;
767 for (i=0;i<state->common->num_total;i++) {
768 if (state->guess[i] == 1) (*cGhost)++;
769 else if (state->guess[i] == 2) (*cVampire)++;
770 else if (state->guess[i] == 4) (*cZombie)++;
777 int check_numbers(game_state *state, int *guess) {
780 int count_ghosts, count_vampires, count_zombies;
782 count_ghosts = count_vampires = count_zombies = 0;
783 for (i=0;i<state->common->num_total;i++) {
784 if (guess[i] == 1) count_ghosts++;
785 if (guess[i] == 2) count_vampires++;
786 if (guess[i] == 4) count_zombies++;
791 if (count_ghosts > state->common->num_ghosts) valid = FALSE;
792 if (count_vampires > state->common->num_vampires) valid = FALSE;
793 if (count_zombies > state->common->num_zombies) valid = FALSE;
798 int check_solution(int *g, struct path path) {
805 for (i=0;i<path.length;i++) {
806 if (path.p[i] == -1) mirror = TRUE;
808 if (g[path.p[i]] == 1 && mirror) count++;
809 else if (g[path.p[i]] == 2 && !mirror) count++;
810 else if (g[path.p[i]] == 4) count++;
813 if (count != path.sightings_start) return FALSE;
817 for (i=path.length-1;i>=0;i--) {
818 if (path.p[i] == -1) mirror = TRUE;
820 if (g[path.p[i]] == 1 && mirror) count++;
821 else if (g[path.p[i]] == 2 && !mirror) count++;
822 else if (g[path.p[i]] == 4) count++;
825 if (count != path.sightings_end) return FALSE;
830 int solve_iterative(game_state *state, struct path *paths) {
840 loop.length = state->common->num_total;
841 guess = snewn(state->common->num_total,int);
842 possible = snewn(state->common->num_total,int);
844 for (i=0;i<state->common->num_total;i++) {
845 guess[i] = state->guess[i];
849 for (p=0;p<state->common->num_paths;p++) {
850 if (paths[p].num_monsters > 0) {
851 loop.length = paths[p].num_monsters;
852 loop.guess = snewn(paths[p].num_monsters,int);
853 loop.possible = snewn(paths[p].num_monsters,int);
855 for (i=0;i<paths[p].num_monsters;i++) {
856 switch (state->guess[paths[p].mapping[i]]) {
857 case 1: loop.guess[i] = 1; break;
858 case 2: loop.guess[i] = 2; break;
859 case 3: loop.guess[i] = 1; break;
860 case 4: loop.guess[i] = 4; break;
861 case 5: loop.guess[i] = 1; break;
862 case 6: loop.guess[i] = 2; break;
863 case 7: loop.guess[i] = 1; break;
865 loop.possible[i] = state->guess[paths[p].mapping[i]];
866 possible[paths[p].mapping[i]] = 0;
870 for (i=0;i<state->common->num_total;i++) {
871 guess[i] = state->guess[i];
874 for (i=0;i<paths[p].num_monsters;i++)
875 guess[paths[p].mapping[i]] = loop.guess[count++];
876 if (check_numbers(state,guess) &&
877 check_solution(guess,paths[p]))
878 for (j=0;j<paths[p].num_monsters;j++)
879 possible[paths[p].mapping[j]] |= loop.guess[j];
880 if (!next_list(&loop,loop.length-1)) break;
882 for (i=0;i<paths[p].num_monsters;i++)
883 state->guess[paths[p].mapping[i]] &=
884 possible[paths[p].mapping[i]];
885 sfree(loop.possible);
890 for (i=0;i<state->common->num_total;i++) {
891 if (state->guess[i] == 3 || state->guess[i] == 5 ||
892 state->guess[i] == 6 || state->guess[i] == 7) {
893 solved = FALSE; break;
903 int solve_bruteforce(game_state *state, struct path *paths) {
905 int number_solutions;
910 loop.guess = snewn(state->common->num_total,int);
911 loop.possible = snewn(state->common->num_total,int);
913 for (i=0;i<state->common->num_total;i++) {
914 loop.possible[i] = state->guess[i];
915 switch (state->guess[i]) {
916 case 1: loop.guess[i] = 1; break;
917 case 2: loop.guess[i] = 2; break;
918 case 3: loop.guess[i] = 1; break;
919 case 4: loop.guess[i] = 4; break;
920 case 5: loop.guess[i] = 1; break;
921 case 6: loop.guess[i] = 2; break;
922 case 7: loop.guess[i] = 1; break;
927 number_solutions = 0;
932 if (!check_numbers(state,loop.guess)) correct = FALSE;
934 for (p=0;p<state->common->num_paths;p++)
935 if (!check_solution(loop.guess,paths[p])) {
936 correct = FALSE; break;
941 if(number_solutions > 1) {
945 for (i=0;i<state->common->num_total;i++)
946 state->guess[i] = loop.guess[i];
948 if (!next_list(&loop,state->common->num_total -1)) {
953 sfree(loop.possible);
959 int path_cmp(const void *a, const void *b) {
960 const struct path *pa = (const struct path *)a;
961 const struct path *pb = (const struct path *)b;
962 return pa->num_monsters - pb->num_monsters;
965 static char *new_game_desc(const game_params *params, random_state *rs,
966 char **aux, int interactive) {
967 int i,count,c,w,h,r,p,g;
970 /* Variables for puzzle generation algorithm */
973 int count_ghosts, count_vampires, count_zombies;
977 /* Variables for solver algorithm */
978 int solved_iterative, solved_bruteforce, contains_inconsistency,
983 /* Variables for game description generation */
990 new = new_state(params);
993 /* Fill grid with random mirrors and (later to be populated)
994 * empty monster cells */
996 for (h=1;h<new->common->params.h+1;h++)
997 for (w=1;w<new->common->params.w+1;w++) {
998 c = random_upto(rs,5);
1000 new->common->grid[w+h*(new->common->params.w+2)] = CELL_EMPTY;
1001 new->common->xinfo[w+h*(new->common->params.w+2)] = count++;
1004 new->common->grid[w+h*(new->common->params.w+2)] =
1006 new->common->xinfo[w+h*(new->common->params.w+2)] = -1;
1009 new->common->grid[w+h*(new->common->params.w+2)] =
1011 new->common->xinfo[w+h*(new->common->params.w+2)] = -1;
1014 new->common->num_total = count; /* Total number of monsters in maze */
1016 /* Puzzle is boring if it has too few monster cells. Discard
1017 * grid, make new grid */
1018 if (new->common->num_total <= 4) {
1023 /* Monsters / Mirrors ratio should be balanced */
1024 ratio = (float)new->common->num_total /
1025 (float)(new->common->params.w * new->common->params.h);
1026 if (ratio < 0.48 || ratio > 0.78) {
1031 /* Assign clue identifiers */
1032 for (r=0;r<2*(new->common->params.w+new->common->params.h);r++) {
1034 gridno = range2grid(r,new->common->params.w,new->common->params.h,
1036 new->common->grid[x+y*(new->common->params.w +2)] = gridno;
1037 new->common->xinfo[x+y*(new->common->params.w +2)] = 0;
1039 /* The four corners don't matter at all for the game. Set them
1040 * all to zero, just to have a nice data structure */
1041 new->common->grid[0] = 0;
1042 new->common->xinfo[0] = 0;
1043 new->common->grid[new->common->params.w+1] = 0;
1044 new->common->xinfo[new->common->params.w+1] = 0;
1045 new->common->grid[new->common->params.w+1 + (new->common->params.h+1)*(new->common->params.w+2)] = 0;
1046 new->common->xinfo[new->common->params.w+1 + (new->common->params.h+1)*(new->common->params.w+2)] = 0;
1047 new->common->grid[(new->common->params.h+1)*(new->common->params.w+2)] = 0;
1048 new->common->xinfo[(new->common->params.h+1)*(new->common->params.w+2)] = 0;
1050 /* Initialize solution vector */
1051 new->guess = snewn(new->common->num_total,int);
1052 for (g=0;g<new->common->num_total;g++) new->guess[g] = 7;
1054 /* Initialize fixed flag from common. Not needed for the
1055 * puzzle generator; initialize it for having clean code */
1056 new->common->fixed = snewn(new->common->num_total,int);
1057 for (g=0;g<new->common->num_total;g++)
1058 new->common->fixed[g] = FALSE;
1060 /* paths generation */
1063 /* Grid is invalid if max. path length > threshold. Discard
1064 * grid, make new one */
1065 switch (new->common->params.diff) {
1066 case DIFF_EASY: max_length = min(new->common->params.w,new->common->params.h) + 1; break;
1067 case DIFF_NORMAL: max_length = (max(new->common->params.w,new->common->params.h) * 3) / 2; break;
1068 case DIFF_TRICKY: max_length = 9; break;
1069 default: max_length = 9; break;
1072 for (p=0;p<new->common->num_paths;p++) {
1073 if (new->common->paths[p].num_monsters > max_length) {
1082 qsort(new->common->paths, new->common->num_paths,
1083 sizeof(struct path), path_cmp);
1085 /* Grid monster initialization */
1086 /* For easy puzzles, we try to fill nearly the whole grid
1087 with unique solution paths (up to 2) For more difficult
1088 puzzles, we fill only roughly half the grid, and choose
1089 random monsters for the rest For hard puzzles, we fill
1090 even less paths with unique solutions */
1092 switch (new->common->params.diff) {
1093 case DIFF_EASY: filling = 2; break;
1094 case DIFF_NORMAL: filling = min( (new->common->params.w+new->common->params.h) , (new->common->num_total)/2 ); break;
1095 case DIFF_TRICKY: filling = max( (new->common->params.w+new->common->params.h) , (new->common->num_total)/2 ); break;
1096 default: filling = 0; break;
1100 while ( (count_monsters(new, &count_ghosts, &count_vampires,
1101 &count_zombies)) > filling) {
1102 if ((count) >= new->common->num_paths) break;
1103 if (new->common->paths[count].num_monsters == 0) {
1107 get_unique(new,count,rs);
1111 /* Fill any remaining ambiguous entries with random monsters */
1112 for(g=0;g<new->common->num_total;g++) {
1113 if (new->guess[g] == 7) {
1114 r = random_upto(rs,3);
1115 new->guess[g] = (r == 0) ? 1 : ( (r == 1) ? 2 : 4 );
1119 /* Determine all hints */
1120 count_monsters(new, &new->common->num_ghosts,
1121 &new->common->num_vampires, &new->common->num_zombies);
1123 /* Puzzle is trivial if it has only one type of monster. Discard. */
1124 if ((new->common->num_ghosts == 0 && new->common->num_vampires == 0) ||
1125 (new->common->num_ghosts == 0 && new->common->num_zombies == 0) ||
1126 (new->common->num_vampires == 0 && new->common->num_zombies == 0)) {
1131 /* Discard puzzle if difficulty Tricky, and it has only 1
1132 * member of any monster type */
1133 if (new->common->params.diff == DIFF_TRICKY &&
1134 (new->common->num_ghosts <= 1 ||
1135 new->common->num_vampires <= 1 || new->common->num_zombies <= 1)) {
1140 for (w=1;w<new->common->params.w+1;w++)
1141 for (h=1;h<new->common->params.h+1;h++) {
1142 c = new->common->xinfo[w+h*(new->common->params.w+2)];
1144 if (new->guess[c] == 1) new->common->grid[w+h*(new->common->params.w+2)] = CELL_GHOST;
1145 if (new->guess[c] == 2) new->common->grid[w+h*(new->common->params.w+2)] = CELL_VAMPIRE;
1146 if (new->guess[c] == 4) new->common->grid[w+h*(new->common->params.w+2)] = CELL_ZOMBIE;
1150 /* Prepare path information needed by the solver (containing all hints) */
1151 for (p=0;p<new->common->num_paths;p++) {
1154 new->common->paths[p].sightings_start = 0;
1155 new->common->paths[p].sightings_end = 0;
1158 for (g=0;g<new->common->paths[p].length;g++) {
1160 if (new->common->paths[p].p[g] == -1) mirror = TRUE;
1162 if (new->guess[new->common->paths[p].p[g]] == 1 && mirror == TRUE) (new->common->paths[p].sightings_start)++;
1163 else if (new->guess[new->common->paths[p].p[g]] == 2 && mirror == FALSE) (new->common->paths[p].sightings_start)++;
1164 else if (new->guess[new->common->paths[p].p[g]] == 4) (new->common->paths[p].sightings_start)++;
1169 for (g=new->common->paths[p].length-1;g>=0;g--) {
1170 if (new->common->paths[p].p[g] == -1) mirror = TRUE;
1172 if (new->guess[new->common->paths[p].p[g]] == 1 && mirror == TRUE) (new->common->paths[p].sightings_end)++;
1173 else if (new->guess[new->common->paths[p].p[g]] == 2 && mirror == FALSE) (new->common->paths[p].sightings_end)++;
1174 else if (new->guess[new->common->paths[p].p[g]] == 4) (new->common->paths[p].sightings_end)++;
1178 range2grid(new->common->paths[p].grid_start,
1179 new->common->params.w,new->common->params.h,&x,&y);
1180 new->common->grid[x+y*(new->common->params.w +2)] =
1181 new->common->paths[p].sightings_start;
1182 range2grid(new->common->paths[p].grid_end,
1183 new->common->params.w,new->common->params.h,&x,&y);
1184 new->common->grid[x+y*(new->common->params.w +2)] =
1185 new->common->paths[p].sightings_end;
1188 /* Try to solve the puzzle with the iterative solver */
1189 old_guess = snewn(new->common->num_total,int);
1190 for (p=0;p<new->common->num_total;p++) {
1194 iterative_depth = 0;
1195 solved_iterative = FALSE;
1196 contains_inconsistency = FALSE;
1197 count_ambiguous = 0;
1202 solved_iterative = solve_iterative(new,new->common->paths);
1204 for (p=0;p<new->common->num_total;p++) {
1205 if (new->guess[p] != old_guess[p]) no_change = FALSE;
1206 old_guess[p] = new->guess[p];
1207 if (new->guess[p] == 0) contains_inconsistency = TRUE;
1209 if (solved_iterative || no_change) break;
1212 /* If necessary, try to solve the puzzle with the brute-force solver */
1213 solved_bruteforce = FALSE;
1214 if (new->common->params.diff != DIFF_EASY &&
1215 !solved_iterative && !contains_inconsistency) {
1216 for (p=0;p<new->common->num_total;p++)
1217 if (new->guess[p] != 1 && new->guess[p] != 2 &&
1218 new->guess[p] != 4) count_ambiguous++;
1220 solved_bruteforce = solve_bruteforce(new, new->common->paths);
1223 /* Determine puzzle difficulty level */
1224 if (new->common->params.diff == DIFF_EASY && solved_iterative &&
1225 iterative_depth <= 3 && !contains_inconsistency) {
1226 /* printf("Puzzle level: EASY Level %d Ratio %f Ambiguous %d (Found after %i tries)\n",iterative_depth, ratio, count_ambiguous, i); */
1230 if (new->common->params.diff == DIFF_NORMAL &&
1231 ((solved_iterative && iterative_depth > 3) ||
1232 (solved_bruteforce && count_ambiguous < 4)) &&
1233 !contains_inconsistency) {
1234 /* printf("Puzzle level: NORMAL Level %d Ratio %f Ambiguous %d (Found after %d tries)\n", iterative_depth, ratio, count_ambiguous, i); */
1237 if (new->common->params.diff == DIFF_TRICKY &&
1238 solved_bruteforce && iterative_depth > 0 &&
1239 count_ambiguous >= 4 && !contains_inconsistency) {
1240 /* printf("Puzzle level: TRICKY Level %d Ratio %f Ambiguous %d (Found after %d tries)\n", iterative_depth, ratio, count_ambiguous, i); */
1244 /* If puzzle is not solvable or does not satisfy the desired
1245 * difficulty level, free memory and start from scratch */
1251 /* We have a valid puzzle! */
1253 desc = snewn(10 + new->common->wh +
1254 6*(new->common->params.w + new->common->params.h), char);
1257 /* Encode monster counts */
1258 e += sprintf(e, "%d,", new->common->num_ghosts);
1259 e += sprintf(e, "%d,", new->common->num_vampires);
1260 e += sprintf(e, "%d,", new->common->num_zombies);
1264 for (y=1;y<new->common->params.h+1;y++)
1265 for (x=1;x<new->common->params.w+1;x++) {
1266 c = new->common->grid[x+y*(new->common->params.w+2)];
1271 if (c != CELL_MIRROR_L && c != CELL_MIRROR_R) {
1274 else if (c == CELL_MIRROR_L) {
1275 if (count > 0) *e++ = (count-1 + 'a');
1280 if (count > 0) *e++ = (count-1 + 'a');
1285 if (count > 0) *e++ = (count-1 + 'a');
1288 for (p=0;p<2*(new->common->params.w + new->common->params.h);p++) {
1289 range2grid(p,new->common->params.w,new->common->params.h,&x,&y);
1290 e += sprintf(e, ",%d", new->common->grid[x+y*(new->common->params.w+2)]);
1294 desc = sresize(desc, e - desc, char);
1302 void num2grid(int num, int width, int height, int *x, int *y) {
1308 static game_state *new_game(midend *me, const game_params *params,
1315 game_state *state = new_state(params);
1317 state->common->num_ghosts = atoi(desc);
1318 while (*desc && isdigit((unsigned char)*desc)) desc++;
1320 state->common->num_vampires = atoi(desc);
1321 while (*desc && isdigit((unsigned char)*desc)) desc++;
1323 state->common->num_zombies = atoi(desc);
1324 while (*desc && isdigit((unsigned char)*desc)) desc++;
1327 state->common->num_total = state->common->num_ghosts + state->common->num_vampires + state->common->num_zombies;
1329 state->guess = snewn(state->common->num_total,int);
1330 state->pencils = snewn(state->common->num_total,unsigned char);
1331 state->common->fixed = snewn(state->common->num_total,int);
1332 for (i=0;i<state->common->num_total;i++) {
1333 state->guess[i] = 7;
1334 state->pencils[i] = 0;
1335 state->common->fixed[i] = FALSE;
1337 for (i=0;i<state->common->wh;i++)
1338 state->cell_errors[i] = FALSE;
1339 for (i=0;i<2*state->common->num_paths;i++)
1340 state->hint_errors[i] = FALSE;
1342 state->count_errors[i] = FALSE;
1346 while (*desc != ',') {
1351 num2grid(n,state->common->params.w,state->common->params.h,&x,&y);
1352 state->common->grid[x+y*(state->common->params.w +2)] = CELL_MIRROR_L;
1353 state->common->xinfo[x+y*(state->common->params.w+2)] = -1;
1356 else if (*desc == 'R') {
1357 num2grid(n,state->common->params.w,state->common->params.h,&x,&y);
1358 state->common->grid[x+y*(state->common->params.w +2)] = CELL_MIRROR_R;
1359 state->common->xinfo[x+y*(state->common->params.w+2)] = -1;
1362 else if (*desc == 'G') {
1363 num2grid(n,state->common->params.w,state->common->params.h,&x,&y);
1364 state->common->grid[x+y*(state->common->params.w +2)] = CELL_GHOST;
1365 state->common->xinfo[x+y*(state->common->params.w+2)] = count;
1366 state->guess[count] = 1;
1367 state->common->fixed[count++] = TRUE;
1370 else if (*desc == 'V') {
1371 num2grid(n,state->common->params.w,state->common->params.h,&x,&y);
1372 state->common->grid[x+y*(state->common->params.w +2)] = CELL_VAMPIRE;
1373 state->common->xinfo[x+y*(state->common->params.w+2)] = count;
1374 state->guess[count] = 2;
1375 state->common->fixed[count++] = TRUE;
1378 else if (*desc == 'Z') {
1379 num2grid(n,state->common->params.w,state->common->params.h,&x,&y);
1380 state->common->grid[x+y*(state->common->params.w +2)] = CELL_ZOMBIE;
1381 state->common->xinfo[x+y*(state->common->params.w+2)] = count;
1382 state->guess[count] = 4;
1383 state->common->fixed[count++] = TRUE;
1387 c = *desc - ('a' -1);
1389 num2grid(n,state->common->params.w,state->common->params.h,&x,&y);
1390 state->common->grid[x+y*(state->common->params.w +2)] = CELL_EMPTY;
1391 state->common->xinfo[x+y*(state->common->params.w+2)] = count;
1392 state->guess[count] = 7;
1393 state->common->fixed[count++] = FALSE;
1401 for (i=0;i<2*(state->common->params.w + state->common->params.h);i++) {
1405 sights = atoi(desc);
1406 while (*desc && isdigit((unsigned char)*desc)) desc++;
1410 range2grid(i,state->common->params.w,state->common->params.h,&x,&y);
1411 state->common->grid[x+y*(state->common->params.w +2)] = sights;
1412 state->common->xinfo[x+y*(state->common->params.w +2)] = -2;
1415 state->common->grid[0] = 0;
1416 state->common->xinfo[0] = -2;
1417 state->common->grid[state->common->params.w+1] = 0;
1418 state->common->xinfo[state->common->params.w+1] = -2;
1419 state->common->grid[state->common->params.w+1 + (state->common->params.h+1)*(state->common->params.w+2)] = 0;
1420 state->common->xinfo[state->common->params.w+1 + (state->common->params.h+1)*(state->common->params.w+2)] = -2;
1421 state->common->grid[(state->common->params.h+1)*(state->common->params.w+2)] = 0;
1422 state->common->xinfo[(state->common->params.h+1)*(state->common->params.w+2)] = -2;
1425 qsort(state->common->paths, state->common->num_paths, sizeof(struct path), path_cmp);
1430 static char *validate_desc(const game_params *params, const char *desc)
1433 int w = params->w, h = params->h;
1438 const char *desc_s = desc;
1441 if (!*desc) return "Faulty game description";
1442 while (*desc && isdigit((unsigned char)*desc)) { desc++; }
1443 if (*desc != ',') return "Invalid character in number list";
1448 area = monsters = monster_count = 0;
1450 monster_count += atoi(desc);
1451 while (*desc && isdigit((unsigned char)*desc)) desc++;
1454 while (*desc && *desc != ',') {
1455 if (*desc >= 'a' && *desc <= 'z') {
1456 area += *desc - 'a' +1; monsters += *desc - 'a' +1;
1457 } else if (*desc == 'G' || *desc == 'V' || *desc == 'Z') {
1459 } else if (*desc == 'L' || *desc == 'R') {
1462 return "Invalid character in grid specification";
1465 if (area < wh) return "Not enough data to fill grid";
1466 else if (area > wh) return "Too much data to fill grid";
1467 if (monsters != monster_count)
1468 return "Monster numbers do not match grid spaces";
1470 for (i = 0; i < 2*(w+h); i++) {
1471 if (!*desc) return "Not enough numbers given after grid specification";
1472 else if (*desc != ',') return "Invalid character in number list";
1474 while (*desc && isdigit((unsigned char)*desc)) { desc++; }
1477 if (*desc) return "Unexpected additional data at end of game description";
1482 static char *solve_game(const game_state *state_start, const game_state *currstate,
1483 const char *aux, char **error)
1487 int iterative_depth;
1488 int solved_iterative, solved_bruteforce, contains_inconsistency,
1494 game_state *solve_state = dup_game(currstate);
1496 old_guess = snewn(solve_state->common->num_total,int);
1497 for (p=0;p<solve_state->common->num_total;p++) {
1498 if (solve_state->common->fixed[p]) {
1499 old_guess[p] = solve_state->guess[p] = state_start->guess[p];
1502 old_guess[p] = solve_state->guess[p] = 7;
1505 iterative_depth = 0;
1506 solved_iterative = FALSE;
1507 contains_inconsistency = FALSE;
1508 count_ambiguous = 0;
1510 /* Try to solve the puzzle with the iterative solver */
1515 solve_iterative(solve_state,solve_state->common->paths);
1517 for (p=0;p<solve_state->common->num_total;p++) {
1518 if (solve_state->guess[p] != old_guess[p]) no_change = FALSE;
1519 old_guess[p] = solve_state->guess[p];
1520 if (solve_state->guess[p] == 0) contains_inconsistency = TRUE;
1522 if (solved_iterative || no_change || contains_inconsistency) break;
1525 if (contains_inconsistency) {
1526 *error = "Puzzle is inconsistent";
1528 free_game(solve_state);
1532 /* If necessary, try to solve the puzzle with the brute-force solver */
1533 solved_bruteforce = FALSE;
1534 if (!solved_iterative) {
1535 for (p=0;p<solve_state->common->num_total;p++)
1536 if (solve_state->guess[p] != 1 && solve_state->guess[p] != 2 &&
1537 solve_state->guess[p] != 4) count_ambiguous++;
1539 solve_bruteforce(solve_state, solve_state->common->paths);
1542 if (!solved_iterative && !solved_bruteforce) {
1543 *error = "Puzzle is unsolvable";
1545 free_game(solve_state);
1549 /* printf("Puzzle solved at level %s, iterations %d, ambiguous %d\n", (solved_bruteforce ? "TRICKY" : "NORMAL"), iterative_depth, count_ambiguous); */
1551 move = snewn(solve_state->common->num_total * 4 +2, char);
1554 for (i = 0; i < solve_state->common->num_total; i++) {
1555 if (solve_state->guess[i] == 1) c += sprintf(c, ";G%d", i);
1556 if (solve_state->guess[i] == 2) c += sprintf(c, ";V%d", i);
1557 if (solve_state->guess[i] == 4) c += sprintf(c, ";Z%d", i);
1560 move = sresize(move, c - move, char);
1563 free_game(solve_state);
1567 static int game_can_format_as_text_now(const game_params *params)
1572 static char *game_text_format(const game_state *state)
1578 ret = snewn(50 + 6*(state->common->params.w +2) +
1579 6*(state->common->params.h+2) +
1580 3*(state->common->params.w * state->common->params.h), char);
1582 sprintf(ret,"G: %d V: %d Z: %d\n\n",state->common->num_ghosts,
1583 state->common->num_vampires, state->common->num_zombies);
1585 for (h=0;h<state->common->params.h+2;h++) {
1586 for (w=0;w<state->common->params.w+2;w++) {
1587 c = state->common->grid[w+h*(state->common->params.w+2)];
1588 xi = state->common->xinfo[w+h*(state->common->params.w+2)];
1589 r = grid2range(w,h,state->common->params.w,state->common->params.h);
1591 sprintf(buf,"%2d", c); strcat(ret,buf);
1592 } else if (c == CELL_MIRROR_L) {
1593 sprintf(buf," \\"); strcat(ret,buf);
1594 } else if (c == CELL_MIRROR_R) {
1595 sprintf(buf," /"); strcat(ret,buf);
1596 } else if (xi >= 0) {
1597 g = state->guess[xi];
1598 if (g == 1) { sprintf(buf," G"); strcat(ret,buf); }
1599 else if (g == 2) { sprintf(buf," V"); strcat(ret,buf); }
1600 else if (g == 4) { sprintf(buf," Z"); strcat(ret,buf); }
1601 else { sprintf(buf," ."); strcat(ret,buf); }
1603 sprintf(buf," "); strcat(ret,buf);
1606 sprintf(buf,"\n"); strcat(ret,buf);
1613 int hx, hy; /* as for solo.c, highlight pos */
1614 int hshow, hpencil, hcursor; /* show state, type, and ?cursor. */
1618 static game_ui *new_ui(const game_state *state)
1620 game_ui *ui = snew(game_ui);
1621 ui->hx = ui->hy = 0;
1622 ui->hpencil = ui->hshow = ui->hcursor = 0;
1627 static void free_ui(game_ui *ui) {
1632 static char *encode_ui(const game_ui *ui)
1637 static void decode_ui(game_ui *ui, const char *encoding)
1642 static void game_changed_state(game_ui *ui, const game_state *oldstate,
1643 const game_state *newstate)
1645 /* See solo.c; if we were pencil-mode highlighting and
1646 * somehow a square has just been properly filled, cancel
1648 if (ui->hshow && ui->hpencil && !ui->hcursor) {
1649 int g = newstate->guess[newstate->common->xinfo[ui->hx + ui->hy*(newstate->common->params.w+2)]];
1650 if (g == 1 || g == 2 || g == 4)
1655 struct game_drawstate {
1656 int tilesize, started, solved;
1660 unsigned char *pencils;
1662 unsigned char count_errors[3];
1663 unsigned char *cell_errors;
1664 unsigned char *hint_errors;
1666 int hx, hy, hshow, hpencil; /* as for game_ui. */
1671 #define TILESIZE (ds->tilesize)
1672 #define BORDER (TILESIZE/4)
1674 static char *interpret_move(const game_state *state, game_ui *ui,
1675 const game_drawstate *ds,
1676 int x, int y, int button)
1682 gx = ((x-BORDER-1) / TILESIZE );
1683 gy = ((y-BORDER-2) / TILESIZE ) - 1;
1685 if (button == 'a' || button == 'A') {
1686 ui->ascii = !ui->ascii;
1690 if (ui->hshow == 1 && ui->hpencil == 0) {
1691 xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)];
1692 if (xi >= 0 && !state->common->fixed[xi]) {
1693 if (button == 'g' || button == 'G' || button == '1') {
1694 if (!ui->hcursor) ui->hshow = 0;
1695 sprintf(buf,"G%d",xi);
1698 if (button == 'v' || button == 'V' || button == '2') {
1699 if (!ui->hcursor) ui->hshow = 0;
1700 sprintf(buf,"V%d",xi);
1703 if (button == 'z' || button == 'Z' || button == '3') {
1704 if (!ui->hcursor) ui->hshow = 0;
1705 sprintf(buf,"Z%d",xi);
1708 if (button == 'e' || button == 'E' || button == CURSOR_SELECT2 ||
1709 button == '0' || button == '\b' ) {
1710 if (!ui->hcursor) ui->hshow = 0;
1711 sprintf(buf,"E%d",xi);
1717 if (IS_CURSOR_MOVE(button)) {
1718 if (ui->hx == 0 && ui->hy == 0) {
1722 else switch (button) {
1723 case CURSOR_UP: ui->hy -= (ui->hy > 1) ? 1 : 0; break;
1724 case CURSOR_DOWN: ui->hy += (ui->hy < ds->h) ? 1 : 0; break;
1725 case CURSOR_RIGHT: ui->hx += (ui->hx < ds->w) ? 1 : 0; break;
1726 case CURSOR_LEFT: ui->hx -= (ui->hx > 1) ? 1 : 0; break;
1728 ui->hshow = ui->hcursor = 1;
1731 if (ui->hshow && button == CURSOR_SELECT) {
1732 ui->hpencil = 1 - ui->hpencil;
1737 if (ui->hshow == 1 && ui->hpencil == 1) {
1738 xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)];
1739 if (xi >= 0 && !state->common->fixed[xi]) {
1740 if (button == 'g' || button == 'G' || button == '1') {
1741 sprintf(buf,"g%d",xi);
1742 if (!ui->hcursor) ui->hpencil = ui->hshow = 0;
1745 if (button == 'v' || button == 'V' || button == '2') {
1746 sprintf(buf,"v%d",xi);
1747 if (!ui->hcursor) ui->hpencil = ui->hshow = 0;
1750 if (button == 'z' || button == 'Z' || button == '3') {
1751 sprintf(buf,"z%d",xi);
1752 if (!ui->hcursor) ui->hpencil = ui->hshow = 0;
1755 if (button == 'e' || button == 'E' || button == CURSOR_SELECT2 ||
1756 button == '0' || button == '\b') {
1757 sprintf(buf,"E%d",xi);
1758 if (!ui->hcursor) ui->hpencil = ui->hshow = 0;
1764 if (gx > 0 && gx < ds->w+1 && gy > 0 && gy < ds->h+1) {
1765 xi = state->common->xinfo[gx+gy*(state->common->params.w+2)];
1766 if (xi >= 0 && !state->common->fixed[xi]) {
1767 g = state->guess[xi];
1768 if (ui->hshow == 0) {
1769 if (button == LEFT_BUTTON) {
1770 ui->hshow = 1; ui->hpencil = 0; ui->hcursor = 0;
1771 ui->hx = gx; ui->hy = gy;
1774 else if (button == RIGHT_BUTTON && g == 7) {
1775 ui->hshow = 1; ui->hpencil = 1; ui->hcursor = 0;
1776 ui->hx = gx; ui->hy = gy;
1780 else if (ui->hshow == 1) {
1781 if (button == LEFT_BUTTON) {
1782 if (ui->hpencil == 0) {
1783 if (gx == ui->hx && gy == ui->hy) {
1784 ui->hshow = 0; ui->hpencil = 0; ui->hcursor = 0;
1785 ui->hx = 0; ui->hy = 0;
1789 ui->hshow = 1; ui->hpencil = 0; ui->hcursor = 0;
1790 ui->hx = gx; ui->hy = gy;
1795 ui->hshow = 1; ui->hpencil = 0; ui->hcursor = 0;
1796 ui->hx = gx; ui->hy = gy;
1800 else if (button == RIGHT_BUTTON) {
1801 if (ui->hpencil == 0 && g == 7) {
1802 ui->hshow = 1; ui->hpencil = 1; ui->hcursor = 0;
1803 ui->hx = gx; ui->hy = gy;
1807 if (gx == ui->hx && gy == ui->hy) {
1808 ui->hshow = 0; ui->hpencil = 0; ui->hcursor = 0;
1809 ui->hx = 0; ui->hy = 0;
1813 ui->hshow = 1; ui->hpencil = 1; ui->hcursor = 0;
1814 ui->hx = gx; ui->hy = gy;
1826 int check_numbers_draw(game_state *state, int *guess) {
1829 int count_ghosts, count_vampires, count_zombies;
1831 count_ghosts = count_vampires = count_zombies = 0;
1832 for (i=0;i<state->common->num_total;i++) {
1833 if (guess[i] == 1) count_ghosts++;
1834 if (guess[i] == 2) count_vampires++;
1835 if (guess[i] == 4) count_zombies++;
1839 filled = (count_ghosts + count_vampires + count_zombies >=
1840 state->common->num_total);
1842 if (count_ghosts > state->common->num_ghosts ||
1843 (filled && count_ghosts != state->common->num_ghosts) ) {
1845 state->count_errors[0] = TRUE;
1846 for (x=1;x<state->common->params.w+1;x++)
1847 for (y=1;y<state->common->params.h+1;y++) {
1848 xy = x+y*(state->common->params.w+2);
1849 if (state->common->xinfo[xy] >= 0 &&
1850 guess[state->common->xinfo[xy]] == 1)
1851 state->cell_errors[xy] = TRUE;
1854 if (count_vampires > state->common->num_vampires ||
1855 (filled && count_vampires != state->common->num_vampires) ) {
1857 state->count_errors[1] = TRUE;
1858 for (x=1;x<state->common->params.w+1;x++)
1859 for (y=1;y<state->common->params.h+1;y++) {
1860 xy = x+y*(state->common->params.w+2);
1861 if (state->common->xinfo[xy] >= 0 &&
1862 guess[state->common->xinfo[xy]] == 2)
1863 state->cell_errors[xy] = TRUE;
1866 if (count_zombies > state->common->num_zombies ||
1867 (filled && count_zombies != state->common->num_zombies) ) {
1869 state->count_errors[2] = TRUE;
1870 for (x=1;x<state->common->params.w+1;x++)
1871 for (y=1;y<state->common->params.h+1;y++) {
1872 xy = x+y*(state->common->params.w+2);
1873 if (state->common->xinfo[xy] >= 0 &&
1874 guess[state->common->xinfo[xy]] == 4)
1875 state->cell_errors[xy] = TRUE;
1882 int check_path_solution(game_state *state, int p) {
1894 for (i=0;i<state->common->paths[p].length;i++) {
1895 if (state->common->paths[p].p[i] == -1) mirror = TRUE;
1897 if (state->guess[state->common->paths[p].p[i]] == 1 && mirror)
1899 else if (state->guess[state->common->paths[p].p[i]] == 2 && !mirror)
1901 else if (state->guess[state->common->paths[p].p[i]] == 4)
1903 else if (state->guess[state->common->paths[p].p[i]] == 7)
1908 if (unfilled == 0 && count != state->common->paths[p].sightings_start) {
1910 state->hint_errors[state->common->paths[p].grid_start] = TRUE;
1916 for (i=state->common->paths[p].length-1;i>=0;i--) {
1917 if (state->common->paths[p].p[i] == -1) mirror = TRUE;
1919 if (state->guess[state->common->paths[p].p[i]] == 1 && mirror)
1921 else if (state->guess[state->common->paths[p].p[i]] == 2 && !mirror)
1923 else if (state->guess[state->common->paths[p].p[i]] == 4)
1925 else if (state->guess[state->common->paths[p].p[i]] == 7)
1930 if (unfilled == 0 && count != state->common->paths[p].sightings_end) {
1932 state->hint_errors[state->common->paths[p].grid_end] = TRUE;
1936 for (i=0;i<state->common->paths[p].length;i++)
1937 state->cell_errors[state->common->paths[p].xy[i]] = TRUE;
1943 static game_state *execute_move(const game_state *state, const char *move)
1950 game_state *ret = dup_game(state);
1959 if (c == 'G' || c == 'V' || c == 'Z' || c == 'E' ||
1960 c == 'g' || c == 'v' || c == 'z') {
1962 sscanf(move, "%d%n", &x, &n);
1963 if (c == 'G') ret->guess[x] = 1;
1964 if (c == 'V') ret->guess[x] = 2;
1965 if (c == 'Z') ret->guess[x] = 4;
1966 if (c == 'E') { ret->guess[x] = 7; ret->pencils[x] = 0; }
1967 if (c == 'g') ret->pencils[x] ^= 1;
1968 if (c == 'v') ret->pencils[x] ^= 2;
1969 if (c == 'z') ret->pencils[x] ^= 4;
1972 if (*move == ';') move++;
1977 for (i=0;i<ret->common->wh;i++) ret->cell_errors[i] = FALSE;
1978 for (i=0;i<2*ret->common->num_paths;i++) ret->hint_errors[i] = FALSE;
1979 for (i=0;i<3;i++) ret->count_errors[i] = FALSE;
1981 if (!check_numbers_draw(ret,ret->guess)) correct = FALSE;
1983 for (p=0;p<state->common->num_paths;p++)
1984 if (!check_path_solution(ret,p)) correct = FALSE;
1986 for (i=0;i<state->common->num_total;i++)
1987 if (!(ret->guess[i] == 1 || ret->guess[i] == 2 ||
1988 ret->guess[i] == 4)) correct = FALSE;
1990 if (correct && !solver) ret->solved = TRUE;
1991 if (solver) ret->cheated = TRUE;
1996 /* ----------------------------------------------------------------------
2000 #define PREFERRED_TILE_SIZE 64
2002 static void game_compute_size(const game_params *params, int tilesize,
2005 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2006 struct { int tilesize; } ads, *ds = &ads;
2007 ads.tilesize = tilesize;
2009 *x = 2*BORDER+(params->w+2)*TILESIZE;
2010 *y = 2*BORDER+(params->h+3)*TILESIZE;
2014 static void game_set_size(drawing *dr, game_drawstate *ds,
2015 const game_params *params, int tilesize)
2017 ds->tilesize = tilesize;
2021 #define COLOUR(ret, i, r, g, b) ((ret[3*(i)+0] = (r)), (ret[3*(i)+1] = (g)), (ret[3*(i)+2] = (b)))
2023 static float *game_colours(frontend *fe, int *ncolours)
2025 float *ret = snewn(3 * NCOLOURS, float);
2027 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
2029 ret[COL_GRID * 3 + 0] = 0.0F;
2030 ret[COL_GRID * 3 + 1] = 0.0F;
2031 ret[COL_GRID * 3 + 2] = 0.0F;
2033 ret[COL_TEXT * 3 + 0] = 0.0F;
2034 ret[COL_TEXT * 3 + 1] = 0.0F;
2035 ret[COL_TEXT * 3 + 2] = 0.0F;
2037 ret[COL_ERROR * 3 + 0] = 1.0F;
2038 ret[COL_ERROR * 3 + 1] = 0.0F;
2039 ret[COL_ERROR * 3 + 2] = 0.0F;
2041 ret[COL_HIGHLIGHT * 3 + 0] = 0.78F * ret[COL_BACKGROUND * 3 + 0];
2042 ret[COL_HIGHLIGHT * 3 + 1] = 0.78F * ret[COL_BACKGROUND * 3 + 1];
2043 ret[COL_HIGHLIGHT * 3 + 2] = 0.78F * ret[COL_BACKGROUND * 3 + 2];
2045 ret[COL_FLASH * 3 + 0] = 1.0F;
2046 ret[COL_FLASH * 3 + 1] = 1.0F;
2047 ret[COL_FLASH * 3 + 2] = 1.0F;
2049 ret[COL_GHOST * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.5F;
2050 ret[COL_GHOST * 3 + 1] = ret[COL_BACKGROUND * 3 + 0];
2051 ret[COL_GHOST * 3 + 2] = ret[COL_BACKGROUND * 3 + 0];
2053 ret[COL_ZOMBIE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.5F;
2054 ret[COL_ZOMBIE * 3 + 1] = ret[COL_BACKGROUND * 3 + 0];
2055 ret[COL_ZOMBIE * 3 + 2] = ret[COL_BACKGROUND * 3 + 0] * 0.5F;
2057 ret[COL_VAMPIRE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0];
2058 ret[COL_VAMPIRE * 3 + 1] = ret[COL_BACKGROUND * 3 + 0] * 0.9F;
2059 ret[COL_VAMPIRE * 3 + 2] = ret[COL_BACKGROUND * 3 + 0] * 0.9F;
2061 *ncolours = NCOLOURS;
2065 static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
2068 struct game_drawstate *ds = snew(struct game_drawstate);
2071 ds->started = ds->solved = FALSE;
2072 ds->w = state->common->params.w;
2073 ds->h = state->common->params.h;
2076 ds->count_errors[0] = FALSE;
2077 ds->count_errors[1] = FALSE;
2078 ds->count_errors[2] = FALSE;
2080 ds->monsters = snewn(state->common->num_total,int);
2081 for (i=0;i<(state->common->num_total);i++)
2082 ds->monsters[i] = 7;
2083 ds->pencils = snewn(state->common->num_total,unsigned char);
2084 for (i=0;i<state->common->num_total;i++)
2087 ds->cell_errors = snewn(state->common->wh,unsigned char);
2088 for (i=0;i<state->common->wh;i++)
2089 ds->cell_errors[i] = FALSE;
2090 ds->hint_errors = snewn(2*state->common->num_paths,unsigned char);
2091 for (i=0;i<2*state->common->num_paths;i++)
2092 ds->hint_errors[i] = FALSE;
2094 ds->hshow = ds->hpencil = ds->hflash = 0;
2095 ds->hx = ds->hy = 0;
2099 static void game_free_drawstate(drawing *dr, game_drawstate *ds) {
2100 sfree(ds->hint_errors);
2101 sfree(ds->cell_errors);
2103 sfree(ds->monsters);
2108 static void draw_cell_background(drawing *dr, game_drawstate *ds,
2109 const game_state *state, const game_ui *ui,
2114 dx = BORDER+(x* ds->tilesize)+(TILESIZE/2);
2115 dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE;
2117 hon = (ui->hshow && x == ui->hx && y == ui->hy);
2118 draw_rect(dr,dx-(TILESIZE/2)+1,dy-(TILESIZE/2)+1,TILESIZE-1,TILESIZE-1,(hon && !ui->hpencil) ? COL_HIGHLIGHT : COL_BACKGROUND);
2120 if (hon && ui->hpencil) {
2122 coords[0] = dx-(TILESIZE/2)+1;
2123 coords[1] = dy-(TILESIZE/2)+1;
2124 coords[2] = coords[0] + TILESIZE/2;
2125 coords[3] = coords[1];
2126 coords[4] = coords[0];
2127 coords[5] = coords[1] + TILESIZE/2;
2128 draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
2131 draw_update(dr,dx-(TILESIZE/2)+1,dy-(TILESIZE/2)+1,TILESIZE-1,TILESIZE-1);
2136 static void draw_circle_or_point(drawing *dr, int cx, int cy, int radius,
2140 draw_circle(dr, cx, cy, radius, colour, colour);
2142 draw_rect(dr, cx, cy, 1, 1, colour);
2145 static void draw_monster(drawing *dr, game_drawstate *ds, int x, int y,
2146 int tilesize, int hflash, int monster)
2148 int black = (hflash ? COL_FLASH : COL_TEXT);
2150 if (monster == 1) { /* ghost */
2153 clip(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize-3,tilesize/2+1);
2154 draw_circle(dr,x,y,2*tilesize/5, COL_GHOST,black);
2158 poly[i++] = x - 2*tilesize/5;
2160 poly[i++] = x - 2*tilesize/5;
2161 poly[i++] = y + 2*tilesize/5;
2163 for (j = 0; j < 3; j++) {
2164 int total = (2*tilesize/5) * 2;
2165 int before = total * j / 3;
2166 int after = total * (j+1) / 3;
2167 int mid = (before + after) / 2;
2168 poly[i++] = x - 2*tilesize/5 + mid;
2169 poly[i++] = y + 2*tilesize/5 - (total / 6);
2170 poly[i++] = x - 2*tilesize/5 + after;
2171 poly[i++] = y + 2*tilesize/5;
2174 poly[i++] = x + 2*tilesize/5;
2177 clip(dr,x-(tilesize/2)+2,y,tilesize-3,tilesize-(tilesize/2)-1);
2178 draw_polygon(dr, poly, i/2, COL_GHOST, black);
2181 draw_circle(dr,x-tilesize/6,y-tilesize/12,tilesize/10,
2182 COL_BACKGROUND,black);
2183 draw_circle(dr,x+tilesize/6,y-tilesize/12,tilesize/10,
2184 COL_BACKGROUND,black);
2186 draw_circle_or_point(dr,x-tilesize/6+1+tilesize/48,y-tilesize/12,
2188 draw_circle_or_point(dr,x+tilesize/6+1+tilesize/48,y-tilesize/12,
2191 } else if (monster == 2) { /* vampire */
2194 clip(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize-3,tilesize/2);
2195 draw_circle(dr,x,y,2*tilesize/5,black,black);
2198 clip(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize/2+1,tilesize/2);
2199 draw_circle(dr,x-tilesize/7,y,2*tilesize/5-tilesize/7,
2202 clip(dr,x,y-(tilesize/2)+2,tilesize/2+1,tilesize/2);
2203 draw_circle(dr,x+tilesize/7,y,2*tilesize/5-tilesize/7,
2207 clip(dr,x-(tilesize/2)+2,y,tilesize-3,tilesize/2);
2208 draw_circle(dr,x,y,2*tilesize/5, COL_VAMPIRE,black);
2211 draw_circle(dr, x-tilesize/7, y-tilesize/16, tilesize/16,
2212 COL_BACKGROUND, black);
2213 draw_circle(dr, x+tilesize/7, y-tilesize/16, tilesize/16,
2214 COL_BACKGROUND, black);
2215 draw_circle_or_point(dr, x-tilesize/7, y-tilesize/16, tilesize/48,
2217 draw_circle_or_point(dr, x+tilesize/7, y-tilesize/16, tilesize/48,
2220 clip(dr, x-(tilesize/2)+2, y+tilesize/8, tilesize-3, tilesize/4);
2223 poly[i++] = x-3*tilesize/16;
2224 poly[i++] = y+1*tilesize/8;
2225 poly[i++] = x-2*tilesize/16;
2226 poly[i++] = y+7*tilesize/24;
2227 poly[i++] = x-1*tilesize/16;
2228 poly[i++] = y+1*tilesize/8;
2229 draw_polygon(dr, poly, i/2, COL_BACKGROUND, black);
2231 poly[i++] = x+3*tilesize/16;
2232 poly[i++] = y+1*tilesize/8;
2233 poly[i++] = x+2*tilesize/16;
2234 poly[i++] = y+7*tilesize/24;
2235 poly[i++] = x+1*tilesize/16;
2236 poly[i++] = y+1*tilesize/8;
2237 draw_polygon(dr, poly, i/2, COL_BACKGROUND, black);
2239 draw_circle(dr, x, y-tilesize/5, 2*tilesize/5, COL_VAMPIRE, black);
2242 } else if (monster == 4) { /* zombie */
2243 draw_circle(dr,x,y,2*tilesize/5, COL_ZOMBIE,black);
2246 x-tilesize/7-tilesize/16, y-tilesize/12-tilesize/16,
2247 x-tilesize/7+tilesize/16, y-tilesize/12+tilesize/16,
2250 x-tilesize/7+tilesize/16, y-tilesize/12-tilesize/16,
2251 x-tilesize/7-tilesize/16, y-tilesize/12+tilesize/16,
2254 x+tilesize/7-tilesize/16, y-tilesize/12-tilesize/16,
2255 x+tilesize/7+tilesize/16, y-tilesize/12+tilesize/16,
2258 x+tilesize/7+tilesize/16, y-tilesize/12-tilesize/16,
2259 x+tilesize/7-tilesize/16, y-tilesize/12+tilesize/16,
2262 clip(dr, x-tilesize/5, y+tilesize/6, 2*tilesize/5+1, tilesize/2);
2263 draw_circle(dr, x-tilesize/15, y+tilesize/6, tilesize/12,
2264 COL_BACKGROUND, black);
2267 draw_line(dr, x-tilesize/5, y+tilesize/6, x+tilesize/5, y+tilesize/6,
2271 draw_update(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize-3,tilesize-3);
2274 static void draw_monster_count(drawing *dr, game_drawstate *ds,
2275 const game_state *state, int c, int hflash) {
2281 dx = BORDER+(ds->w+2)*TILESIZE/2+TILESIZE/4;
2284 sprintf(buf,"%d",state->common->num_ghosts);
2289 sprintf(buf,"%d",state->common->num_vampires);
2293 sprintf(buf,"%d",state->common->num_zombies);
2299 draw_rect(dr, dx-2*TILESIZE/3, dy, 3*TILESIZE/2, TILESIZE,
2302 draw_monster(dr, ds, dx-TILESIZE/3, dy+TILESIZE/2,
2303 2*TILESIZE/3, hflash, 1<<c);
2305 draw_text(dr, dx-TILESIZE/3,dy+TILESIZE/2,FONT_VARIABLE,TILESIZE/2,
2306 ALIGN_HCENTRE|ALIGN_VCENTRE,
2307 hflash ? COL_FLASH : COL_TEXT, bufm);
2309 draw_text(dr, dx, dy+TILESIZE/2, FONT_VARIABLE, TILESIZE/2,
2310 ALIGN_HLEFT|ALIGN_VCENTRE,
2311 (state->count_errors[c] ? COL_ERROR :
2312 hflash ? COL_FLASH : COL_TEXT), buf);
2313 draw_update(dr, dx-2*TILESIZE/3, dy, 3*TILESIZE/2, TILESIZE);
2318 static void draw_path_hint(drawing *dr, game_drawstate *ds,
2319 const struct game_params *params,
2320 int hint_index, int hflash, int hint) {
2321 int x, y, color, dx, dy, text_dx, text_dy, text_size;
2324 if (ds->hint_errors[hint_index])
2331 range2grid(hint_index, params->w, params->h, &x, &y);
2332 /* Upper-left corner of the "tile" */
2333 dx = BORDER + x * TILESIZE;
2334 dy = BORDER + y * TILESIZE + TILESIZE;
2335 /* Center of the "tile" */
2336 text_dx = dx + TILESIZE / 2;
2337 text_dy = dy + TILESIZE / 2;
2338 /* Avoid wiping out the borders of the puzzle */
2341 text_size = TILESIZE - 3;
2343 sprintf(buf,"%d", hint);
2344 draw_rect(dr, dx, dy, text_size, text_size, COL_BACKGROUND);
2345 draw_text(dr, text_dx, text_dy, FONT_FIXED, TILESIZE / 2,
2346 ALIGN_HCENTRE | ALIGN_VCENTRE, color, buf);
2347 draw_update(dr, dx, dy, text_size, text_size);
2352 static void draw_mirror(drawing *dr, game_drawstate *ds,
2353 const game_state *state, int x, int y,
2354 int hflash, int mirror) {
2355 int dx,dy,mx1,my1,mx2,my2;
2356 dx = BORDER+(x* ds->tilesize)+(TILESIZE/2);
2357 dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE;
2359 if (mirror == CELL_MIRROR_L) {
2360 mx1 = dx-(TILESIZE/4);
2361 my1 = dy-(TILESIZE/4);
2362 mx2 = dx+(TILESIZE/4);
2363 my2 = dy+(TILESIZE/4);
2366 mx1 = dx-(TILESIZE/4);
2367 my1 = dy+(TILESIZE/4);
2368 mx2 = dx+(TILESIZE/4);
2369 my2 = dy-(TILESIZE/4);
2371 draw_thick_line(dr,(float)(TILESIZE/16),mx1,my1,mx2,my2,
2372 hflash ? COL_FLASH : COL_TEXT);
2373 draw_update(dr,dx-(TILESIZE/2)+1,dy-(TILESIZE/2)+1,TILESIZE-1,TILESIZE-1);
2378 static void draw_big_monster(drawing *dr, game_drawstate *ds,
2379 const game_state *state, int x, int y,
2380 int hflash, int monster)
2384 dx = BORDER+(x* ds->tilesize)+(TILESIZE/2);
2385 dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE;
2387 if (monster == 1) sprintf(buf,"G");
2388 else if (monster == 2) sprintf(buf,"V");
2389 else if (monster == 4) sprintf(buf,"Z");
2390 else sprintf(buf," ");
2391 draw_text(dr,dx,dy,FONT_FIXED,TILESIZE/2,ALIGN_HCENTRE|ALIGN_VCENTRE,
2392 hflash ? COL_FLASH : COL_TEXT,buf);
2393 draw_update(dr,dx-(TILESIZE/2)+2,dy-(TILESIZE/2)+2,TILESIZE-3,
2397 draw_monster(dr, ds, dx, dy, 3*TILESIZE/4, hflash, monster);
2402 static void draw_pencils(drawing *dr, game_drawstate *ds,
2403 const game_state *state, int x, int y, int pencil)
2409 dx = BORDER+(x* ds->tilesize)+(TILESIZE/4);
2410 dy = BORDER+(y* ds->tilesize)+(TILESIZE/4)+TILESIZE;
2412 for (i = 0, j = 1; j < 8; j *= 2)
2418 for (py = 0; py < 2; py++)
2419 for (px = 0; px < 2; px++)
2420 if (monsters[py*2+px]) {
2422 draw_monster(dr, ds,
2423 dx + TILESIZE/2 * px, dy + TILESIZE/2 * py,
2424 TILESIZE/2, 0, monsters[py*2+px]);
2427 switch (monsters[py*2+px]) {
2428 case 1: sprintf(buf,"G"); break;
2429 case 2: sprintf(buf,"V"); break;
2430 case 4: sprintf(buf,"Z"); break;
2432 draw_text(dr,dx + TILESIZE/2 * px,dy + TILESIZE/2 * py,
2433 FONT_FIXED,TILESIZE/4,ALIGN_HCENTRE|ALIGN_VCENTRE,
2437 draw_update(dr,dx-(TILESIZE/4)+2,dy-(TILESIZE/4)+2,
2438 (TILESIZE/2)-3,(TILESIZE/2)-3);
2443 #define FLASH_TIME 0.7F
2445 static int is_hint_stale(const game_drawstate *ds, int hflash,
2446 const game_state *state, int index)
2448 if (!ds->started) return TRUE;
2449 if (ds->hflash != hflash) return TRUE;
2451 if (ds->hint_errors[index] != state->hint_errors[index]) {
2452 ds->hint_errors[index] = state->hint_errors[index];
2459 static void game_redraw(drawing *dr, game_drawstate *ds,
2460 const game_state *oldstate, const game_state *state,
2461 int dir, const game_ui *ui,
2462 float animtime, float flashtime)
2465 int stale, xi, c, hflash, hchanged, changed_ascii;
2467 hflash = (int)(flashtime * 5 / FLASH_TIME) % 2;
2469 /* Draw static grid components at startup */
2471 draw_rect(dr, 0, 0, 2*BORDER+(ds->w+2)*TILESIZE,
2472 2*BORDER+(ds->h+3)*TILESIZE, COL_BACKGROUND);
2473 draw_rect(dr, BORDER+TILESIZE-1, BORDER+2*TILESIZE-1,
2474 (ds->w)*TILESIZE +3, (ds->h)*TILESIZE +3, COL_GRID);
2475 for (i=0;i<ds->w;i++)
2476 for (j=0;j<ds->h;j++)
2477 draw_rect(dr, BORDER+(ds->tilesize*(i+1))+1,
2478 BORDER+(ds->tilesize*(j+2))+1, ds->tilesize-1,
2479 ds->tilesize-1, COL_BACKGROUND);
2480 draw_update(dr, 0, 0, 2*BORDER+(ds->w+2)*TILESIZE,
2481 2*BORDER+(ds->h+3)*TILESIZE);
2485 if (ds->hx != ui->hx || ds->hy != ui->hy ||
2486 ds->hshow != ui->hshow || ds->hpencil != ui->hpencil)
2489 if (ds->ascii != ui->ascii) {
2490 ds->ascii = ui->ascii;
2491 changed_ascii = TRUE;
2493 changed_ascii = FALSE;
2495 /* Draw monster count hints */
2499 if (!ds->started) stale = TRUE;
2500 if (ds->hflash != hflash) stale = TRUE;
2501 if (changed_ascii) stale = TRUE;
2502 if (ds->count_errors[i] != state->count_errors[i]) {
2504 ds->count_errors[i] = state->count_errors[i];
2508 draw_monster_count(dr, ds, state, i, hflash);
2512 /* Draw path count hints */
2513 for (i=0;i<state->common->num_paths;i++) {
2514 struct path *path = &state->common->paths[i];
2516 if (is_hint_stale(ds, hflash, state, path->grid_start)) {
2517 draw_path_hint(dr, ds, &state->common->params, path->grid_start,
2518 hflash, path->sightings_start);
2521 if (is_hint_stale(ds, hflash, state, path->grid_end)) {
2522 draw_path_hint(dr, ds, &state->common->params, path->grid_end,
2523 hflash, path->sightings_end);
2527 /* Draw puzzle grid contents */
2528 for (x = 1; x < ds->w+1; x++)
2529 for (y = 1; y < ds->h+1; y++) {
2531 xy = x+y*(state->common->params.w+2);
2532 xi = state->common->xinfo[xy];
2533 c = state->common->grid[xy];
2535 if (!ds->started) stale = TRUE;
2536 if (ds->hflash != hflash) stale = TRUE;
2537 if (changed_ascii) stale = TRUE;
2540 if ((x == ui->hx && y == ui->hy) ||
2541 (x == ds->hx && y == ds->hy))
2545 if (xi >= 0 && (state->guess[xi] != ds->monsters[xi]) ) {
2547 ds->monsters[xi] = state->guess[xi];
2550 if (xi >= 0 && (state->pencils[xi] != ds->pencils[xi]) ) {
2552 ds->pencils[xi] = state->pencils[xi];
2555 if (state->cell_errors[xy] != ds->cell_errors[xy]) {
2557 ds->cell_errors[xy] = state->cell_errors[xy];
2561 draw_cell_background(dr, ds, state, ui, x, y);
2563 draw_mirror(dr, ds, state, x, y, hflash, c);
2564 else if (state->guess[xi] == 1 || state->guess[xi] == 2 ||
2565 state->guess[xi] == 4)
2566 draw_big_monster(dr, ds, state, x, y, hflash, state->guess[xi]);
2568 draw_pencils(dr, ds, state, x, y, state->pencils[xi]);
2572 ds->hx = ui->hx; ds->hy = ui->hy;
2573 ds->hshow = ui->hshow;
2574 ds->hpencil = ui->hpencil;
2575 ds->hflash = hflash;
2580 static float game_anim_length(const game_state *oldstate,
2581 const game_state *newstate, int dir, game_ui *ui)
2586 static float game_flash_length(const game_state *oldstate,
2587 const game_state *newstate, int dir, game_ui *ui)
2589 return (!oldstate->solved && newstate->solved && !oldstate->cheated &&
2590 !newstate->cheated) ? FLASH_TIME : 0.0F;
2593 static int game_status(const game_state *state)
2595 return state->solved;
2598 static int game_timing_state(const game_state *state, game_ui *ui)
2603 static void game_print_size(const game_params *params, float *x, float *y)
2607 static void game_print(drawing *dr, const game_state *state, int tilesize)
2612 #define thegame undead
2615 const struct game thegame = {
2616 "Undead", "games.undead", "undead",
2623 TRUE, game_configure, custom_params,
2631 TRUE, game_can_format_as_text_now, game_text_format,
2639 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
2642 game_free_drawstate,
2647 FALSE, FALSE, game_print_size, game_print,
2648 FALSE, /* wants_statusbar */
2649 FALSE, game_timing_state,