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(game_params *params) {
117 game_params *ret = snew(game_params);
118 *ret = *params; /* structure copy */
122 static void decode_params(game_params *params, char const *string) {
123 params->w = params->h = atoi(string);
125 while (*string && isdigit((unsigned char) *string)) ++string;
126 if (*string == 'x') {
128 params->h = atoi(string);
129 while (*string && isdigit((unsigned char)*string)) string++;
132 params->diff = DIFF_NORMAL;
133 if (*string == 'd') {
136 for (i = 0; i < DIFFCOUNT; i++)
137 if (*string == undead_diffchars[i])
139 if (*string) string++;
145 static char *encode_params(game_params *params, int full) {
147 sprintf(buf, "%dx%d", params->w, params->h);
149 sprintf(buf + strlen(buf), "d%c", undead_diffchars[params->diff]);
153 static config_item *game_configure(game_params *params) {
157 ret = snewn(4, config_item);
159 ret[0].name = "Width";
160 ret[0].type = C_STRING;
161 sprintf(buf, "%d", params->w);
162 ret[0].sval = dupstr(buf);
165 ret[1].name = "Height";
166 ret[1].type = C_STRING;
167 sprintf(buf, "%d", params->h);
168 ret[1].sval = dupstr(buf);
171 ret[2].name = "Difficulty";
172 ret[2].type = C_CHOICES;
173 ret[2].sval = DIFFCONFIG;
174 ret[2].ival = params->diff;
184 static game_params *custom_params(config_item *cfg) {
185 game_params *ret = snew(game_params);
187 ret->w = atoi(cfg[0].sval);
188 ret->h = atoi(cfg[1].sval);
189 ret->diff = cfg[2].ival;
193 static char *validate_params(game_params *params, int full) {
194 if ((params->w * params->h ) > 54) return "Grid is too big";
195 if (params->w < 3) return "Width must be at least 3";
196 if (params->h < 3) return "Height must be at least 3";
197 if (params->diff >= DIFFCOUNT) return "Unknown difficulty rating";
201 /* --------------------------------------------------------------- */
202 /* Game state allocation, deallocation. */
218 struct game_params params;
220 int num_ghosts,num_vampires,num_zombies,num_total;
230 struct game_common *common;
232 unsigned char *pencils;
233 unsigned char *cell_errors;
234 unsigned char *hint_errors;
235 unsigned char count_errors[3];
240 static game_state *new_state(game_params *params) {
242 game_state *state = snew(game_state);
243 state->common = snew(struct game_common);
245 state->common->refcount = 1;
246 state->common->params.w = params->w;
247 state->common->params.h = params->h;
248 state->common->params.diff = params->diff;
250 state->common->wh = (state->common->params.w +2) * (state->common->params.h +2);
252 state->common->num_ghosts = 0;
253 state->common->num_vampires = 0;
254 state->common->num_zombies = 0;
255 state->common->num_total = 0;
257 state->common->grid = snewn(state->common->wh, int);
258 state->common->xinfo = snewn(state->common->wh, int);
259 state->common->fixed = NULL;
260 state->common->solved = FALSE;
262 state->common->num_paths =
263 state->common->params.w + state->common->params.h;
264 state->common->paths = snewn(state->common->num_paths, struct path);
266 for (i=0;i<state->common->num_paths;i++) {
267 state->common->paths[i].length = 0;
268 state->common->paths[i].grid_start = -1;
269 state->common->paths[i].grid_end = -1;
270 state->common->paths[i].num_monsters = 0;
271 state->common->paths[i].sightings_start = 0;
272 state->common->paths[i].sightings_end = 0;
273 state->common->paths[i].p = snewn(state->common->wh,int);
274 state->common->paths[i].xy = snewn(state->common->wh,int);
275 state->common->paths[i].mapping = snewn(state->common->wh,int);
279 state->pencils = NULL;
281 state->cell_errors = snewn(state->common->wh, unsigned char);
282 for (i=0;i<state->common->wh;i++)
283 state->cell_errors[i] = FALSE;
284 state->hint_errors = snewn(2*state->common->num_paths, unsigned char);
285 for (i=0;i<2*state->common->num_paths;i++)
286 state->hint_errors[i] = FALSE;
288 state->count_errors[i] = FALSE;
290 state->solved = FALSE;
291 state->cheated = FALSE;
296 static game_state *dup_game(game_state *state) {
297 game_state *ret = snew(game_state);
299 ret->common = state->common;
300 ret->common->refcount++;
302 if (state->guess != NULL) {
303 ret->guess = snewn(ret->common->num_total,int);
304 memcpy(ret->guess, state->guess, ret->common->num_total*sizeof(int));
306 else ret->guess = NULL;
308 if (state->pencils != NULL) {
309 ret->pencils = snewn(ret->common->num_total,unsigned char);
310 memcpy(ret->pencils, state->pencils,
311 ret->common->num_total*sizeof(unsigned char));
313 else ret->pencils = NULL;
315 if (state->cell_errors != NULL) {
316 ret->cell_errors = snewn(ret->common->wh,unsigned char);
317 memcpy(ret->cell_errors, state->cell_errors,
318 ret->common->wh*sizeof(unsigned char));
320 else ret->cell_errors = NULL;
322 if (state->hint_errors != NULL) {
323 ret->hint_errors = snewn(2*ret->common->num_paths,unsigned char);
324 memcpy(ret->hint_errors, state->hint_errors,
325 2*ret->common->num_paths*sizeof(unsigned char));
327 else ret->hint_errors = NULL;
329 ret->count_errors[0] = state->count_errors[0];
330 ret->count_errors[1] = state->count_errors[1];
331 ret->count_errors[2] = state->count_errors[2];
333 ret->solved = state->solved;
334 ret->cheated = state->cheated;
339 static void free_game(game_state *state) {
342 state->common->refcount--;
343 if (state->common->refcount == 0) {
344 for (i=0;i<state->common->num_paths;i++) {
345 sfree(state->common->paths[i].mapping);
346 sfree(state->common->paths[i].xy);
347 sfree(state->common->paths[i].p);
349 sfree(state->common->paths);
350 sfree(state->common->xinfo);
351 sfree(state->common->grid);
352 if (state->common->fixed != NULL) sfree(state->common->fixed);
353 sfree(state->common);
355 if (state->hint_errors != NULL) sfree(state->hint_errors);
356 if (state->cell_errors != NULL) sfree(state->cell_errors);
357 if (state->pencils != NULL) sfree(state->pencils);
358 if (state->guess != NULL) sfree(state->guess);
364 /* --------------------------------------------------------------- */
365 /* Puzzle generator */
378 /* grid walk directions */
387 int range2grid(int rangeno, int width, int height, int *x, int *y) {
390 *x = 0; *y = 0; return DIRECTION_NONE;
392 if (rangeno < width) {
393 *x = rangeno+1; *y = 0; return DIRECTION_DOWN;
395 rangeno = rangeno - width;
396 if (rangeno < height) {
397 *x = width+1; *y = rangeno+1; return DIRECTION_LEFT;
399 rangeno = rangeno - height;
400 if (rangeno < width) {
401 *x = width-rangeno; *y = height+1; return DIRECTION_UP;
403 rangeno = rangeno - width;
404 if (rangeno < height) {
405 *x = 0; *y = height-rangeno; return DIRECTION_RIGHT;
408 return DIRECTION_NONE;
411 int grid2range(int x, int y, int w, int h) {
412 if (x>0 && x<w+1 && y>0 && y<h+1) return -1;
413 if (x<0 || x>w+1 || y<0 || y>h+1) return -1;
414 if ((x == 0 || x==w+1) && (y==0 || y==h+1)) return -1;
415 if (y==0) return x-1;
416 if (x==(w+1)) return y-1+w;
417 if (y==(h+1)) return 2*w + h - x;
421 void make_paths(game_state *state) {
425 for (i=0;i<2*(state->common->params.w + state->common->params.h);i++) {
427 int j,k,num_monsters;
431 /* Check whether inverse path is already in list */
432 for (j=0;j<count;j++) {
433 if (i == state->common->paths[j].grid_end) {
440 /* We found a new path through the mirror maze */
441 state->common->paths[count].grid_start = i;
442 dir = range2grid(i, state->common->params.w,
443 state->common->params.h,&x,&y);
444 state->common->paths[count].sightings_start =
445 state->common->grid[x+y*(state->common->params.w +2)];
449 if (dir == DIRECTION_DOWN) y++;
450 else if (dir == DIRECTION_LEFT) x--;
451 else if (dir == DIRECTION_UP) y--;
452 else if (dir == DIRECTION_RIGHT) x++;
454 r = grid2range(x, y, state->common->params.w,
455 state->common->params.h);
457 state->common->paths[count].grid_end = r;
458 state->common->paths[count].sightings_end =
459 state->common->grid[x+y*(state->common->params.w +2)];
463 c = state->common->grid[x+y*(state->common->params.w+2)];
464 state->common->paths[count].xy[state->common->paths[count].length] =
465 x+y*(state->common->params.w+2);
466 if (c == CELL_MIRROR_L) {
467 state->common->paths[count].p[state->common->paths[count].length] = -1;
468 if (dir == DIRECTION_DOWN) dir = DIRECTION_RIGHT;
469 else if (dir == DIRECTION_LEFT) dir = DIRECTION_UP;
470 else if (dir == DIRECTION_UP) dir = DIRECTION_LEFT;
471 else if (dir == DIRECTION_RIGHT) dir = DIRECTION_DOWN;
473 else if (c == CELL_MIRROR_R) {
474 state->common->paths[count].p[state->common->paths[count].length] = -1;
475 if (dir == DIRECTION_DOWN) dir = DIRECTION_LEFT;
476 else if (dir == DIRECTION_LEFT) dir = DIRECTION_DOWN;
477 else if (dir == DIRECTION_UP) dir = DIRECTION_RIGHT;
478 else if (dir == DIRECTION_RIGHT) dir = DIRECTION_UP;
481 state->common->paths[count].p[state->common->paths[count].length] =
482 state->common->xinfo[x+y*(state->common->params.w+2)];
484 state->common->paths[count].length++;
486 /* Count unique monster entries in each path */
487 state->common->paths[count].num_monsters = 0;
488 for (j=0;j<state->common->num_total;j++) {
490 for (k=0;k<state->common->paths[count].length;k++)
491 if (state->common->paths[count].p[k] == j)
493 if (num_monsters > 0)
494 state->common->paths[count].num_monsters++;
497 /* Generate mapping vector */
499 for (p=0;p<state->common->paths[count].length;p++) {
501 m = state->common->paths[count].p[p];
502 if (m == -1) continue;
505 if (state->common->paths[count].mapping[j] == m) found = TRUE;
506 if (!found) state->common->paths[count].mapping[c++] = m;
519 int next_list(struct guess *g, int pos) {
522 if ((g->guess[pos] == 1 && g->possible[pos] == 1) ||
523 (g->guess[pos] == 2 && (g->possible[pos] == 3 ||
524 g->possible[pos] == 2)) ||
527 if (g->guess[pos] == 1 && (g->possible[pos] == 3 ||
528 g->possible[pos] == 7)) {
529 g->guess[pos] = 2; return TRUE;
531 if (g->guess[pos] == 1 && g->possible[pos] == 5) {
532 g->guess[pos] = 4; return TRUE;
534 if (g->guess[pos] == 2 && (g->possible[pos] == 6 || g->possible[pos] == 7)) {
535 g->guess[pos] = 4; return TRUE;
539 if (g->guess[pos] == 1) {
540 if (g->possible[pos] == 1) {
541 return next_list(g,pos-1);
543 if (g->possible[pos] == 3 || g->possible[pos] == 7) {
544 g->guess[pos] = 2; return TRUE;
546 if (g->possible[pos] == 5) {
547 g->guess[pos] = 4; return TRUE;
551 if (g->guess[pos] == 2) {
552 if (g->possible[pos] == 2) {
553 return next_list(g,pos-1);
555 if (g->possible[pos] == 3) {
556 g->guess[pos] = 1; return next_list(g,pos-1);
558 if (g->possible[pos] == 6 || g->possible[pos] == 7) {
559 g->guess[pos] = 4; return TRUE;
563 if (g->guess[pos] == 4) {
564 if (g->possible[pos] == 5 || g->possible[pos] == 7) {
565 g->guess[pos] = 1; return next_list(g,pos-1);
567 if (g->possible[pos] == 6) {
568 g->guess[pos] = 2; return next_list(g,pos-1);
570 if (g->possible[pos] == 4) {
571 return next_list(g,pos-1);
577 void get_unique(game_state *state, int counter, random_state *rs) {
579 int p,i,c,pathlimit,count_uniques;
580 struct guess path_guess;
593 } views, single_views, test_views;
595 struct entry test_entry;
597 path_guess.length = state->common->paths[counter].num_monsters;
598 path_guess.guess = snewn(path_guess.length,int);
599 path_guess.possible = snewn(path_guess.length,int);
600 for (i=0;i<path_guess.length;i++)
601 path_guess.guess[i] = path_guess.possible[i] = 0;
603 for (p=0;p<path_guess.length;p++) {
604 path_guess.possible[p] =
605 state->guess[state->common->paths[counter].mapping[p]];
606 switch (path_guess.possible[p]) {
607 case 1: path_guess.guess[p] = 1; break;
608 case 2: path_guess.guess[p] = 2; break;
609 case 3: path_guess.guess[p] = 1; break;
610 case 4: path_guess.guess[p] = 4; break;
611 case 5: path_guess.guess[p] = 1; break;
612 case 6: path_guess.guess[p] = 2; break;
613 case 7: path_guess.guess[p] = 1; break;
620 pathlimit = state->common->paths[counter].length + 1;
621 view_count = snewn(pathlimit*pathlimit, int);
622 for (i = 0; i < pathlimit*pathlimit; i++)
626 int mirror, start_view, end_view;
630 for (p=0;p<state->common->paths[counter].length;p++) {
631 if (state->common->paths[counter].p[p] == -1) mirror = TRUE;
633 for (i=0;i<path_guess.length;i++) {
634 if (state->common->paths[counter].p[p] ==
635 state->common->paths[counter].mapping[i]) {
636 if (path_guess.guess[i] == 1 && mirror == TRUE)
638 if (path_guess.guess[i] == 2 && mirror == FALSE)
640 if (path_guess.guess[i] == 4)
649 for (p=state->common->paths[counter].length-1;p>=0;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)
667 assert(start_view >= 0 && start_view < pathlimit);
668 assert(end_view >= 0 && end_view < pathlimit);
669 i = start_view * pathlimit + end_view;
671 if (view_count[i] == 1) {
672 views.node = snewn(1,struct entry);
673 views.node->link = views.head;
674 views.node->guess = snewn(path_guess.length,int);
675 views.head = views.node;
676 views.node->start_view = start_view;
677 views.node->end_view = end_view;
678 memcpy(views.node->guess, path_guess.guess,
679 path_guess.length*sizeof(int));
681 } while (next_list(&path_guess, path_guess.length-1));
683 /* extract single entries from view list */
685 test_views.head = views.head;
686 test_views.node = views.node;
688 test_entry.guess = snewn(path_guess.length,int);
690 single_views.head = NULL;
691 single_views.node = NULL;
694 while (test_views.head != NULL) {
695 test_views.node = test_views.head;
696 test_views.head = test_views.head->link;
697 i = test_views.node->start_view * pathlimit + test_views.node->end_view;
698 if (view_count[i] == 1) {
699 single_views.node = snewn(1,struct entry);
700 single_views.node->link = single_views.head;
701 single_views.node->guess = snewn(path_guess.length,int);
702 single_views.head = single_views.node;
703 single_views.node->start_view = test_views.node->start_view;
704 single_views.node->end_view = test_views.node->end_view;
705 memcpy(single_views.node->guess, test_views.node->guess,
706 path_guess.length*sizeof(int));
713 if (count_uniques > 0) {
714 test_entry.start_view = 0;
715 test_entry.end_view = 0;
716 /* Choose one unique guess per random */
717 /* While we are busy with looping through single_views, we
718 * conveniently free the linked list single_view */
719 c = random_upto(rs,count_uniques);
720 while(single_views.head != NULL) {
721 single_views.node = single_views.head;
722 single_views.head = single_views.head->link;
724 memcpy(test_entry.guess, single_views.node->guess,
725 path_guess.length*sizeof(int));
726 test_entry.start_view = single_views.node->start_view;
727 test_entry.end_view = single_views.node->end_view;
729 sfree(single_views.node->guess);
730 sfree(single_views.node);
733 /* Modify state_guess according to path_guess.mapping */
734 for (i=0;i<path_guess.length;i++)
735 state->guess[state->common->paths[counter].mapping[i]] =
739 sfree(test_entry.guess);
741 while (views.head != NULL) {
742 views.node = views.head;
743 views.head = views.head->link;
744 sfree(views.node->guess);
748 sfree(path_guess.possible);
749 sfree(path_guess.guess);
754 int count_monsters(game_state *state,
755 int *cGhost, int *cVampire, int *cZombie) {
759 *cGhost = *cVampire = *cZombie = cNone = 0;
761 for (i=0;i<state->common->num_total;i++) {
762 if (state->guess[i] == 1) (*cGhost)++;
763 else if (state->guess[i] == 2) (*cVampire)++;
764 else if (state->guess[i] == 4) (*cZombie)++;
771 int check_numbers(game_state *state, int *guess) {
774 int count_ghosts, count_vampires, count_zombies;
776 count_ghosts = count_vampires = count_zombies = 0;
777 for (i=0;i<state->common->num_total;i++) {
778 if (guess[i] == 1) count_ghosts++;
779 if (guess[i] == 2) count_vampires++;
780 if (guess[i] == 4) count_zombies++;
785 if (count_ghosts > state->common->num_ghosts) valid = FALSE;
786 if (count_vampires > state->common->num_vampires) valid = FALSE;
787 if (count_zombies > state->common->num_zombies) valid = FALSE;
792 int check_solution(int *g, struct path path) {
799 for (i=0;i<path.length;i++) {
800 if (path.p[i] == -1) mirror = TRUE;
802 if (g[path.p[i]] == 1 && mirror) count++;
803 else if (g[path.p[i]] == 2 && !mirror) count++;
804 else if (g[path.p[i]] == 4) count++;
807 if (count != path.sightings_start) return FALSE;
811 for (i=path.length-1;i>=0;i--) {
812 if (path.p[i] == -1) mirror = TRUE;
814 if (g[path.p[i]] == 1 && mirror) count++;
815 else if (g[path.p[i]] == 2 && !mirror) count++;
816 else if (g[path.p[i]] == 4) count++;
819 if (count != path.sightings_end) return FALSE;
824 int solve_iterative(game_state *state, struct path *paths) {
834 loop.length = state->common->num_total;
835 guess = snewn(state->common->num_total,int);
836 possible = snewn(state->common->num_total,int);
838 for (i=0;i<state->common->num_total;i++) {
839 guess[i] = state->guess[i];
843 for (p=0;p<state->common->num_paths;p++) {
844 if (paths[p].num_monsters > 0) {
845 loop.length = paths[p].num_monsters;
846 loop.guess = snewn(paths[p].num_monsters,int);
847 loop.possible = snewn(paths[p].num_monsters,int);
849 for (i=0;i<paths[p].num_monsters;i++) {
850 switch (state->guess[paths[p].mapping[i]]) {
851 case 1: loop.guess[i] = 1; break;
852 case 2: loop.guess[i] = 2; break;
853 case 3: loop.guess[i] = 1; break;
854 case 4: loop.guess[i] = 4; break;
855 case 5: loop.guess[i] = 1; break;
856 case 6: loop.guess[i] = 2; break;
857 case 7: loop.guess[i] = 1; break;
859 loop.possible[i] = state->guess[paths[p].mapping[i]];
860 possible[paths[p].mapping[i]] = 0;
864 for (i=0;i<state->common->num_total;i++) {
865 guess[i] = state->guess[i];
868 for (i=0;i<paths[p].num_monsters;i++)
869 guess[paths[p].mapping[i]] = loop.guess[count++];
870 if (check_numbers(state,guess) &&
871 check_solution(guess,paths[p]))
872 for (j=0;j<paths[p].num_monsters;j++)
873 possible[paths[p].mapping[j]] |= loop.guess[j];
874 if (!next_list(&loop,loop.length-1)) break;
876 for (i=0;i<paths[p].num_monsters;i++)
877 state->guess[paths[p].mapping[i]] &=
878 possible[paths[p].mapping[i]];
879 sfree(loop.possible);
884 for (i=0;i<state->common->num_total;i++) {
885 if (state->guess[i] == 3 || state->guess[i] == 5 ||
886 state->guess[i] == 6 || state->guess[i] == 7) {
887 solved = FALSE; break;
897 int solve_bruteforce(game_state *state, struct path *paths) {
899 int number_solutions;
904 loop.guess = snewn(state->common->num_total,int);
905 loop.possible = snewn(state->common->num_total,int);
907 for (i=0;i<state->common->num_total;i++) {
908 loop.possible[i] = state->guess[i];
909 switch (state->guess[i]) {
910 case 1: loop.guess[i] = 1; break;
911 case 2: loop.guess[i] = 2; break;
912 case 3: loop.guess[i] = 1; break;
913 case 4: loop.guess[i] = 4; break;
914 case 5: loop.guess[i] = 1; break;
915 case 6: loop.guess[i] = 2; break;
916 case 7: loop.guess[i] = 1; break;
921 number_solutions = 0;
926 if (!check_numbers(state,loop.guess)) correct = FALSE;
928 for (p=0;p<state->common->num_paths;p++)
929 if (!check_solution(loop.guess,paths[p])) {
930 correct = FALSE; break;
935 if(number_solutions > 1) {
939 for (i=0;i<state->common->num_total;i++)
940 state->guess[i] = loop.guess[i];
942 if (!next_list(&loop,state->common->num_total -1)) {
947 sfree(loop.possible);
953 int path_cmp(const void *a, const void *b) {
954 const struct path *pa = (const struct path *)a;
955 const struct path *pb = (const struct path *)b;
956 return pa->num_monsters - pb->num_monsters;
959 static char *new_game_desc(game_params *params, random_state *rs,
960 char **aux, int interactive) {
961 int i,count,c,w,h,r,p,g;
964 /* Variables for puzzle generation algorithm */
967 int count_ghosts, count_vampires, count_zombies;
971 /* Variables for solver algorithm */
972 int solved_iterative, solved_bruteforce, contains_inconsistency,
977 /* Variables for game description generation */
984 new = new_state(params);
987 /* Fill grid with random mirrors and (later to be populated)
988 * empty monster cells */
990 for (h=1;h<new->common->params.h+1;h++)
991 for (w=1;w<new->common->params.w+1;w++) {
992 c = random_upto(rs,5);
994 new->common->grid[w+h*(new->common->params.w+2)] = CELL_EMPTY;
995 new->common->xinfo[w+h*(new->common->params.w+2)] = count++;
998 new->common->grid[w+h*(new->common->params.w+2)] =
1000 new->common->xinfo[w+h*(new->common->params.w+2)] = -1;
1003 new->common->grid[w+h*(new->common->params.w+2)] =
1005 new->common->xinfo[w+h*(new->common->params.w+2)] = -1;
1008 new->common->num_total = count; /* Total number of monsters in maze */
1010 /* Puzzle is boring if it has too few monster cells. Discard
1011 * grid, make new grid */
1012 if (new->common->num_total <= 4) {
1017 /* Monsters / Mirrors ratio should be balanced */
1018 ratio = (float)new->common->num_total /
1019 (float)(new->common->params.w * new->common->params.h);
1020 if (ratio < 0.48 || ratio > 0.78) {
1025 /* Assign clue identifiers */
1026 for (r=0;r<2*(new->common->params.w+new->common->params.h);r++) {
1028 gridno = range2grid(r,new->common->params.w,new->common->params.h,
1030 new->common->grid[x+y*(new->common->params.w +2)] = gridno;
1031 new->common->xinfo[x+y*(new->common->params.w +2)] = 0;
1033 /* The four corners don't matter at all for the game. Set them
1034 * all to zero, just to have a nice data structure */
1035 new->common->grid[0] = 0;
1036 new->common->xinfo[0] = 0;
1037 new->common->grid[new->common->params.w+1] = 0;
1038 new->common->xinfo[new->common->params.w+1] = 0;
1039 new->common->grid[new->common->params.w+1 + (new->common->params.h+1)*(new->common->params.w+2)] = 0;
1040 new->common->xinfo[new->common->params.w+1 + (new->common->params.h+1)*(new->common->params.w+2)] = 0;
1041 new->common->grid[(new->common->params.h+1)*(new->common->params.w+2)] = 0;
1042 new->common->xinfo[(new->common->params.h+1)*(new->common->params.w+2)] = 0;
1044 /* Initialize solution vector */
1045 new->guess = snewn(new->common->num_total,int);
1046 for (g=0;g<new->common->num_total;g++) new->guess[g] = 7;
1048 /* Initialize fixed flag from common. Not needed for the
1049 * puzzle generator; initialize it for having clean code */
1050 new->common->fixed = snewn(new->common->num_total,int);
1051 for (g=0;g<new->common->num_total;g++)
1052 new->common->fixed[g] = FALSE;
1054 /* paths generation */
1057 /* Grid is invalid if max. path length > threshold. Discard
1058 * grid, make new one */
1059 switch (new->common->params.diff) {
1060 case DIFF_EASY: max_length = min(new->common->params.w,new->common->params.h) + 1; break;
1061 case DIFF_NORMAL: max_length = (max(new->common->params.w,new->common->params.h) * 3) / 2; break;
1062 case DIFF_TRICKY: max_length = 9; break;
1063 default: max_length = 9; break;
1066 for (p=0;p<new->common->num_paths;p++) {
1067 if (new->common->paths[p].num_monsters > max_length) {
1076 qsort(new->common->paths, new->common->num_paths,
1077 sizeof(struct path), path_cmp);
1079 /* Grid monster initialization */
1080 /* For easy puzzles, we try to fill nearly the whole grid
1081 with unique solution paths (up to 2) For more difficult
1082 puzzles, we fill only roughly half the grid, and choose
1083 random monsters for the rest For hard puzzles, we fill
1084 even less paths with unique solutions */
1086 switch (new->common->params.diff) {
1087 case DIFF_EASY: filling = 2; break;
1088 case DIFF_NORMAL: filling = min( (new->common->params.w+new->common->params.h) , (new->common->num_total)/2 ); break;
1089 case DIFF_TRICKY: filling = max( (new->common->params.w+new->common->params.h) , (new->common->num_total)/2 ); break;
1090 default: filling = 0; break;
1094 while ( (count_monsters(new, &count_ghosts, &count_vampires,
1095 &count_zombies)) > filling) {
1096 if ((count) >= new->common->num_paths) break;
1097 if (new->common->paths[count].num_monsters == 0) {
1101 get_unique(new,count,rs);
1105 /* Fill any remaining ambiguous entries with random monsters */
1106 for(g=0;g<new->common->num_total;g++) {
1107 if (new->guess[g] == 7) {
1108 r = random_upto(rs,3);
1109 new->guess[g] = (r == 0) ? 1 : ( (r == 1) ? 2 : 4 );
1113 /* Determine all hints */
1114 count_monsters(new, &new->common->num_ghosts,
1115 &new->common->num_vampires, &new->common->num_zombies);
1117 /* Puzzle is trivial if it has only one type of monster. Discard. */
1118 if ((new->common->num_ghosts == 0 && new->common->num_vampires == 0) ||
1119 (new->common->num_ghosts == 0 && new->common->num_zombies == 0) ||
1120 (new->common->num_vampires == 0 && new->common->num_zombies == 0)) {
1125 /* Discard puzzle if difficulty Tricky, and it has only 1
1126 * member of any monster type */
1127 if (new->common->params.diff == DIFF_TRICKY &&
1128 (new->common->num_ghosts <= 1 ||
1129 new->common->num_vampires <= 1 || new->common->num_zombies <= 1)) {
1134 for (w=1;w<new->common->params.w+1;w++)
1135 for (h=1;h<new->common->params.h+1;h++) {
1136 c = new->common->xinfo[w+h*(new->common->params.w+2)];
1138 if (new->guess[c] == 1) new->common->grid[w+h*(new->common->params.w+2)] = CELL_GHOST;
1139 if (new->guess[c] == 2) new->common->grid[w+h*(new->common->params.w+2)] = CELL_VAMPIRE;
1140 if (new->guess[c] == 4) new->common->grid[w+h*(new->common->params.w+2)] = CELL_ZOMBIE;
1144 /* Prepare path information needed by the solver (containing all hints) */
1145 for (p=0;p<new->common->num_paths;p++) {
1148 new->common->paths[p].sightings_start = 0;
1149 new->common->paths[p].sightings_end = 0;
1152 for (g=0;g<new->common->paths[p].length;g++) {
1154 if (new->common->paths[p].p[g] == -1) mirror = TRUE;
1156 if (new->guess[new->common->paths[p].p[g]] == 1 && mirror == TRUE) (new->common->paths[p].sightings_start)++;
1157 else if (new->guess[new->common->paths[p].p[g]] == 2 && mirror == FALSE) (new->common->paths[p].sightings_start)++;
1158 else if (new->guess[new->common->paths[p].p[g]] == 4) (new->common->paths[p].sightings_start)++;
1163 for (g=new->common->paths[p].length-1;g>=0;g--) {
1164 if (new->common->paths[p].p[g] == -1) mirror = TRUE;
1166 if (new->guess[new->common->paths[p].p[g]] == 1 && mirror == TRUE) (new->common->paths[p].sightings_end)++;
1167 else if (new->guess[new->common->paths[p].p[g]] == 2 && mirror == FALSE) (new->common->paths[p].sightings_end)++;
1168 else if (new->guess[new->common->paths[p].p[g]] == 4) (new->common->paths[p].sightings_end)++;
1172 range2grid(new->common->paths[p].grid_start,
1173 new->common->params.w,new->common->params.h,&x,&y);
1174 new->common->grid[x+y*(new->common->params.w +2)] =
1175 new->common->paths[p].sightings_start;
1176 range2grid(new->common->paths[p].grid_end,
1177 new->common->params.w,new->common->params.h,&x,&y);
1178 new->common->grid[x+y*(new->common->params.w +2)] =
1179 new->common->paths[p].sightings_end;
1182 /* Try to solve the puzzle with the iterative solver */
1183 old_guess = snewn(new->common->num_total,int);
1184 for (p=0;p<new->common->num_total;p++) {
1188 iterative_depth = 0;
1189 solved_iterative = FALSE;
1190 contains_inconsistency = FALSE;
1191 count_ambiguous = 0;
1196 solved_iterative = solve_iterative(new,new->common->paths);
1198 for (p=0;p<new->common->num_total;p++) {
1199 if (new->guess[p] != old_guess[p]) no_change = FALSE;
1200 old_guess[p] = new->guess[p];
1201 if (new->guess[p] == 0) contains_inconsistency = TRUE;
1203 if (solved_iterative || no_change) break;
1206 /* If necessary, try to solve the puzzle with the brute-force solver */
1207 solved_bruteforce = FALSE;
1208 if (new->common->params.diff != DIFF_EASY &&
1209 !solved_iterative && !contains_inconsistency) {
1210 for (p=0;p<new->common->num_total;p++)
1211 if (new->guess[p] != 1 && new->guess[p] != 2 &&
1212 new->guess[p] != 4) count_ambiguous++;
1214 solved_bruteforce = solve_bruteforce(new, new->common->paths);
1217 /* Determine puzzle difficulty level */
1218 if (new->common->params.diff == DIFF_EASY && solved_iterative &&
1219 iterative_depth <= 3 && !contains_inconsistency) {
1220 /* printf("Puzzle level: EASY Level %d Ratio %f Ambiguous %d (Found after %i tries)\n",iterative_depth, ratio, count_ambiguous, i); */
1224 if (new->common->params.diff == DIFF_NORMAL &&
1225 ((solved_iterative && iterative_depth > 3) ||
1226 (solved_bruteforce && count_ambiguous < 4)) &&
1227 !contains_inconsistency) {
1228 /* printf("Puzzle level: NORMAL Level %d Ratio %f Ambiguous %d (Found after %d tries)\n", iterative_depth, ratio, count_ambiguous, i); */
1231 if (new->common->params.diff == DIFF_TRICKY &&
1232 solved_bruteforce && iterative_depth > 0 &&
1233 count_ambiguous >= 4 && !contains_inconsistency) {
1234 /* printf("Puzzle level: TRICKY Level %d Ratio %f Ambiguous %d (Found after %d tries)\n", iterative_depth, ratio, count_ambiguous, i); */
1238 /* If puzzle is not solvable or does not satisfy the desired
1239 * difficulty level, free memory and start from scratch */
1245 /* We have a valid puzzle! */
1247 desc = snewn(10 + new->common->wh +
1248 6*(new->common->params.w + new->common->params.h), char);
1251 /* Encode monster counts */
1252 e += sprintf(e, "%d,", new->common->num_ghosts);
1253 e += sprintf(e, "%d,", new->common->num_vampires);
1254 e += sprintf(e, "%d,", new->common->num_zombies);
1258 for (y=1;y<new->common->params.h+1;y++)
1259 for (x=1;x<new->common->params.w+1;x++) {
1260 c = new->common->grid[x+y*(new->common->params.w+2)];
1265 if (c != CELL_MIRROR_L && c != CELL_MIRROR_R) {
1268 else if (c == CELL_MIRROR_L) {
1269 if (count > 0) *e++ = (count-1 + 'a');
1274 if (count > 0) *e++ = (count-1 + 'a');
1279 if (count > 0) *e++ = (count-1 + 'a');
1282 for (p=0;p<2*(new->common->params.w + new->common->params.h);p++) {
1283 range2grid(p,new->common->params.w,new->common->params.h,&x,&y);
1284 e += sprintf(e, ",%d", new->common->grid[x+y*(new->common->params.w+2)]);
1288 desc = sresize(desc, e - desc, char);
1296 void num2grid(int num, int width, int height, int *x, int *y) {
1302 static game_state *new_game(midend *me, game_params *params, char *desc) {
1307 game_state *state = new_state(params);
1309 state->common->num_ghosts = atoi(desc);
1310 while (*desc && isdigit((unsigned char)*desc)) desc++;
1312 state->common->num_vampires = atoi(desc);
1313 while (*desc && isdigit((unsigned char)*desc)) desc++;
1315 state->common->num_zombies = atoi(desc);
1316 while (*desc && isdigit((unsigned char)*desc)) desc++;
1319 state->common->num_total = state->common->num_ghosts + state->common->num_vampires + state->common->num_zombies;
1321 state->guess = snewn(state->common->num_total,int);
1322 state->pencils = snewn(state->common->num_total,unsigned char);
1323 state->common->fixed = snewn(state->common->num_total,int);
1324 for (i=0;i<state->common->num_total;i++) {
1325 state->guess[i] = 7;
1326 state->pencils[i] = 0;
1327 state->common->fixed[i] = FALSE;
1329 for (i=0;i<state->common->wh;i++)
1330 state->cell_errors[i] = FALSE;
1331 for (i=0;i<2*state->common->num_paths;i++)
1332 state->hint_errors[i] = FALSE;
1334 state->count_errors[i] = FALSE;
1338 while (*desc != ',') {
1343 num2grid(n,state->common->params.w,state->common->params.h,&x,&y);
1344 state->common->grid[x+y*(state->common->params.w +2)] = CELL_MIRROR_L;
1345 state->common->xinfo[x+y*(state->common->params.w+2)] = -1;
1348 else if (*desc == 'R') {
1349 num2grid(n,state->common->params.w,state->common->params.h,&x,&y);
1350 state->common->grid[x+y*(state->common->params.w +2)] = CELL_MIRROR_R;
1351 state->common->xinfo[x+y*(state->common->params.w+2)] = -1;
1354 else if (*desc == 'G') {
1355 num2grid(n,state->common->params.w,state->common->params.h,&x,&y);
1356 state->common->grid[x+y*(state->common->params.w +2)] = CELL_GHOST;
1357 state->common->xinfo[x+y*(state->common->params.w+2)] = count;
1358 state->guess[count] = 1;
1359 state->common->fixed[count++] = TRUE;
1362 else if (*desc == 'V') {
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_VAMPIRE;
1365 state->common->xinfo[x+y*(state->common->params.w+2)] = count;
1366 state->guess[count] = 2;
1367 state->common->fixed[count++] = TRUE;
1370 else if (*desc == 'Z') {
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_ZOMBIE;
1373 state->common->xinfo[x+y*(state->common->params.w+2)] = count;
1374 state->guess[count] = 4;
1375 state->common->fixed[count++] = TRUE;
1379 c = *desc - ('a' -1);
1381 num2grid(n,state->common->params.w,state->common->params.h,&x,&y);
1382 state->common->grid[x+y*(state->common->params.w +2)] = CELL_EMPTY;
1383 state->common->xinfo[x+y*(state->common->params.w+2)] = count;
1384 state->guess[count] = 7;
1385 state->common->fixed[count++] = FALSE;
1393 for (i=0;i<2*(state->common->params.w + state->common->params.h);i++) {
1397 sights = atoi(desc);
1398 while (*desc && isdigit((unsigned char)*desc)) desc++;
1402 range2grid(i,state->common->params.w,state->common->params.h,&x,&y);
1403 state->common->grid[x+y*(state->common->params.w +2)] = sights;
1404 state->common->xinfo[x+y*(state->common->params.w +2)] = -2;
1407 state->common->grid[0] = 0;
1408 state->common->xinfo[0] = -2;
1409 state->common->grid[state->common->params.w+1] = 0;
1410 state->common->xinfo[state->common->params.w+1] = -2;
1411 state->common->grid[state->common->params.w+1 + (state->common->params.h+1)*(state->common->params.w+2)] = 0;
1412 state->common->xinfo[state->common->params.w+1 + (state->common->params.h+1)*(state->common->params.w+2)] = -2;
1413 state->common->grid[(state->common->params.h+1)*(state->common->params.w+2)] = 0;
1414 state->common->xinfo[(state->common->params.h+1)*(state->common->params.w+2)] = -2;
1417 qsort(state->common->paths, state->common->num_paths, sizeof(struct path), path_cmp);
1422 static char *validate_desc(game_params *params, char *desc) {
1424 int w = params->w, h = params->h;
1429 char *desc_s = desc;
1432 if (!*desc) return "Faulty game description";
1433 while (*desc && isdigit((unsigned char)*desc)) { desc++; }
1434 if (*desc != ',') return "Invalid character in number list";
1439 area = monsters = monster_count = 0;
1441 monster_count += atoi(desc);
1442 while (*desc && isdigit((unsigned char)*desc)) desc++;
1445 while (*desc && *desc != ',') {
1446 if (*desc >= 'a' && *desc <= 'z') {
1447 area += *desc - 'a' +1; monsters += *desc - 'a' +1;
1448 } else if (*desc == 'G' || *desc == 'V' || *desc == 'Z') {
1450 } else if (*desc == 'L' || *desc == 'R') {
1453 return "Invalid character in grid specification";
1456 if (area < wh) return "Not enough data to fill grid";
1457 else if (area > wh) return "Too much data to fill grid";
1458 if (monsters != monster_count)
1459 return "Monster numbers do not match grid spaces";
1461 for (i = 0; i < 2*(w+h); i++) {
1462 if (!*desc) return "Not enough numbers given after grid specification";
1463 else if (*desc != ',') return "Invalid character in number list";
1465 while (*desc && isdigit((unsigned char)*desc)) { desc++; }
1468 if (*desc) return "Unexpected additional data at end of game description";
1473 static char *solve_game(game_state *state_start, game_state *currstate, char *aux, char **error) {
1476 int iterative_depth;
1477 int solved_iterative, solved_bruteforce, contains_inconsistency,
1483 game_state *solve_state = dup_game(currstate);
1485 old_guess = snewn(solve_state->common->num_total,int);
1486 for (p=0;p<solve_state->common->num_total;p++) {
1487 if (solve_state->common->fixed[p]) {
1488 old_guess[p] = solve_state->guess[p] = state_start->guess[p];
1491 old_guess[p] = solve_state->guess[p] = 7;
1494 iterative_depth = 0;
1495 solved_iterative = FALSE;
1496 contains_inconsistency = FALSE;
1497 count_ambiguous = 0;
1499 /* Try to solve the puzzle with the iterative solver */
1504 solve_iterative(solve_state,solve_state->common->paths);
1506 for (p=0;p<solve_state->common->num_total;p++) {
1507 if (solve_state->guess[p] != old_guess[p]) no_change = FALSE;
1508 old_guess[p] = solve_state->guess[p];
1509 if (solve_state->guess[p] == 0) contains_inconsistency = TRUE;
1511 if (solved_iterative || no_change || contains_inconsistency) break;
1514 if (contains_inconsistency) {
1515 *error = "Puzzle is inconsistent";
1517 free_game(solve_state);
1521 /* If necessary, try to solve the puzzle with the brute-force solver */
1522 solved_bruteforce = FALSE;
1523 if (!solved_iterative) {
1524 for (p=0;p<solve_state->common->num_total;p++)
1525 if (solve_state->guess[p] != 1 && solve_state->guess[p] != 2 &&
1526 solve_state->guess[p] != 4) count_ambiguous++;
1528 solve_bruteforce(solve_state, solve_state->common->paths);
1531 if (!solved_iterative && !solved_bruteforce) {
1532 *error = "Puzzle is unsolvable";
1534 free_game(solve_state);
1538 /* printf("Puzzle solved at level %s, iterations %d, ambiguous %d\n", (solved_bruteforce ? "TRICKY" : "NORMAL"), iterative_depth, count_ambiguous); */
1540 move = snewn(solve_state->common->num_total * 4 +2, char);
1543 for (i = 0; i < solve_state->common->num_total; i++) {
1544 if (solve_state->guess[i] == 1) c += sprintf(c, ";G%d", i);
1545 if (solve_state->guess[i] == 2) c += sprintf(c, ";V%d", i);
1546 if (solve_state->guess[i] == 4) c += sprintf(c, ";Z%d", i);
1549 move = sresize(move, c - move, char);
1552 free_game(solve_state);
1556 static int game_can_format_as_text_now(game_params *params) {
1560 static char *game_text_format(game_state *state) {
1565 ret = snewn(50 + 6*(state->common->params.w +2) +
1566 6*(state->common->params.h+2) +
1567 3*(state->common->params.w * state->common->params.h), char);
1569 sprintf(ret,"G: %d V: %d Z: %d\n\n",state->common->num_ghosts,
1570 state->common->num_vampires, state->common->num_zombies);
1572 for (h=0;h<state->common->params.h+2;h++) {
1573 for (w=0;w<state->common->params.w+2;w++) {
1574 c = state->common->grid[w+h*(state->common->params.w+2)];
1575 xi = state->common->xinfo[w+h*(state->common->params.w+2)];
1576 r = grid2range(w,h,state->common->params.w,state->common->params.h);
1578 sprintf(buf,"%2d", c); strcat(ret,buf);
1579 } else if (c == CELL_MIRROR_L) {
1580 sprintf(buf," \\"); strcat(ret,buf);
1581 } else if (c == CELL_MIRROR_R) {
1582 sprintf(buf," /"); strcat(ret,buf);
1583 } else if (xi >= 0) {
1584 g = state->guess[xi];
1585 if (g == 1) { sprintf(buf," G"); strcat(ret,buf); }
1586 else if (g == 2) { sprintf(buf," V"); strcat(ret,buf); }
1587 else if (g == 4) { sprintf(buf," Z"); strcat(ret,buf); }
1588 else { sprintf(buf," ."); strcat(ret,buf); }
1590 sprintf(buf," "); strcat(ret,buf);
1593 sprintf(buf,"\n"); strcat(ret,buf);
1600 int hx, hy; /* as for solo.c, highlight pos */
1601 int hshow, hpencil, hcursor; /* show state, type, and ?cursor. */
1605 static game_ui *new_ui(game_state *state) {
1606 game_ui *ui = snew(game_ui);
1607 ui->hx = ui->hy = 0;
1608 ui->hpencil = ui->hshow = ui->hcursor = 0;
1613 static void free_ui(game_ui *ui) {
1618 static char *encode_ui(game_ui *ui) {
1622 static void decode_ui(game_ui *ui, char *encoding) {
1626 static void game_changed_state(game_ui *ui, game_state *oldstate, game_state *newstate) {
1627 /* See solo.c; if we were pencil-mode highlighting and
1628 * somehow a square has just been properly filled, cancel
1630 if (ui->hshow && ui->hpencil && !ui->hcursor) {
1631 int g = newstate->guess[newstate->common->xinfo[ui->hx + ui->hy*(newstate->common->params.w+2)]];
1632 if (g == 1 || g == 2 || g == 4)
1637 struct game_drawstate {
1638 int tilesize, started, solved;
1642 unsigned char *pencils;
1644 unsigned char count_errors[3];
1645 unsigned char *cell_errors;
1646 unsigned char *hint_errors;
1648 int hx, hy, hshow, hpencil; /* as for game_ui. */
1653 #define TILESIZE (ds->tilesize)
1654 #define BORDER (TILESIZE/4)
1656 static char *interpret_move(game_state *state, game_ui *ui,
1657 const game_drawstate *ds, int x, int y, int button)
1663 gx = ((x-BORDER-1) / TILESIZE );
1664 gy = ((y-BORDER-2) / TILESIZE ) - 1;
1666 if (button == 'a' || button == 'A') {
1667 ui->ascii = !ui->ascii;
1671 if (ui->hshow == 1 && ui->hpencil == 0) {
1672 xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)];
1673 if (xi >= 0 && !state->common->fixed[xi]) {
1674 if (button == 'g' || button == 'G' || button == '1') {
1675 if (!ui->hcursor) ui->hshow = 0;
1676 sprintf(buf,"G%d",xi);
1679 if (button == 'v' || button == 'V' || button == '2') {
1680 if (!ui->hcursor) ui->hshow = 0;
1681 sprintf(buf,"V%d",xi);
1684 if (button == 'z' || button == 'Z' || button == '3') {
1685 if (!ui->hcursor) ui->hshow = 0;
1686 sprintf(buf,"Z%d",xi);
1689 if (button == 'e' || button == 'E' || button == CURSOR_SELECT2 ||
1690 button == '0' || button == '\b' ) {
1691 if (!ui->hcursor) ui->hshow = 0;
1692 sprintf(buf,"E%d",xi);
1698 if (IS_CURSOR_MOVE(button)) {
1699 if (ui->hx == 0 && ui->hy == 0) {
1703 else switch (button) {
1704 case CURSOR_UP: ui->hy -= (ui->hy > 1) ? 1 : 0; break;
1705 case CURSOR_DOWN: ui->hy += (ui->hy < ds->h) ? 1 : 0; break;
1706 case CURSOR_RIGHT: ui->hx += (ui->hx < ds->w) ? 1 : 0; break;
1707 case CURSOR_LEFT: ui->hx -= (ui->hx > 1) ? 1 : 0; break;
1709 ui->hshow = ui->hcursor = 1;
1712 if (ui->hshow && button == CURSOR_SELECT) {
1713 ui->hpencil = 1 - ui->hpencil;
1718 if (ui->hshow == 1 && ui->hpencil == 1) {
1719 xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)];
1720 if (xi >= 0 && !state->common->fixed[xi]) {
1721 if (button == 'g' || button == 'G' || button == '1') {
1722 sprintf(buf,"g%d",xi);
1723 if (!ui->hcursor) ui->hpencil = ui->hshow = 0;
1726 if (button == 'v' || button == 'V' || button == '2') {
1727 sprintf(buf,"v%d",xi);
1728 if (!ui->hcursor) ui->hpencil = ui->hshow = 0;
1731 if (button == 'z' || button == 'Z' || button == '3') {
1732 sprintf(buf,"z%d",xi);
1733 if (!ui->hcursor) ui->hpencil = ui->hshow = 0;
1736 if (button == 'e' || button == 'E' || button == CURSOR_SELECT2 ||
1737 button == '0' || button == '\b') {
1738 sprintf(buf,"E%d",xi);
1739 if (!ui->hcursor) ui->hpencil = ui->hshow = 0;
1745 if (gx > 0 && gx < ds->w+1 && gy > 0 && gy < ds->h+1) {
1746 xi = state->common->xinfo[gx+gy*(state->common->params.w+2)];
1747 if (xi >= 0 && !state->common->fixed[xi]) {
1748 g = state->guess[xi];
1749 if (ui->hshow == 0) {
1750 if (button == LEFT_BUTTON) {
1751 ui->hshow = 1; ui->hpencil = 0; ui->hcursor = 0;
1752 ui->hx = gx; ui->hy = gy;
1755 else if (button == RIGHT_BUTTON && g == 7) {
1756 ui->hshow = 1; ui->hpencil = 1; ui->hcursor = 0;
1757 ui->hx = gx; ui->hy = gy;
1761 else if (ui->hshow == 1) {
1762 if (button == LEFT_BUTTON) {
1763 if (ui->hpencil == 0) {
1764 if (gx == ui->hx && gy == ui->hy) {
1765 ui->hshow = 0; ui->hpencil = 0; ui->hcursor = 0;
1766 ui->hx = 0; ui->hy = 0;
1770 ui->hshow = 1; ui->hpencil = 0; ui->hcursor = 0;
1771 ui->hx = gx; ui->hy = gy;
1776 ui->hshow = 1; ui->hpencil = 0; ui->hcursor = 0;
1777 ui->hx = gx; ui->hy = gy;
1781 else if (button == RIGHT_BUTTON) {
1782 if (ui->hpencil == 0 && g == 7) {
1783 ui->hshow = 1; ui->hpencil = 1; ui->hcursor = 0;
1784 ui->hx = gx; ui->hy = gy;
1788 if (gx == ui->hx && gy == ui->hy) {
1789 ui->hshow = 0; ui->hpencil = 0; ui->hcursor = 0;
1790 ui->hx = 0; ui->hy = 0;
1794 ui->hshow = 1; ui->hpencil = 1; ui->hcursor = 0;
1795 ui->hx = gx; ui->hy = gy;
1807 int check_numbers_draw(game_state *state, int *guess) {
1810 int count_ghosts, count_vampires, count_zombies;
1812 count_ghosts = count_vampires = count_zombies = 0;
1813 for (i=0;i<state->common->num_total;i++) {
1814 if (guess[i] == 1) count_ghosts++;
1815 if (guess[i] == 2) count_vampires++;
1816 if (guess[i] == 4) count_zombies++;
1820 filled = (count_ghosts + count_vampires + count_zombies >=
1821 state->common->num_total);
1823 if (count_ghosts > state->common->num_ghosts ||
1824 (filled && count_ghosts != state->common->num_ghosts) ) {
1826 state->count_errors[0] = TRUE;
1827 for (x=1;x<state->common->params.w+1;x++)
1828 for (y=1;y<state->common->params.h+1;y++) {
1829 xy = x+y*(state->common->params.w+2);
1830 if (state->common->xinfo[xy] >= 0 &&
1831 guess[state->common->xinfo[xy]] == 1)
1832 state->cell_errors[xy] = TRUE;
1835 if (count_vampires > state->common->num_vampires ||
1836 (filled && count_vampires != state->common->num_vampires) ) {
1838 state->count_errors[1] = TRUE;
1839 for (x=1;x<state->common->params.w+1;x++)
1840 for (y=1;y<state->common->params.h+1;y++) {
1841 xy = x+y*(state->common->params.w+2);
1842 if (state->common->xinfo[xy] >= 0 &&
1843 guess[state->common->xinfo[xy]] == 2)
1844 state->cell_errors[xy] = TRUE;
1847 if (count_zombies > state->common->num_zombies ||
1848 (filled && count_zombies != state->common->num_zombies) ) {
1850 state->count_errors[2] = TRUE;
1851 for (x=1;x<state->common->params.w+1;x++)
1852 for (y=1;y<state->common->params.h+1;y++) {
1853 xy = x+y*(state->common->params.w+2);
1854 if (state->common->xinfo[xy] >= 0 &&
1855 guess[state->common->xinfo[xy]] == 4)
1856 state->cell_errors[xy] = TRUE;
1863 int check_path_solution(game_state *state, int p) {
1875 for (i=0;i<state->common->paths[p].length;i++) {
1876 if (state->common->paths[p].p[i] == -1) mirror = TRUE;
1878 if (state->guess[state->common->paths[p].p[i]] == 1 && mirror)
1880 else if (state->guess[state->common->paths[p].p[i]] == 2 && !mirror)
1882 else if (state->guess[state->common->paths[p].p[i]] == 4)
1884 else if (state->guess[state->common->paths[p].p[i]] == 7)
1889 if (unfilled == 0 && count != state->common->paths[p].sightings_start) {
1891 state->hint_errors[state->common->paths[p].grid_start] = TRUE;
1897 for (i=state->common->paths[p].length-1;i>=0;i--) {
1898 if (state->common->paths[p].p[i] == -1) mirror = TRUE;
1900 if (state->guess[state->common->paths[p].p[i]] == 1 && mirror)
1902 else if (state->guess[state->common->paths[p].p[i]] == 2 && !mirror)
1904 else if (state->guess[state->common->paths[p].p[i]] == 4)
1906 else if (state->guess[state->common->paths[p].p[i]] == 7)
1911 if (unfilled == 0 && count != state->common->paths[p].sightings_end) {
1913 state->hint_errors[state->common->paths[p].grid_end] = TRUE;
1917 for (i=0;i<state->common->paths[p].length;i++)
1918 state->cell_errors[state->common->paths[p].xy[i]] = TRUE;
1924 static game_state *execute_move(game_state *state, char *move) {
1930 game_state *ret = dup_game(state);
1939 if (c == 'G' || c == 'V' || c == 'Z' || c == 'E' ||
1940 c == 'g' || c == 'v' || c == 'z') {
1942 sscanf(move, "%d%n", &x, &n);
1943 if (c == 'G') ret->guess[x] = 1;
1944 if (c == 'V') ret->guess[x] = 2;
1945 if (c == 'Z') ret->guess[x] = 4;
1946 if (c == 'E') { ret->guess[x] = 7; ret->pencils[x] = 0; }
1947 if (c == 'g') ret->pencils[x] ^= 1;
1948 if (c == 'v') ret->pencils[x] ^= 2;
1949 if (c == 'z') ret->pencils[x] ^= 4;
1952 if (*move == ';') move++;
1957 for (i=0;i<ret->common->wh;i++) ret->cell_errors[i] = FALSE;
1958 for (i=0;i<2*ret->common->num_paths;i++) ret->hint_errors[i] = FALSE;
1959 for (i=0;i<3;i++) ret->count_errors[i] = FALSE;
1961 if (!check_numbers_draw(ret,ret->guess)) correct = FALSE;
1963 for (p=0;p<state->common->num_paths;p++)
1964 if (!check_path_solution(ret,p)) correct = FALSE;
1966 for (i=0;i<state->common->num_total;i++)
1967 if (!(ret->guess[i] == 1 || ret->guess[i] == 2 ||
1968 ret->guess[i] == 4)) correct = FALSE;
1970 if (correct && !solver) ret->solved = TRUE;
1971 if (solver) ret->cheated = TRUE;
1976 /* ----------------------------------------------------------------------
1980 #define PREFERRED_TILE_SIZE 64
1982 static void game_compute_size(game_params *params, int tilesize,
1984 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1985 struct { int tilesize; } ads, *ds = &ads;
1986 ads.tilesize = tilesize;
1988 *x = 2*BORDER+(params->w+2)*TILESIZE;
1989 *y = 2*BORDER+(params->h+3)*TILESIZE;
1993 static void game_set_size(drawing *dr, game_drawstate *ds,
1994 game_params *params, int tilesize) {
1995 ds->tilesize = tilesize;
1999 #define COLOUR(ret, i, r, g, b) ((ret[3*(i)+0] = (r)), (ret[3*(i)+1] = (g)), (ret[3*(i)+2] = (b)))
2001 static float *game_colours(frontend *fe, int *ncolours) {
2002 float *ret = snewn(3 * NCOLOURS, float);
2004 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
2006 ret[COL_GRID * 3 + 0] = 0.0F;
2007 ret[COL_GRID * 3 + 1] = 0.0F;
2008 ret[COL_GRID * 3 + 2] = 0.0F;
2010 ret[COL_TEXT * 3 + 0] = 0.0F;
2011 ret[COL_TEXT * 3 + 1] = 0.0F;
2012 ret[COL_TEXT * 3 + 2] = 0.0F;
2014 ret[COL_ERROR * 3 + 0] = 1.0F;
2015 ret[COL_ERROR * 3 + 1] = 0.0F;
2016 ret[COL_ERROR * 3 + 2] = 0.0F;
2018 ret[COL_HIGHLIGHT * 3 + 0] = 0.78F * ret[COL_BACKGROUND * 3 + 0];
2019 ret[COL_HIGHLIGHT * 3 + 1] = 0.78F * ret[COL_BACKGROUND * 3 + 1];
2020 ret[COL_HIGHLIGHT * 3 + 2] = 0.78F * ret[COL_BACKGROUND * 3 + 2];
2022 ret[COL_FLASH * 3 + 0] = 1.0F;
2023 ret[COL_FLASH * 3 + 1] = 1.0F;
2024 ret[COL_FLASH * 3 + 2] = 1.0F;
2026 ret[COL_GHOST * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.5F;
2027 ret[COL_GHOST * 3 + 1] = ret[COL_BACKGROUND * 3 + 0];
2028 ret[COL_GHOST * 3 + 2] = ret[COL_BACKGROUND * 3 + 0];
2030 ret[COL_ZOMBIE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.5F;
2031 ret[COL_ZOMBIE * 3 + 1] = ret[COL_BACKGROUND * 3 + 0];
2032 ret[COL_ZOMBIE * 3 + 2] = ret[COL_BACKGROUND * 3 + 0] * 0.5F;
2034 ret[COL_VAMPIRE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0];
2035 ret[COL_VAMPIRE * 3 + 1] = ret[COL_BACKGROUND * 3 + 0] * 0.9F;
2036 ret[COL_VAMPIRE * 3 + 2] = ret[COL_BACKGROUND * 3 + 0] * 0.9F;
2038 *ncolours = NCOLOURS;
2042 static game_drawstate *game_new_drawstate(drawing *dr, game_state *state) {
2044 struct game_drawstate *ds = snew(struct game_drawstate);
2047 ds->started = ds->solved = FALSE;
2048 ds->w = state->common->params.w;
2049 ds->h = state->common->params.h;
2052 ds->count_errors[0] = FALSE;
2053 ds->count_errors[1] = FALSE;
2054 ds->count_errors[2] = FALSE;
2056 ds->monsters = snewn(state->common->num_total,int);
2057 for (i=0;i<(state->common->num_total);i++)
2058 ds->monsters[i] = 7;
2059 ds->pencils = snewn(state->common->num_total,unsigned char);
2060 for (i=0;i<state->common->num_total;i++)
2063 ds->cell_errors = snewn(state->common->wh,unsigned char);
2064 for (i=0;i<state->common->wh;i++)
2065 ds->cell_errors[i] = FALSE;
2066 ds->hint_errors = snewn(2*state->common->num_paths,unsigned char);
2067 for (i=0;i<2*state->common->num_paths;i++)
2068 ds->hint_errors[i] = FALSE;
2070 ds->hshow = ds->hpencil = ds->hflash = 0;
2071 ds->hx = ds->hy = 0;
2075 static void game_free_drawstate(drawing *dr, game_drawstate *ds) {
2076 sfree(ds->hint_errors);
2077 sfree(ds->cell_errors);
2079 sfree(ds->monsters);
2084 static void draw_cell_background(drawing *dr, game_drawstate *ds,
2085 game_state *state, game_ui *ui, int x, int y) {
2089 dx = BORDER+(x* ds->tilesize)+(TILESIZE/2);
2090 dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE;
2092 hon = (ui->hshow && x == ui->hx && y == ui->hy);
2093 draw_rect(dr,dx-(TILESIZE/2)+1,dy-(TILESIZE/2)+1,TILESIZE-1,TILESIZE-1,(hon && !ui->hpencil) ? COL_HIGHLIGHT : COL_BACKGROUND);
2095 if (hon && ui->hpencil) {
2097 coords[0] = dx-(TILESIZE/2)+1;
2098 coords[1] = dy-(TILESIZE/2)+1;
2099 coords[2] = coords[0] + TILESIZE/2;
2100 coords[3] = coords[1];
2101 coords[4] = coords[0];
2102 coords[5] = coords[1] + TILESIZE/2;
2103 draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
2106 draw_update(dr,dx-(TILESIZE/2)+1,dy-(TILESIZE/2)+1,TILESIZE-1,TILESIZE-1);
2111 static void draw_circle_or_point(drawing *dr, int cx, int cy, int radius,
2115 draw_circle(dr, cx, cy, radius, colour, colour);
2117 draw_rect(dr, cx, cy, 1, 1, colour);
2120 static void draw_monster(drawing *dr, game_drawstate *ds, int x, int y,
2121 int tilesize, int hflash, int monster)
2123 int black = (hflash ? COL_FLASH : COL_TEXT);
2125 if (monster == 1) { /* ghost */
2128 clip(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize-3,tilesize/2+1);
2129 draw_circle(dr,x,y,2*tilesize/5, COL_GHOST,black);
2133 poly[i++] = x - 2*tilesize/5;
2135 poly[i++] = x - 2*tilesize/5;
2136 poly[i++] = y + 2*tilesize/5;
2138 for (j = 0; j < 3; j++) {
2139 int total = (2*tilesize/5) * 2;
2140 int before = total * j / 3;
2141 int after = total * (j+1) / 3;
2142 int mid = (before + after) / 2;
2143 poly[i++] = x - 2*tilesize/5 + mid;
2144 poly[i++] = y + 2*tilesize/5 - (total / 6);
2145 poly[i++] = x - 2*tilesize/5 + after;
2146 poly[i++] = y + 2*tilesize/5;
2149 poly[i++] = x + 2*tilesize/5;
2152 clip(dr,x-(tilesize/2)+2,y,tilesize-3,tilesize-(tilesize/2)-1);
2153 draw_polygon(dr, poly, i/2, COL_GHOST, black);
2156 draw_circle(dr,x-tilesize/6,y-tilesize/12,tilesize/10,
2157 COL_BACKGROUND,black);
2158 draw_circle(dr,x+tilesize/6,y-tilesize/12,tilesize/10,
2159 COL_BACKGROUND,black);
2161 draw_circle_or_point(dr,x-tilesize/6+1+tilesize/48,y-tilesize/12,
2163 draw_circle_or_point(dr,x+tilesize/6+1+tilesize/48,y-tilesize/12,
2166 } else if (monster == 2) { /* vampire */
2169 clip(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize-3,tilesize/2);
2170 draw_circle(dr,x,y,2*tilesize/5,black,black);
2173 clip(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize/2+1,tilesize/2);
2174 draw_circle(dr,x-tilesize/7,y,2*tilesize/5-tilesize/7,
2177 clip(dr,x,y-(tilesize/2)+2,tilesize/2+1,tilesize/2);
2178 draw_circle(dr,x+tilesize/7,y,2*tilesize/5-tilesize/7,
2182 clip(dr,x-(tilesize/2)+2,y,tilesize-3,tilesize/2);
2183 draw_circle(dr,x,y,2*tilesize/5, COL_VAMPIRE,black);
2186 draw_circle(dr, x-tilesize/7, y-tilesize/16, tilesize/16,
2187 COL_BACKGROUND, black);
2188 draw_circle(dr, x+tilesize/7, y-tilesize/16, tilesize/16,
2189 COL_BACKGROUND, black);
2190 draw_circle_or_point(dr, x-tilesize/7, y-tilesize/16, tilesize/48,
2192 draw_circle_or_point(dr, x+tilesize/7, y-tilesize/16, tilesize/48,
2195 clip(dr, x-(tilesize/2)+2, y+tilesize/8, tilesize-3, tilesize/4);
2198 poly[i++] = x-3*tilesize/16;
2199 poly[i++] = y+1*tilesize/8;
2200 poly[i++] = x-2*tilesize/16;
2201 poly[i++] = y+7*tilesize/24;
2202 poly[i++] = x-1*tilesize/16;
2203 poly[i++] = y+1*tilesize/8;
2204 draw_polygon(dr, poly, i/2, COL_BACKGROUND, black);
2206 poly[i++] = x+3*tilesize/16;
2207 poly[i++] = y+1*tilesize/8;
2208 poly[i++] = x+2*tilesize/16;
2209 poly[i++] = y+7*tilesize/24;
2210 poly[i++] = x+1*tilesize/16;
2211 poly[i++] = y+1*tilesize/8;
2212 draw_polygon(dr, poly, i/2, COL_BACKGROUND, black);
2214 draw_circle(dr, x, y-tilesize/5, 2*tilesize/5, COL_VAMPIRE, black);
2217 } else if (monster == 4) { /* zombie */
2218 draw_circle(dr,x,y,2*tilesize/5, COL_ZOMBIE,black);
2221 x-tilesize/7-tilesize/16, y-tilesize/12-tilesize/16,
2222 x-tilesize/7+tilesize/16, y-tilesize/12+tilesize/16,
2225 x-tilesize/7+tilesize/16, y-tilesize/12-tilesize/16,
2226 x-tilesize/7-tilesize/16, y-tilesize/12+tilesize/16,
2229 x+tilesize/7-tilesize/16, y-tilesize/12-tilesize/16,
2230 x+tilesize/7+tilesize/16, y-tilesize/12+tilesize/16,
2233 x+tilesize/7+tilesize/16, y-tilesize/12-tilesize/16,
2234 x+tilesize/7-tilesize/16, y-tilesize/12+tilesize/16,
2237 clip(dr, x-tilesize/5, y+tilesize/6, 2*tilesize/5+1, tilesize/2);
2238 draw_circle(dr, x-tilesize/15, y+tilesize/6, tilesize/12,
2239 COL_BACKGROUND, black);
2242 draw_line(dr, x-tilesize/5, y+tilesize/6, x+tilesize/5, y+tilesize/6,
2246 draw_update(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize-3,tilesize-3);
2249 static void draw_monster_count(drawing *dr, game_drawstate *ds,
2250 game_state *state, int c, int hflash) {
2257 dx = BORDER+(ds->w+2)*TILESIZE/2+TILESIZE/4;
2260 sprintf(buf,"%d",state->common->num_ghosts);
2265 sprintf(buf,"%d",state->common->num_vampires);
2269 sprintf(buf,"%d",state->common->num_zombies);
2276 draw_rect(dr,dx-2*TILESIZE/3,dy,3*TILESIZE/2,dh,COL_BACKGROUND);
2277 draw_monster(dr,ds,dx-TILESIZE/3,dh,2*TILESIZE/3,hflash,1<<c);
2278 draw_text(dr,dx,dh,FONT_VARIABLE,dy-1,ALIGN_HLEFT|ALIGN_VCENTRE,
2279 (state->count_errors[c] ? COL_ERROR : hflash ? COL_FLASH : COL_TEXT), buf);
2280 draw_update(dr,dx-2*TILESIZE/3,dy,3*TILESIZE/2,dh);
2283 draw_rect(dr,dx-2*TILESIZE/3,dy,3*TILESIZE/2,dh,COL_BACKGROUND);
2284 draw_text(dr,dx-TILESIZE/3,dh,FONT_VARIABLE,dy-1,
2285 ALIGN_HCENTRE|ALIGN_VCENTRE,
2286 hflash ? COL_FLASH : COL_TEXT, bufm);
2287 draw_text(dr,dx,dh,FONT_VARIABLE,dy-1,ALIGN_HLEFT|ALIGN_VCENTRE,
2288 (state->count_errors[c] ? COL_ERROR : hflash ? COL_FLASH : COL_TEXT), buf);
2289 draw_update(dr,dx-2*TILESIZE/3,dy,3*TILESIZE/2,dh);
2295 static void draw_path_hint(drawing *dr, game_drawstate *ds, game_state *state,
2296 int i, int hflash, int start) {
2301 p = start ? state->common->paths[i].grid_start : state->common->paths[i].grid_end;
2302 range2grid(p,state->common->params.w,state->common->params.h,&x,&y);
2303 error = ds->hint_errors[p];
2305 dx = BORDER+(x* ds->tilesize)+(TILESIZE/2);
2306 dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE;
2307 sprintf(buf,"%d", start ? state->common->paths[i].sightings_start : state->common->paths[i].sightings_end);
2308 draw_rect(dr,dx-(TILESIZE/2)+2,dy-(TILESIZE/2)+2,TILESIZE-3,TILESIZE-3,COL_BACKGROUND);
2309 draw_text(dr,dx,dy,FONT_FIXED,TILESIZE/2,ALIGN_HCENTRE|ALIGN_VCENTRE, error ? COL_ERROR : hflash ? COL_FLASH : COL_TEXT,buf);
2310 draw_update(dr,dx-(TILESIZE/2)+2,dy-(TILESIZE/2)+2,TILESIZE-3,TILESIZE-3);
2315 static void draw_mirror(drawing *dr, game_drawstate *ds, game_state *state,
2316 int x, int y, int hflash, int mirror) {
2317 int dx,dy,mx1,my1,mx2,my2;
2318 dx = BORDER+(x* ds->tilesize)+(TILESIZE/2);
2319 dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE;
2321 if (mirror == CELL_MIRROR_L) {
2322 mx1 = dx-(TILESIZE/4);
2323 my1 = dy-(TILESIZE/4);
2324 mx2 = dx+(TILESIZE/4);
2325 my2 = dy+(TILESIZE/4);
2328 mx1 = dx-(TILESIZE/4);
2329 my1 = dy+(TILESIZE/4);
2330 mx2 = dx+(TILESIZE/4);
2331 my2 = dy-(TILESIZE/4);
2333 draw_thick_line(dr,(float)(TILESIZE/16),mx1,my1,mx2,my2,
2334 hflash ? COL_FLASH : COL_TEXT);
2335 draw_update(dr,dx-(TILESIZE/2)+1,dy-(TILESIZE/2)+1,TILESIZE-1,TILESIZE-1);
2340 static void draw_big_monster(drawing *dr, game_drawstate *ds, game_state *state,
2341 int x, int y, int hflash, int monster)
2345 dx = BORDER+(x* ds->tilesize)+(TILESIZE/2);
2346 dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE;
2348 if (monster == 1) sprintf(buf,"G");
2349 else if (monster == 2) sprintf(buf,"V");
2350 else if (monster == 4) sprintf(buf,"Z");
2351 else sprintf(buf," ");
2352 draw_text(dr,dx,dy,FONT_FIXED,TILESIZE/2,ALIGN_HCENTRE|ALIGN_VCENTRE,
2353 hflash ? COL_FLASH : COL_TEXT,buf);
2354 draw_update(dr,dx-(TILESIZE/2)+2,dy-(TILESIZE/2)+2,TILESIZE-3,
2358 draw_monster(dr, ds, dx, dy, 3*TILESIZE/4, hflash, monster);
2363 static void draw_pencils(drawing *dr, game_drawstate *ds, game_state *state,
2364 int x, int y, int pencil) {
2369 dx = BORDER+(x* ds->tilesize)+(TILESIZE/4);
2370 dy = BORDER+(y* ds->tilesize)+(TILESIZE/4)+TILESIZE;
2372 for (i = 0, j = 1; j < 8; j *= 2)
2378 for (py = 0; py < 2; py++)
2379 for (px = 0; px < 2; px++)
2380 if (monsters[py*2+px]) {
2382 draw_monster(dr, ds,
2383 dx + TILESIZE/2 * px, dy + TILESIZE/2 * py,
2384 TILESIZE/2, 0, monsters[py*2+px]);
2387 switch (monsters[py*2+px]) {
2388 case 1: sprintf(buf,"G"); break;
2389 case 2: sprintf(buf,"V"); break;
2390 case 4: sprintf(buf,"Z"); break;
2392 draw_text(dr,dx + TILESIZE/2 * px,dy + TILESIZE/2 * py,
2393 FONT_FIXED,TILESIZE/4,ALIGN_HCENTRE|ALIGN_VCENTRE,
2397 draw_update(dr,dx-(TILESIZE/4)+2,dy-(TILESIZE/4)+2,
2398 (TILESIZE/2)-3,(TILESIZE/2)-3);
2403 #define FLASH_TIME 0.7F
2405 static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
2406 game_state *state, int dir, game_ui *ui,
2407 float animtime, float flashtime) {
2409 int stale, xi, c, hflash, hchanged, changed_ascii;
2411 hflash = (int)(flashtime * 5 / FLASH_TIME) % 2;
2413 /* Draw static grid components at startup */
2415 draw_rect(dr, 0, 0, 2*BORDER+(ds->w+2)*TILESIZE,
2416 2*BORDER+(ds->h+3)*TILESIZE, COL_BACKGROUND);
2417 draw_rect(dr, BORDER+TILESIZE-1, BORDER+2*TILESIZE-1,
2418 (ds->w)*TILESIZE +3, (ds->h)*TILESIZE +3, COL_GRID);
2419 for (i=0;i<ds->w;i++)
2420 for (j=0;j<ds->h;j++)
2421 draw_rect(dr, BORDER+(ds->tilesize*(i+1))+1,
2422 BORDER+(ds->tilesize*(j+2))+1, ds->tilesize-1,
2423 ds->tilesize-1, COL_BACKGROUND);
2424 draw_update(dr, 0, 0, 2*BORDER+(ds->w+2)*TILESIZE,
2425 2*BORDER+(ds->h+3)*TILESIZE);
2429 if (ds->hx != ui->hx || ds->hy != ui->hy ||
2430 ds->hshow != ui->hshow || ds->hpencil != ui->hpencil)
2433 if (ds->ascii != ui->ascii) {
2434 ds->ascii = ui->ascii;
2435 changed_ascii = TRUE;
2437 changed_ascii = FALSE;
2439 /* Draw monster count hints */
2443 if (!ds->started) stale = TRUE;
2444 if (ds->hflash != hflash) stale = TRUE;
2445 if (changed_ascii) stale = TRUE;
2446 if (ds->count_errors[i] != state->count_errors[i]) {
2448 ds->count_errors[i] = state->count_errors[i];
2452 draw_monster_count(dr, ds, state, i, hflash);
2456 /* Draw path count hints */
2457 for (i=0;i<state->common->num_paths;i++) {
2461 if (!ds->started) stale = TRUE;
2462 if (ds->hflash != hflash) stale = TRUE;
2464 p = state->common->paths[i].grid_start;
2465 if (ds->hint_errors[p] != state->hint_errors[p]) {
2467 ds->hint_errors[p] = state->hint_errors[p];
2471 draw_path_hint(dr, ds, state, i, hflash, TRUE);
2476 if (!ds->started) stale = TRUE;
2477 if (ds->hflash != hflash) stale = TRUE;
2479 p = state->common->paths[i].grid_end;
2480 if (ds->hint_errors[p] != state->hint_errors[p]) {
2482 ds->hint_errors[p] = state->hint_errors[p];
2486 draw_path_hint(dr, ds, state, i, hflash, FALSE);
2491 /* Draw puzzle grid contents */
2492 for (x = 1; x < ds->w+1; x++)
2493 for (y = 1; y < ds->h+1; y++) {
2495 xy = x+y*(state->common->params.w+2);
2496 xi = state->common->xinfo[xy];
2497 c = state->common->grid[xy];
2499 if (!ds->started) stale = TRUE;
2500 if (ds->hflash != hflash) stale = TRUE;
2501 if (changed_ascii) stale = TRUE;
2504 if ((x == ui->hx && y == ui->hy) ||
2505 (x == ds->hx && y == ds->hy))
2509 if (xi >= 0 && (state->guess[xi] != ds->monsters[xi]) ) {
2511 ds->monsters[xi] = state->guess[xi];
2514 if (xi >= 0 && (state->pencils[xi] != ds->pencils[xi]) ) {
2516 ds->pencils[xi] = state->pencils[xi];
2519 if (state->cell_errors[xy] != ds->cell_errors[xy]) {
2521 ds->cell_errors[xy] = state->cell_errors[xy];
2525 draw_cell_background(dr, ds, state, ui, x, y);
2527 draw_mirror(dr, ds, state, x, y, hflash, c);
2528 else if (state->guess[xi] == 1 || state->guess[xi] == 2 ||
2529 state->guess[xi] == 4)
2530 draw_big_monster(dr, ds, state, x, y, hflash, state->guess[xi]);
2532 draw_pencils(dr, ds, state, x, y, state->pencils[xi]);
2536 ds->hx = ui->hx; ds->hy = ui->hy;
2537 ds->hshow = ui->hshow;
2538 ds->hpencil = ui->hpencil;
2539 ds->hflash = hflash;
2544 static float game_anim_length(game_state *oldstate, game_state *newstate,
2545 int dir, game_ui *ui) {
2549 static float game_flash_length(game_state *oldstate, game_state *newstate,
2550 int dir, game_ui *ui) {
2551 return (!oldstate->solved && newstate->solved && !oldstate->cheated &&
2552 !newstate->cheated) ? FLASH_TIME : 0.0F;
2555 static int game_status(game_state *state) {
2556 return state->solved;
2559 static int game_timing_state(game_state *state, game_ui *ui) {
2563 static void game_print_size(game_params *params, float *x, float *y) {
2566 static void game_print(drawing *dr, game_state *state, int tilesize) {
2570 #define thegame undead
2573 const struct game thegame = {
2574 "Undead", "games.undead", "undead",
2581 TRUE, game_configure, custom_params,
2589 TRUE, game_can_format_as_text_now, game_text_format,
2597 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
2600 game_free_drawstate,
2605 FALSE, FALSE, game_print_size, game_print,
2606 FALSE, /* wants_statusbar */
2607 FALSE, game_timing_state,