A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/*
2 * towers.c: the puzzle also known as 'Skyscrapers'.
3 *
4 * Possible future work:
5 *
6 * - Relax the upper bound on grid size at 9?
7 * + I'd need TOCHAR and FROMCHAR macros a bit like group's, to
8 * be used wherever this code has +'0' or -'0'
9 * + the pencil marks in the drawstate would need a separate
10 * word to live in
11 * + the clues outside the grid would have to cope with being
12 * multi-digit, meaning in particular that the text formatting
13 * would become more unpleasant
14 * + most importantly, though, the solver just isn't fast
15 * enough. Even at size 9 it can't really do the solver_hard
16 * factorial-time enumeration at a sensible rate. Easy puzzles
17 * higher than that would be possible, but more latin-squarey
18 * than skyscrapery, as it were.
19 */
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <assert.h>
25#include <ctype.h>
26#ifdef NO_TGMATH_H
27# include <math.h>
28#else
29# include <tgmath.h>
30#endif
31
32#include "puzzles.h"
33#include "latin.h"
34
35/*
36 * Difficulty levels. I do some macro ickery here to ensure that my
37 * enum and the various forms of my name list always match up.
38 */
39#define DIFFLIST(A) \
40 A(EASY,Easy,solver_easy,e) \
41 A(HARD,Hard,solver_hard,h) \
42 A(EXTREME,Extreme,NULL,x) \
43 A(UNREASONABLE,Unreasonable,NULL,u)
44#define ENUM(upper,title,func,lower) DIFF_ ## upper,
45#define TITLE(upper,title,func,lower) #title,
46#define ENCODE(upper,title,func,lower) #lower
47#define CONFIG(upper,title,func,lower) ":" #title
48enum { DIFFLIST(ENUM) DIFFCOUNT };
49static char const *const towers_diffnames[] = { DIFFLIST(TITLE) };
50static char const towers_diffchars[] = DIFFLIST(ENCODE);
51#define DIFFCONFIG DIFFLIST(CONFIG)
52
53enum {
54 COL_BACKGROUND,
55 COL_GRID,
56 COL_USER,
57 COL_HIGHLIGHT,
58 COL_ERROR,
59 COL_PENCIL,
60 COL_DONE,
61 NCOLOURS
62};
63
64enum {
65 PREF_PENCIL_KEEP_HIGHLIGHT,
66 PREF_APPEARANCE,
67 N_PREF_ITEMS
68};
69
70struct game_params {
71 int w, diff;
72};
73
74struct clues {
75 int refcount;
76 int w;
77 /*
78 * An array of 4w integers, of which:
79 * - the first w run across the top
80 * - the next w across the bottom
81 * - the third w down the left
82 * - the last w down the right.
83 */
84 int *clues;
85
86 /*
87 * An array of w*w digits.
88 */
89 digit *immutable;
90};
91
92/*
93 * Macros to compute clue indices and coordinates.
94 */
95#define STARTSTEP(start, step, index, w) do { \
96 if (index < w) \
97 start = index, step = w; \
98 else if (index < 2*w) \
99 start = (w-1)*w+(index-w), step = -w; \
100 else if (index < 3*w) \
101 start = w*(index-2*w), step = 1; \
102 else \
103 start = w*(index-3*w)+(w-1), step = -1; \
104} while (0)
105#define CSTARTSTEP(start, step, index, w) \
106 STARTSTEP(start, step, (((index)+2*w)%(4*w)), w)
107#define CLUEPOS(x, y, index, w) do { \
108 if (index < w) \
109 x = index, y = -1; \
110 else if (index < 2*w) \
111 x = index-w, y = w; \
112 else if (index < 3*w) \
113 x = -1, y = index-2*w; \
114 else \
115 x = w, y = index-3*w; \
116} while (0)
117
118#ifdef STANDALONE_SOLVER
119static const char *const cluepos[] = {
120 "above column", "below column", "left of row", "right of row"
121};
122#endif
123
124struct game_state {
125 game_params par;
126 struct clues *clues;
127 bool *clues_done;
128 digit *grid;
129 int *pencil; /* bitmaps using bits 1<<1..1<<n */
130 bool completed, cheated;
131};
132
133static game_params *default_params(void)
134{
135 game_params *ret = snew(game_params);
136
137 ret->w = 5;
138 ret->diff = DIFF_EASY;
139
140 return ret;
141}
142
143static const struct game_params towers_presets[] = {
144 { 4, DIFF_EASY },
145 { 5, DIFF_EASY },
146 { 5, DIFF_HARD },
147 { 6, DIFF_EASY },
148 { 6, DIFF_HARD },
149 { 6, DIFF_EXTREME },
150 { 6, DIFF_UNREASONABLE },
151};
152
153static bool game_fetch_preset(int i, char **name, game_params **params)
154{
155 game_params *ret;
156 char buf[80];
157
158 if (i < 0 || i >= lenof(towers_presets))
159 return false;
160
161 ret = snew(game_params);
162 *ret = towers_presets[i]; /* structure copy */
163
164 sprintf(buf, "%dx%d %s", ret->w, ret->w, towers_diffnames[ret->diff]);
165
166 *name = dupstr(buf);
167 *params = ret;
168 return true;
169}
170
171static void free_params(game_params *params)
172{
173 sfree(params);
174}
175
176static game_params *dup_params(const game_params *params)
177{
178 game_params *ret = snew(game_params);
179 *ret = *params; /* structure copy */
180 return ret;
181}
182
183static void decode_params(game_params *params, char const *string)
184{
185 char const *p = string;
186
187 params->w = atoi(p);
188 while (*p && isdigit((unsigned char)*p)) p++;
189
190 if (*p == 'd') {
191 int i;
192 p++;
193 params->diff = DIFFCOUNT+1; /* ...which is invalid */
194 if (*p) {
195 for (i = 0; i < DIFFCOUNT; i++) {
196 if (*p == towers_diffchars[i])
197 params->diff = i;
198 }
199 p++;
200 }
201 }
202}
203
204static char *encode_params(const game_params *params, bool full)
205{
206 char ret[80];
207
208 sprintf(ret, "%d", params->w);
209 if (full)
210 sprintf(ret + strlen(ret), "d%c", towers_diffchars[params->diff]);
211
212 return dupstr(ret);
213}
214
215static config_item *game_configure(const game_params *params)
216{
217 config_item *ret;
218 char buf[80];
219
220 ret = snewn(3, config_item);
221
222 ret[0].name = "Grid size";
223 ret[0].type = C_STRING;
224 sprintf(buf, "%d", params->w);
225 ret[0].u.string.sval = dupstr(buf);
226
227 ret[1].name = "Difficulty";
228 ret[1].type = C_CHOICES;
229 ret[1].u.choices.choicenames = DIFFCONFIG;
230 ret[1].u.choices.selected = params->diff;
231
232 ret[2].name = NULL;
233 ret[2].type = C_END;
234
235 return ret;
236}
237
238static game_params *custom_params(const config_item *cfg)
239{
240 game_params *ret = snew(game_params);
241
242 ret->w = atoi(cfg[0].u.string.sval);
243 ret->diff = cfg[1].u.choices.selected;
244
245 return ret;
246}
247
248static const char *validate_params(const game_params *params, bool full)
249{
250 if (params->w < 3 || params->w > 9)
251 return "Grid size must be between 3 and 9";
252 if (params->diff >= DIFFCOUNT)
253 return "Unknown difficulty rating";
254 return NULL;
255}
256
257/* ----------------------------------------------------------------------
258 * Solver.
259 */
260
261struct solver_ctx {
262 int w, diff;
263 bool started;
264 int *clues;
265 long *iscratch;
266 int *dscratch;
267};
268
269static int solver_easy(struct latin_solver *solver, void *vctx)
270{
271 struct solver_ctx *ctx = (struct solver_ctx *)vctx;
272 int w = ctx->w;
273 int c, i, j, n, m, furthest;
274 int start, step, cstart, cstep, clue, pos, cpos;
275 int ret = 0;
276#ifdef STANDALONE_SOLVER
277 char prefix[256];
278#endif
279
280 if (!ctx->started) {
281 ctx->started = true;
282 /*
283 * One-off loop to help get started: when a pair of facing
284 * clues sum to w+1, it must mean that the row consists of
285 * two increasing sequences back to back, so we can
286 * immediately place the highest digit by knowing the
287 * lengths of those two sequences.
288 */
289 for (c = 0; c < 3*w; c = (c == w-1 ? 2*w : c+1)) {
290 int c2 = c + w;
291
292 if (ctx->clues[c] && ctx->clues[c2] &&
293 ctx->clues[c] + ctx->clues[c2] == w+1) {
294 STARTSTEP(start, step, c, w);
295 CSTARTSTEP(cstart, cstep, c, w);
296 pos = start + (ctx->clues[c]-1)*step;
297 cpos = cstart + (ctx->clues[c]-1)*cstep;
298 if (solver->cube[cpos*w+w-1]) {
299#ifdef STANDALONE_SOLVER
300 if (solver_show_working) {
301 printf("%*sfacing clues on %s %d are maximal:\n",
302 solver_recurse_depth*4, "",
303 c>=2*w ? "row" : "column", c % w + 1);
304 printf("%*s placing %d at (%d,%d)\n",
305 solver_recurse_depth*4, "",
306 w, pos%w+1, pos/w+1);
307 }
308#endif
309 latin_solver_place(solver, pos%w, pos/w, w);
310 ret = 1;
311 } else {
312 ret = -1;
313 }
314 }
315 }
316
317 if (ret)
318 return ret;
319 }
320
321 /*
322 * Go over every clue doing reasonably simple heuristic
323 * deductions.
324 */
325 for (c = 0; c < 4*w; c++) {
326 clue = ctx->clues[c];
327 if (!clue)
328 continue;
329 STARTSTEP(start, step, c, w);
330 CSTARTSTEP(cstart, cstep, c, w);
331
332 /* Find the location of each number in the row. */
333 for (i = 0; i < w; i++)
334 ctx->dscratch[i] = w;
335 for (i = 0; i < w; i++)
336 if (solver->grid[start+i*step])
337 ctx->dscratch[solver->grid[start+i*step]-1] = i;
338
339 n = m = 0;
340 furthest = w;
341 for (i = w; i >= 1; i--) {
342 if (ctx->dscratch[i-1] == w) {
343 break;
344 } else if (ctx->dscratch[i-1] < furthest) {
345 furthest = ctx->dscratch[i-1];
346 m = i;
347 n++;
348 }
349 }
350 if (clue == n+1 && furthest > 1) {
351#ifdef STANDALONE_SOLVER
352 if (solver_show_working)
353 sprintf(prefix, "%*sclue %s %d is nearly filled:\n",
354 solver_recurse_depth*4, "",
355 cluepos[c/w], c%w+1);
356 else
357 prefix[0] = '\0'; /* placate optimiser */
358#endif
359 /*
360 * We can already see an increasing sequence of the very
361 * highest numbers, of length one less than that
362 * specified in the clue. All of those numbers _must_ be
363 * part of the clue sequence, so the number right next
364 * to the clue must be the final one - i.e. it must be
365 * bigger than any of the numbers between it and m. This
366 * allows us to rule out small numbers in that square.
367 *
368 * (This is a generalisation of the obvious deduction
369 * that when you see a clue saying 1, it must be right
370 * next to the largest possible number; and similarly,
371 * when you see a clue saying 2 opposite that, it must
372 * be right next to the second-largest.)
373 */
374 j = furthest-1; /* number of small numbers we can rule out */
375 for (i = 1; i <= w && j > 0; i++) {
376 if (ctx->dscratch[i-1] < w && ctx->dscratch[i-1] >= furthest)
377 continue; /* skip this number, it's elsewhere */
378 j--;
379 if (solver->cube[cstart*w+i-1]) {
380#ifdef STANDALONE_SOLVER
381 if (solver_show_working) {
382 printf("%s%*s ruling out %d at (%d,%d)\n",
383 prefix, solver_recurse_depth*4, "",
384 i, start%w+1, start/w+1);
385 prefix[0] = '\0';
386 }
387#endif
388 solver->cube[cstart*w+i-1] = 0;
389 ret = 1;
390 }
391 }
392 }
393
394 if (ret)
395 return ret;
396
397#ifdef STANDALONE_SOLVER
398 if (solver_show_working)
399 sprintf(prefix, "%*slower bounds for clue %s %d:\n",
400 solver_recurse_depth*4, "",
401 cluepos[c/w], c%w+1);
402 else
403 prefix[0] = '\0'; /* placate optimiser */
404#endif
405
406 i = 0;
407 for (n = w; n > 0; n--) {
408 /*
409 * The largest number cannot occur in the first (clue-1)
410 * squares of the row, or else there wouldn't be space
411 * for a sufficiently long increasing sequence which it
412 * terminated. The second-largest number (not counting
413 * any that are known to be on the far side of a larger
414 * number and hence excluded from this sequence) cannot
415 * occur in the first (clue-2) squares, similarly, and
416 * so on.
417 */
418
419 if (ctx->dscratch[n-1] < w) {
420 for (m = n+1; m < w; m++)
421 if (ctx->dscratch[m] < ctx->dscratch[n-1])
422 break;
423 if (m < w)
424 continue; /* this number doesn't count */
425 }
426
427 for (j = 0; j < clue - i - 1; j++)
428 if (solver->cube[(cstart + j*cstep)*w+n-1]) {
429#ifdef STANDALONE_SOLVER
430 if (solver_show_working) {
431 int pos = start+j*step;
432 printf("%s%*s ruling out %d at (%d,%d)\n",
433 prefix, solver_recurse_depth*4, "",
434 n, pos%w+1, pos/w+1);
435 prefix[0] = '\0';
436 }
437#endif
438 solver->cube[(cstart + j*cstep)*w+n-1] = 0;
439 ret = 1;
440 }
441 i++;
442 }
443 }
444
445 if (ret)
446 return ret;
447
448 return 0;
449}
450
451static int solver_hard(struct latin_solver *solver, void *vctx)
452{
453 struct solver_ctx *ctx = (struct solver_ctx *)vctx;
454 int w = ctx->w;
455 int c, i, j, n, best, clue, start, step, ret;
456 long bitmap;
457#ifdef STANDALONE_SOLVER
458 char prefix[256];
459#endif
460
461 /*
462 * Go over every clue analysing all possibilities.
463 */
464 for (c = 0; c < 4*w; c++) {
465 clue = ctx->clues[c];
466 if (!clue)
467 continue;
468 CSTARTSTEP(start, step, c, w);
469
470 for (i = 0; i < w; i++)
471 ctx->iscratch[i] = 0;
472
473 /*
474 * Instead of a tedious physical recursion, I iterate in the
475 * scratch array through all possibilities. At any given
476 * moment, i indexes the element of the box that will next
477 * be incremented.
478 */
479 i = 0;
480 ctx->dscratch[i] = 0;
481 best = n = 0;
482 bitmap = 0;
483
484 while (1) {
485 if (i < w) {
486 /*
487 * Find the next valid value for cell i.
488 */
489 int limit = (n == clue ? best : w);
490 int pos = start + step * i;
491 for (j = ctx->dscratch[i] + 1; j <= limit; j++) {
492 if (bitmap & (1L << j))
493 continue; /* used this one already */
494 if (!solver->cube[pos*w+j-1])
495 continue; /* ruled out already */
496
497 /* Found one. */
498 break;
499 }
500
501 if (j > limit) {
502 /* No valid values left; drop back. */
503 i--;
504 if (i < 0)
505 break; /* overall iteration is finished */
506 bitmap &= ~(1L << ctx->dscratch[i]);
507 if (ctx->dscratch[i] == best) {
508 n--;
509 best = 0;
510 for (j = 0; j < i; j++)
511 if (best < ctx->dscratch[j])
512 best = ctx->dscratch[j];
513 }
514 } else {
515 /* Got a valid value; store it and move on. */
516 bitmap |= 1L << j;
517 ctx->dscratch[i++] = j;
518 if (j > best) {
519 best = j;
520 n++;
521 }
522 ctx->dscratch[i] = 0;
523 }
524 } else {
525 if (n == clue) {
526 for (j = 0; j < w; j++)
527 ctx->iscratch[j] |= 1L << ctx->dscratch[j];
528 }
529 i--;
530 bitmap &= ~(1L << ctx->dscratch[i]);
531 if (ctx->dscratch[i] == best) {
532 n--;
533 best = 0;
534 for (j = 0; j < i; j++)
535 if (best < ctx->dscratch[j])
536 best = ctx->dscratch[j];
537 }
538 }
539 }
540
541#ifdef STANDALONE_SOLVER
542 if (solver_show_working)
543 sprintf(prefix, "%*sexhaustive analysis of clue %s %d:\n",
544 solver_recurse_depth*4, "",
545 cluepos[c/w], c%w+1);
546 else
547 prefix[0] = '\0'; /* placate optimiser */
548#endif
549
550 ret = 0;
551
552 for (i = 0; i < w; i++) {
553 int pos = start + step * i;
554 for (j = 1; j <= w; j++) {
555 if (solver->cube[pos*w+j-1] &&
556 !(ctx->iscratch[i] & (1L << j))) {
557#ifdef STANDALONE_SOLVER
558 if (solver_show_working) {
559 printf("%s%*s ruling out %d at (%d,%d)\n",
560 prefix, solver_recurse_depth*4, "",
561 j, pos/w+1, pos%w+1);
562 prefix[0] = '\0';
563 }
564#endif
565 solver->cube[pos*w+j-1] = 0;
566 ret = 1;
567 }
568 }
569
570 /*
571 * Once we find one clue we can do something with in
572 * this way, revert to trying easier deductions, so as
573 * not to generate solver diagnostics that make the
574 * problem look harder than it is.
575 */
576 if (ret)
577 return ret;
578 }
579 }
580
581 return 0;
582}
583
584#define SOLVER(upper,title,func,lower) func,
585static usersolver_t const towers_solvers[] = { DIFFLIST(SOLVER) };
586
587static bool towers_valid(struct latin_solver *solver, void *vctx)
588{
589 struct solver_ctx *ctx = (struct solver_ctx *)vctx;
590 int w = ctx->w;
591 int c, i, n, best, clue, start, step;
592 for (c = 0; c < 4*w; c++) {
593 clue = ctx->clues[c];
594 if (!clue)
595 continue;
596
597 STARTSTEP(start, step, c, w);
598 n = best = 0;
599 for (i = 0; i < w; i++) {
600 if (solver->grid[start+i*step] > best) {
601 best = solver->grid[start+i*step];
602 n++;
603 }
604 }
605
606 if (n != clue) {
607#ifdef STANDALONE_SOLVER
608 if (solver_show_working)
609 printf("%*sclue %s %d is violated\n",
610 solver_recurse_depth*4, "",
611 cluepos[c/w], c%w+1);
612#endif
613 return false;
614 }
615 }
616 return true;
617}
618
619static int solver(int w, int *clues, digit *soln, int maxdiff)
620{
621 int ret;
622 struct solver_ctx ctx;
623
624 ctx.w = w;
625 ctx.diff = maxdiff;
626 ctx.clues = clues;
627 ctx.started = false;
628 ctx.iscratch = snewn(w, long);
629 ctx.dscratch = snewn(w+1, int);
630
631 ret = latin_solver(soln, w, maxdiff,
632 DIFF_EASY, DIFF_HARD, DIFF_EXTREME,
633 DIFF_EXTREME, DIFF_UNREASONABLE,
634 towers_solvers, towers_valid, &ctx, NULL, NULL);
635
636 sfree(ctx.iscratch);
637 sfree(ctx.dscratch);
638
639 return ret;
640}
641
642/* ----------------------------------------------------------------------
643 * Grid generation.
644 */
645
646static char *new_game_desc(const game_params *params, random_state *rs,
647 char **aux, bool interactive)
648{
649 int w = params->w, a = w*w;
650 digit *grid, *soln, *soln2;
651 int *clues, *order;
652 int i, ret;
653 int diff = params->diff;
654 char *desc, *p;
655
656 /*
657 * Difficulty exceptions: some combinations of size and
658 * difficulty cannot be satisfied, because all puzzles of at
659 * most that difficulty are actually even easier.
660 *
661 * Remember to re-test this whenever a change is made to the
662 * solver logic!
663 *
664 * I tested it using the following shell command:
665
666for d in e h x u; do
667 for i in {3..9}; do
668 echo -n "./towers --generate 1 ${i}d${d}: "
669 perl -e 'alarm 30; exec @ARGV' ./towers --generate 1 ${i}d${d} >/dev/null \
670 && echo ok
671 done
672done
673
674 * Of course, it's better to do that after taking the exceptions
675 * _out_, so as to detect exceptions that should be removed as
676 * well as those which should be added.
677 */
678 if (diff > DIFF_HARD && w <= 3)
679 diff = DIFF_HARD;
680
681 grid = NULL;
682 clues = snewn(4*w, int);
683 soln = snewn(a, digit);
684 soln2 = snewn(a, digit);
685 order = snewn(max(4*w,a), int);
686
687 while (1) {
688 /*
689 * Construct a latin square to be the solution.
690 */
691 sfree(grid);
692 grid = latin_generate(w, rs);
693
694 /*
695 * Fill in the clues.
696 */
697 for (i = 0; i < 4*w; i++) {
698 int start, step, j, k, best;
699 STARTSTEP(start, step, i, w);
700 k = best = 0;
701 for (j = 0; j < w; j++) {
702 if (grid[start+j*step] > best) {
703 best = grid[start+j*step];
704 k++;
705 }
706 }
707 clues[i] = k;
708 }
709
710 /*
711 * Remove the grid numbers and then the clues, one by one,
712 * for as long as the game remains soluble at the given
713 * difficulty.
714 */
715 memcpy(soln, grid, a);
716
717 if (diff == DIFF_EASY && w <= 5) {
718 /*
719 * Special case: for Easy-mode grids that are small
720 * enough, it's nice to be able to find completely empty
721 * grids.
722 */
723 memset(soln2, 0, a);
724 ret = solver(w, clues, soln2, diff);
725 if (ret > diff)
726 continue;
727 }
728
729 for (i = 0; i < a; i++)
730 order[i] = i;
731 shuffle(order, a, sizeof(*order), rs);
732 for (i = 0; i < a; i++) {
733 int j = order[i];
734
735 memcpy(soln2, grid, a);
736 soln2[j] = 0;
737 ret = solver(w, clues, soln2, diff);
738 if (ret <= diff)
739 grid[j] = 0;
740 }
741
742 if (diff > DIFF_EASY) { /* leave all clues on Easy mode */
743 for (i = 0; i < 4*w; i++)
744 order[i] = i;
745 shuffle(order, 4*w, sizeof(*order), rs);
746 for (i = 0; i < 4*w; i++) {
747 int j = order[i];
748 int clue = clues[j];
749
750 memcpy(soln2, grid, a);
751 clues[j] = 0;
752 ret = solver(w, clues, soln2, diff);
753 if (ret > diff)
754 clues[j] = clue;
755 }
756 }
757
758 /*
759 * See if the game can be solved at the specified difficulty
760 * level, but not at the one below.
761 */
762 memcpy(soln2, grid, a);
763 ret = solver(w, clues, soln2, diff);
764 if (ret != diff)
765 continue; /* go round again */
766
767 /*
768 * We've got a usable puzzle!
769 */
770 break;
771 }
772
773 /*
774 * Encode the puzzle description.
775 */
776 desc = snewn(40*a, char);
777 p = desc;
778 for (i = 0; i < 4*w; i++) {
779 if (i)
780 *p++ = '/';
781 if (clues[i])
782 p += sprintf(p, "%d", clues[i]);
783 }
784 for (i = 0; i < a; i++)
785 if (grid[i])
786 break;
787 if (i < a) {
788 int run = 0;
789
790 *p++ = ',';
791
792 for (i = 0; i <= a; i++) {
793 int n = (i < a ? grid[i] : -1);
794
795 if (!n)
796 run++;
797 else {
798 if (run) {
799 while (run > 0) {
800 int thisrun = min(run, 26);
801 *p++ = thisrun - 1 + 'a';
802 run -= thisrun;
803 }
804 } else {
805 /*
806 * If there's a number in the very top left or
807 * bottom right, there's no point putting an
808 * unnecessary _ before or after it.
809 */
810 if (i > 0 && n > 0)
811 *p++ = '_';
812 }
813 if (n > 0)
814 p += sprintf(p, "%d", n);
815 run = 0;
816 }
817 }
818 }
819 *p++ = '\0';
820 desc = sresize(desc, p - desc, char);
821
822 /*
823 * Encode the solution.
824 */
825 *aux = snewn(a+2, char);
826 (*aux)[0] = 'S';
827 for (i = 0; i < a; i++)
828 (*aux)[i+1] = '0' + soln[i];
829 (*aux)[a+1] = '\0';
830
831 sfree(grid);
832 sfree(clues);
833 sfree(soln);
834 sfree(soln2);
835 sfree(order);
836
837 return desc;
838}
839
840/* ----------------------------------------------------------------------
841 * Gameplay.
842 */
843
844static const char *validate_desc(const game_params *params, const char *desc)
845{
846 int w = params->w, a = w*w;
847 const char *p = desc;
848 int i, clue;
849
850 /*
851 * Verify that the right number of clues are given, and that
852 * they're in range.
853 */
854 for (i = 0; i < 4*w; i++) {
855 if (!*p)
856 return "Too few clues for grid size";
857
858 if (i > 0) {
859 if (*p != '/')
860 return "Expected commas between clues";
861 p++;
862 }
863
864 if (isdigit((unsigned char)*p)) {
865 clue = atoi(p);
866 while (*p && isdigit((unsigned char)*p)) p++;
867
868 if (clue <= 0 || clue > w)
869 return "Clue number out of range";
870 }
871 }
872 if (*p == '/')
873 return "Too many clues for grid size";
874
875 if (*p == ',') {
876 /*
877 * Verify that the right amount of grid data is given, and
878 * that any grid elements provided are in range.
879 */
880 int squares = 0;
881
882 p++;
883 while (*p) {
884 int c = *p++;
885 if (c >= 'a' && c <= 'z') {
886 squares += c - 'a' + 1;
887 } else if (c == '_') {
888 /* do nothing */;
889 } else if (c > '0' && c <= '9') {
890 int val = atoi(p-1);
891 if (val < 1 || val > w)
892 return "Out-of-range number in grid description";
893 squares++;
894 while (*p && isdigit((unsigned char)*p)) p++;
895 } else
896 return "Invalid character in game description";
897 }
898
899 if (squares < a)
900 return "Not enough data to fill grid";
901
902 if (squares > a)
903 return "Too much data to fit in grid";
904 }
905
906 if (*p) return "Rubbish at end of game description";
907 return NULL;
908}
909
910static key_label *game_request_keys(const game_params *params, int *nkeys)
911{
912 int i;
913 int w = params->w;
914 key_label *keys = snewn(w+1, key_label);
915 *nkeys = w + 1;
916
917 for (i = 0; i < w; i++) {
918 if (i<9) keys[i].button = '1' + i;
919 else keys[i].button = 'a' + i - 9;
920
921 keys[i].label = NULL;
922 }
923 keys[w].button = '\b';
924 keys[w].label = NULL;
925
926 return keys;
927}
928
929static game_state *new_game(midend *me, const game_params *params,
930 const char *desc)
931{
932 int w = params->w, a = w*w;
933 game_state *state = snew(game_state);
934 const char *p = desc;
935 int i;
936
937 state->par = *params; /* structure copy */
938 state->clues = snew(struct clues);
939 state->clues->refcount = 1;
940 state->clues->w = w;
941 state->clues->clues = snewn(4*w, int);
942 state->clues->immutable = snewn(a, digit);
943 state->grid = snewn(a, digit);
944 state->clues_done = snewn(4*w, bool);
945 state->pencil = snewn(a, int);
946
947 for (i = 0; i < a; i++) {
948 state->grid[i] = 0;
949 state->pencil[i] = 0;
950 }
951
952 memset(state->clues->immutable, 0, a);
953 memset(state->clues_done, 0, 4*w*sizeof(bool));
954
955 for (i = 0; i < 4*w; i++) {
956 if (i > 0) {
957 assert(*p == '/');
958 p++;
959 }
960 if (*p && isdigit((unsigned char)*p)) {
961 state->clues->clues[i] = atoi(p);
962 while (*p && isdigit((unsigned char)*p)) p++;
963 } else
964 state->clues->clues[i] = 0;
965 }
966
967 if (*p == ',') {
968 int pos = 0;
969 p++;
970 while (*p) {
971 int c = *p++;
972 if (c >= 'a' && c <= 'z') {
973 pos += c - 'a' + 1;
974 } else if (c == '_') {
975 /* do nothing */;
976 } else if (c > '0' && c <= '9') {
977 int val = atoi(p-1);
978 assert(val >= 1 && val <= w);
979 assert(pos < a);
980 state->grid[pos] = state->clues->immutable[pos] = val;
981 pos++;
982 while (*p && isdigit((unsigned char)*p)) p++;
983 } else
984 assert(!"Corrupt game description");
985 }
986 assert(pos == a);
987 }
988 assert(!*p);
989
990 state->completed = false;
991 state->cheated = false;
992
993 return state;
994}
995
996static game_state *dup_game(const game_state *state)
997{
998 int w = state->par.w, a = w*w;
999 game_state *ret = snew(game_state);
1000
1001 ret->par = state->par; /* structure copy */
1002
1003 ret->clues = state->clues;
1004 ret->clues->refcount++;
1005
1006 ret->grid = snewn(a, digit);
1007 ret->pencil = snewn(a, int);
1008 ret->clues_done = snewn(4*w, bool);
1009 memcpy(ret->grid, state->grid, a*sizeof(digit));
1010 memcpy(ret->pencil, state->pencil, a*sizeof(int));
1011 memcpy(ret->clues_done, state->clues_done, 4*w*sizeof(bool));
1012
1013 ret->completed = state->completed;
1014 ret->cheated = state->cheated;
1015
1016 return ret;
1017}
1018
1019static void free_game(game_state *state)
1020{
1021 sfree(state->grid);
1022 sfree(state->pencil);
1023 sfree(state->clues_done);
1024 if (--state->clues->refcount <= 0) {
1025 sfree(state->clues->immutable);
1026 sfree(state->clues->clues);
1027 sfree(state->clues);
1028 }
1029 sfree(state);
1030}
1031
1032static char *solve_game(const game_state *state, const game_state *currstate,
1033 const char *aux, const char **error)
1034{
1035 int w = state->par.w, a = w*w;
1036 int i, ret;
1037 digit *soln;
1038 char *out;
1039
1040 if (aux)
1041 return dupstr(aux);
1042
1043 soln = snewn(a, digit);
1044 memcpy(soln, state->clues->immutable, a);
1045
1046 ret = solver(w, state->clues->clues, soln, DIFFCOUNT-1);
1047
1048 if (ret == diff_impossible) {
1049 *error = "No solution exists for this puzzle";
1050 out = NULL;
1051 } else if (ret == diff_ambiguous) {
1052 *error = "Multiple solutions exist for this puzzle";
1053 out = NULL;
1054 } else {
1055 out = snewn(a+2, char);
1056 out[0] = 'S';
1057 for (i = 0; i < a; i++)
1058 out[i+1] = '0' + soln[i];
1059 out[a+1] = '\0';
1060 }
1061
1062 sfree(soln);
1063 return out;
1064}
1065
1066static bool game_can_format_as_text_now(const game_params *params)
1067{
1068 return true;
1069}
1070
1071static char *game_text_format(const game_state *state)
1072{
1073 int w = state->par.w /* , a = w*w */;
1074 char *ret;
1075 char *p;
1076 int x, y;
1077 int total;
1078
1079 /*
1080 * We have:
1081 * - a top clue row, consisting of three spaces, then w clue
1082 * digits with spaces between (total 2*w+3 chars including
1083 * newline)
1084 * - a blank line (one newline)
1085 * - w main rows, consisting of a left clue digit, two spaces,
1086 * w grid digits with spaces between, two spaces and a right
1087 * clue digit (total 2*w+6 chars each including newline)
1088 * - a blank line (one newline)
1089 * - a bottom clue row (same as top clue row)
1090 * - terminating NUL.
1091 *
1092 * Total size is therefore 2*(2*w+3) + 2 + w*(2*w+6) + 1
1093 * = 2w^2+10w+9.
1094 */
1095 total = 2*w*w + 10*w + 9;
1096 ret = snewn(total, char);
1097 p = ret;
1098
1099 /* Top clue row. */
1100 *p++ = ' '; *p++ = ' ';
1101 for (x = 0; x < w; x++) {
1102 *p++ = ' ';
1103 *p++ = (state->clues->clues[x] ? '0' + state->clues->clues[x] : ' ');
1104 }
1105 *p++ = '\n';
1106
1107 /* Blank line. */
1108 *p++ = '\n';
1109
1110 /* Main grid. */
1111 for (y = 0; y < w; y++) {
1112 *p++ = (state->clues->clues[y+2*w] ? '0' + state->clues->clues[y+2*w] :
1113 ' ');
1114 *p++ = ' ';
1115 for (x = 0; x < w; x++) {
1116 *p++ = ' ';
1117 *p++ = (state->grid[y*w+x] ? '0' + state->grid[y*w+x] : ' ');
1118 }
1119 *p++ = ' '; *p++ = ' ';
1120 *p++ = (state->clues->clues[y+3*w] ? '0' + state->clues->clues[y+3*w] :
1121 ' ');
1122 *p++ = '\n';
1123 }
1124
1125 /* Blank line. */
1126 *p++ = '\n';
1127
1128 /* Bottom clue row. */
1129 *p++ = ' '; *p++ = ' ';
1130 for (x = 0; x < w; x++) {
1131 *p++ = ' ';
1132 *p++ = (state->clues->clues[x+w] ? '0' + state->clues->clues[x+w] :
1133 ' ');
1134 }
1135 *p++ = '\n';
1136
1137 *p++ = '\0';
1138 assert(p == ret + total);
1139
1140 return ret;
1141}
1142
1143struct game_ui {
1144 /*
1145 * These are the coordinates of the currently highlighted
1146 * square on the grid, if hshow = 1.
1147 */
1148 int hx, hy;
1149 /*
1150 * This indicates whether the current highlight is a
1151 * pencil-mark one or a real one.
1152 */
1153 bool hpencil;
1154 /*
1155 * This indicates whether or not we're showing the highlight
1156 * (used to be hx = hy = -1); important so that when we're
1157 * using the cursor keys it doesn't keep coming back at a
1158 * fixed position. When hshow = 1, pressing a valid number
1159 * or letter key or Space will enter that number or letter in the grid.
1160 */
1161 bool hshow;
1162 /*
1163 * This indicates whether we're using the highlight as a cursor;
1164 * it means that it doesn't vanish on a keypress, and that it is
1165 * allowed on immutable squares.
1166 */
1167 bool hcursor;
1168
1169 /*
1170 * User preference option which can be set to FALSE to disable the
1171 * 3D graphical style, and instead just display the puzzle as if
1172 * it was a Sudoku variant, i.e. each square just has a digit in
1173 * it.
1174 *
1175 * I was initially a bit uncertain about whether the 3D style
1176 * would be the right thing, on the basis that it uses up space in
1177 * the cells and makes it hard to use many pencil marks. Actually
1178 * nobody seems to have complained, but having put in the option
1179 * while I was still being uncertain, it seems silly not to leave
1180 * it in just in case.
1181 */
1182 int three_d;
1183
1184 /*
1185 * User preference option: if the user right-clicks in a square
1186 * and presses a number key to add/remove a pencil mark, do we
1187 * hide the mouse highlight again afterwards?
1188 *
1189 * Historically our answer was yes. The Android port prefers no.
1190 * There are advantages both ways, depending how much you dislike
1191 * the highlight cluttering your view. So it's a preference.
1192 */
1193 bool pencil_keep_highlight;
1194};
1195
1196static void legacy_prefs_override(struct game_ui *ui_out)
1197{
1198 static bool initialised = false;
1199 static int three_d = -1;
1200
1201 if (!initialised) {
1202 initialised = true;
1203 three_d = getenv_bool("TOWERS_2D", -1);
1204 }
1205
1206 if (three_d != -1)
1207 ui_out->three_d = three_d;
1208}
1209
1210static game_ui *new_ui(const game_state *state)
1211{
1212 game_ui *ui = snew(game_ui);
1213
1214 ui->hx = ui->hy = 0;
1215 ui->hpencil = false;
1216 ui->hshow = ui->hcursor = getenv_bool("PUZZLES_SHOW_CURSOR", false);
1217
1218 ui->three_d = true;
1219 ui->pencil_keep_highlight = false;
1220 legacy_prefs_override(ui);
1221
1222 return ui;
1223}
1224
1225static void free_ui(game_ui *ui)
1226{
1227 sfree(ui);
1228}
1229
1230static config_item *get_prefs(game_ui *ui)
1231{
1232 config_item *ret;
1233
1234 ret = snewn(N_PREF_ITEMS+1, config_item);
1235
1236 ret[PREF_PENCIL_KEEP_HIGHLIGHT].name =
1237 "Keep mouse highlight after changing a pencil mark";
1238 ret[PREF_PENCIL_KEEP_HIGHLIGHT].kw = "pencil-keep-highlight";
1239 ret[PREF_PENCIL_KEEP_HIGHLIGHT].type = C_BOOLEAN;
1240 ret[PREF_PENCIL_KEEP_HIGHLIGHT].u.boolean.bval = ui->pencil_keep_highlight;
1241
1242 ret[PREF_APPEARANCE].name = "Puzzle appearance";
1243 ret[PREF_APPEARANCE].kw = "appearance";
1244 ret[PREF_APPEARANCE].type = C_CHOICES;
1245 ret[PREF_APPEARANCE].u.choices.choicenames = ":2D:3D";
1246 ret[PREF_APPEARANCE].u.choices.choicekws = ":2d:3d";
1247 ret[PREF_APPEARANCE].u.choices.selected = ui->three_d;
1248
1249 ret[N_PREF_ITEMS].name = NULL;
1250 ret[N_PREF_ITEMS].type = C_END;
1251
1252 return ret;
1253}
1254
1255static void set_prefs(game_ui *ui, const config_item *cfg)
1256{
1257 ui->pencil_keep_highlight = cfg[PREF_PENCIL_KEEP_HIGHLIGHT].u.boolean.bval;
1258 ui->three_d = cfg[PREF_APPEARANCE].u.choices.selected;
1259}
1260
1261static void game_changed_state(game_ui *ui, const game_state *oldstate,
1262 const game_state *newstate)
1263{
1264 int w = newstate->par.w;
1265 /*
1266 * We prevent pencil-mode highlighting of a filled square, unless
1267 * we're using the cursor keys. So if the user has just filled in
1268 * a square which we had a pencil-mode highlight in (by Undo, or
1269 * by Redo, or by Solve), then we cancel the highlight.
1270 */
1271 if (ui->hshow && ui->hpencil && !ui->hcursor &&
1272 newstate->grid[ui->hy * w + ui->hx] != 0) {
1273 ui->hshow = false;
1274 }
1275}
1276
1277static const char *current_key_label(const game_ui *ui,
1278 const game_state *state, int button)
1279{
1280 if (ui->hshow && (button == CURSOR_SELECT))
1281 return ui->hpencil ? "Ink" : "Pencil";
1282 return "";
1283}
1284
1285#define PREFERRED_TILESIZE 48
1286#define TILESIZE (ds->tilesize)
1287#define BORDER (TILESIZE * 9 / 8)
1288#define COORD(x) ((x)*TILESIZE + BORDER)
1289#define FROMCOORD(x) (((x)+(TILESIZE-BORDER)) / TILESIZE - 1)
1290
1291/* These always return positive values, though y offsets are actually -ve */
1292#define X_3D_DISP(height, w) ((height) * TILESIZE / (8 * (w)))
1293#define Y_3D_DISP(height, w) ((height) * TILESIZE / (4 * (w)))
1294
1295#define FLASH_TIME 0.4F
1296
1297#define DF_PENCIL_SHIFT 16
1298#define DF_CLUE_DONE 0x10000
1299#define DF_ERROR 0x8000
1300#define DF_HIGHLIGHT 0x4000
1301#define DF_HIGHLIGHT_PENCIL 0x2000
1302#define DF_IMMUTABLE 0x1000
1303#define DF_PLAYAREA 0x0800
1304#define DF_DIGIT_MASK 0x00FF
1305
1306struct game_drawstate {
1307 int tilesize;
1308 long *tiles; /* (w+2)*(w+2) temp space */
1309 long *drawn; /* (w+2)*(w+2)*4: current drawn data */
1310 bool *errtmp;
1311};
1312
1313static bool check_errors(const game_state *state, bool *errors)
1314{
1315 int w = state->par.w /*, a = w*w */;
1316 int W = w+2, A = W*W; /* the errors array is (w+2) square */
1317 int *clues = state->clues->clues;
1318 digit *grid = state->grid;
1319 int i, x, y;
1320 bool errs = false;
1321 int tmp[32];
1322
1323 assert(w < lenof(tmp));
1324
1325 if (errors)
1326 for (i = 0; i < A; i++)
1327 errors[i] = false;
1328
1329 for (y = 0; y < w; y++) {
1330 unsigned long mask = 0, errmask = 0;
1331 for (x = 0; x < w; x++) {
1332 unsigned long bit = 1UL << grid[y*w+x];
1333 errmask |= (mask & bit);
1334 mask |= bit;
1335 }
1336
1337 if (mask != (1L << (w+1)) - (1L << 1)) {
1338 errs = true;
1339 errmask &= ~1UL;
1340 if (errors) {
1341 for (x = 0; x < w; x++)
1342 if (errmask & (1UL << grid[y*w+x]))
1343 errors[(y+1)*W+(x+1)] = true;
1344 }
1345 }
1346 }
1347
1348 for (x = 0; x < w; x++) {
1349 unsigned long mask = 0, errmask = 0;
1350 for (y = 0; y < w; y++) {
1351 unsigned long bit = 1UL << grid[y*w+x];
1352 errmask |= (mask & bit);
1353 mask |= bit;
1354 }
1355
1356 if (mask != (1 << (w+1)) - (1 << 1)) {
1357 errs = true;
1358 errmask &= ~1UL;
1359 if (errors) {
1360 for (y = 0; y < w; y++)
1361 if (errmask & (1UL << grid[y*w+x]))
1362 errors[(y+1)*W+(x+1)] = true;
1363 }
1364 }
1365 }
1366
1367 for (i = 0; i < 4*w; i++) {
1368 int start, step, j, n, best;
1369 STARTSTEP(start, step, i, w);
1370
1371 if (!clues[i])
1372 continue;
1373
1374 best = n = 0;
1375 for (j = 0; j < w; j++) {
1376 int number = grid[start+j*step];
1377 if (!number)
1378 break; /* can't tell what happens next */
1379 if (number > best) {
1380 best = number;
1381 n++;
1382 }
1383 }
1384
1385 if (n > clues[i] || (best == w && n < clues[i]) ||
1386 (best < w && n == clues[i])) {
1387 if (errors) {
1388 int x, y;
1389 CLUEPOS(x, y, i, w);
1390 errors[(y+1)*W+(x+1)] = true;
1391 }
1392 errs = true;
1393 }
1394 }
1395
1396 return errs;
1397}
1398
1399static int clue_index(const game_state *state, int x, int y)
1400{
1401 int w = state->par.w;
1402
1403 if (x == -1 || x == w)
1404 return w * (x == -1 ? 2 : 3) + y;
1405 else if (y == -1 || y == w)
1406 return (y == -1 ? 0 : w) + x;
1407
1408 return -1;
1409}
1410
1411static bool is_clue(const game_state *state, int x, int y)
1412{
1413 int w = state->par.w;
1414
1415 if (((x == -1 || x == w) && y >= 0 && y < w) ||
1416 ((y == -1 || y == w) && x >= 0 && x < w))
1417 {
1418 if (state->clues->clues[clue_index(state, x, y)] & DF_DIGIT_MASK)
1419 return true;
1420 }
1421
1422 return false;
1423}
1424
1425static char *interpret_move(const game_state *state, game_ui *ui,
1426 const game_drawstate *ds,
1427 int x, int y, int button)
1428{
1429 int w = state->par.w;
1430 bool shift_or_control = button & (MOD_SHFT | MOD_CTRL);
1431 int tx, ty;
1432 char buf[80];
1433
1434 button = STRIP_BUTTON_MODIFIERS(button);
1435
1436 tx = FROMCOORD(x);
1437 ty = FROMCOORD(y);
1438
1439 if (ui->three_d) {
1440 /*
1441 * In 3D mode, just locating the mouse click in the natural
1442 * square grid may not be sufficient to tell which tower the
1443 * user clicked on. Investigate the _tops_ of the nearby
1444 * towers to see if a click on one grid square was actually
1445 * a click on a tower protruding into that region from
1446 * another.
1447 */
1448 int dx, dy;
1449 for (dy = 0; dy <= 1; dy++)
1450 for (dx = 0; dx >= -1; dx--) {
1451 int cx = tx + dx, cy = ty + dy;
1452 if (cx >= 0 && cx < w && cy >= 0 && cy < w) {
1453 int height = state->grid[cy*w+cx];
1454 int bx = COORD(cx), by = COORD(cy);
1455 int ox = bx + X_3D_DISP(height, w);
1456 int oy = by - Y_3D_DISP(height, w);
1457 if (/* on top face? */
1458 (x - ox >= 0 && x - ox < TILESIZE &&
1459 y - oy >= 0 && y - oy < TILESIZE) ||
1460 /* in triangle between top-left corners? */
1461 (ox > bx && x >= bx && x <= ox && y <= by &&
1462 (by-y) * (ox-bx) <= (by-oy) * (x-bx)) ||
1463 /* in triangle between bottom-right corners? */
1464 (ox > bx && x >= bx+TILESIZE && x <= ox+TILESIZE &&
1465 y >= oy+TILESIZE &&
1466 (by-y+TILESIZE)*(ox-bx) >= (by-oy)*(x-bx-TILESIZE))) {
1467 tx = cx;
1468 ty = cy;
1469 }
1470 }
1471 }
1472 }
1473
1474 if (tx >= 0 && tx < w && ty >= 0 && ty < w) {
1475 if (button == LEFT_BUTTON) {
1476 if (tx == ui->hx && ty == ui->hy &&
1477 ui->hshow && !ui->hpencil) {
1478 ui->hshow = false;
1479 } else {
1480 ui->hx = tx;
1481 ui->hy = ty;
1482 ui->hshow = !state->clues->immutable[ty*w+tx];
1483 ui->hpencil = false;
1484 }
1485 ui->hcursor = false;
1486 return MOVE_UI_UPDATE;
1487 }
1488 if (button == RIGHT_BUTTON) {
1489 /*
1490 * Pencil-mode highlighting for non filled squares.
1491 */
1492 if (state->grid[ty*w+tx] == 0) {
1493 if (tx == ui->hx && ty == ui->hy &&
1494 ui->hshow && ui->hpencil) {
1495 ui->hshow = false;
1496 } else {
1497 ui->hpencil = true;
1498 ui->hx = tx;
1499 ui->hy = ty;
1500 ui->hshow = true;
1501 }
1502 } else {
1503 ui->hshow = false;
1504 }
1505 ui->hcursor = false;
1506 return MOVE_UI_UPDATE;
1507 }
1508 } else if (button == LEFT_BUTTON) {
1509 if (is_clue(state, tx, ty)) {
1510 sprintf(buf, "%c%d,%d", 'D', tx, ty);
1511 return dupstr(buf);
1512 }
1513 }
1514 if (IS_CURSOR_MOVE(button)) {
1515 if (shift_or_control) {
1516 int x = ui->hx, y = ui->hy;
1517 switch (button) {
1518 case CURSOR_LEFT: x = -1; break;
1519 case CURSOR_RIGHT: x = w; break;
1520 case CURSOR_UP: y = -1; break;
1521 case CURSOR_DOWN: y = w; break;
1522 }
1523 if (is_clue(state, x, y)) {
1524 sprintf(buf, "%c%d,%d", 'D', x, y);
1525 return dupstr(buf);
1526 }
1527 return NULL;
1528 }
1529 ui->hcursor = true;
1530 return move_cursor(button, &ui->hx, &ui->hy, w, w, false, &ui->hshow);
1531 }
1532 if (ui->hshow &&
1533 (button == CURSOR_SELECT)) {
1534 ui->hpencil = !ui->hpencil;
1535 ui->hcursor = true;
1536 return MOVE_UI_UPDATE;
1537 }
1538
1539 if (ui->hshow &&
1540 ((button >= '0' && button <= '9' && button - '0' <= w) ||
1541 button == CURSOR_SELECT2 || button == '\b')) {
1542 int n = button - '0';
1543 if (button == CURSOR_SELECT2 || button == '\b')
1544 n = 0;
1545
1546 /*
1547 * Can't make pencil marks in a filled square. This can only
1548 * become highlighted if we're using cursor keys.
1549 */
1550 if (ui->hpencil && state->grid[ui->hy*w+ui->hx])
1551 return NULL;
1552
1553 /*
1554 * Can't do anything to an immutable square.
1555 */
1556 if (state->clues->immutable[ui->hy*w+ui->hx])
1557 return NULL;
1558
1559 /*
1560 * If you ask to fill a square with what it already contains,
1561 * or blank it when it's already empty, that has no effect...
1562 */
1563 if ((!ui->hpencil || n == 0) && state->grid[ui->hy*w+ui->hx] == n &&
1564 state->pencil[ui->hy*w+ui->hx] == 0) {
1565 /* ... expect to remove the cursor in mouse mode. */
1566 if (!ui->hcursor) {
1567 ui->hshow = false;
1568 return MOVE_UI_UPDATE;
1569 }
1570 return NULL;
1571 }
1572
1573 sprintf(buf, "%c%d,%d,%d",
1574 (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n);
1575
1576 /*
1577 * Hide the highlight after a keypress, if it was mouse-
1578 * generated. Also, don't hide it if this move has changed
1579 * pencil marks and the user preference says not to hide the
1580 * highlight in that situation.
1581 */
1582 if (!ui->hcursor && !(ui->hpencil && ui->pencil_keep_highlight))
1583 ui->hshow = false;
1584
1585 return dupstr(buf);
1586 }
1587
1588 if (button == 'M' || button == 'm')
1589 return dupstr("M");
1590
1591 return NULL;
1592}
1593
1594static game_state *execute_move(const game_state *from, const char *move)
1595{
1596 int w = from->par.w, a = w*w;
1597 game_state *ret = dup_game(from);
1598 int x, y, i, n;
1599
1600 if (move[0] == 'S') {
1601 ret->completed = ret->cheated = true;
1602
1603 for (i = 0; i < a; i++) {
1604 if (move[i+1] < '1' || move[i+1] > '0'+w)
1605 goto badmove;
1606 ret->grid[i] = move[i+1] - '0';
1607 ret->pencil[i] = 0;
1608 }
1609
1610 if (move[a+1] != '\0')
1611 goto badmove;
1612
1613 return ret;
1614 } else if ((move[0] == 'P' || move[0] == 'R') &&
1615 sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 &&
1616 x >= 0 && x < w && y >= 0 && y < w && n >= 0 && n <= w) {
1617 if (from->clues->immutable[y*w+x])
1618 goto badmove;
1619
1620 if (move[0] == 'P' && n > 0) {
1621 ret->pencil[y*w+x] ^= 1L << n;
1622 } else {
1623 ret->grid[y*w+x] = n;
1624 ret->pencil[y*w+x] = 0;
1625
1626 if (!ret->completed && !check_errors(ret, NULL))
1627 ret->completed = true;
1628 }
1629 return ret;
1630 } else if (move[0] == 'M') {
1631 /*
1632 * Fill in absolutely all pencil marks everywhere. (I
1633 * wouldn't use this for actual play, but it's a handy
1634 * starting point when following through a set of
1635 * diagnostics output by the standalone solver.)
1636 */
1637 for (i = 0; i < a; i++) {
1638 if (!ret->grid[i])
1639 ret->pencil[i] = (1L << (w+1)) - (1L << 1);
1640 }
1641 return ret;
1642 } else if (move[0] == 'D' && sscanf(move+1, "%d,%d", &x, &y) == 2 &&
1643 is_clue(from, x, y)) {
1644 int index = clue_index(from, x, y);
1645 ret->clues_done[index] = !ret->clues_done[index];
1646 return ret;
1647 }
1648
1649 badmove:
1650 /* couldn't parse move string */
1651 free_game(ret);
1652 return NULL;
1653}
1654
1655/* ----------------------------------------------------------------------
1656 * Drawing routines.
1657 */
1658
1659#define SIZE(w) ((w) * TILESIZE + 2*BORDER)
1660
1661static void game_compute_size(const game_params *params, int tilesize,
1662 const game_ui *ui, int *x, int *y)
1663{
1664 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
1665 struct { int tilesize; } ads, *ds = &ads;
1666 ads.tilesize = tilesize;
1667
1668 *x = *y = SIZE(params->w);
1669}
1670
1671static void game_set_size(drawing *dr, game_drawstate *ds,
1672 const game_params *params, int tilesize)
1673{
1674 ds->tilesize = tilesize;
1675}
1676
1677static float *game_colours(frontend *fe, int *ncolours)
1678{
1679 float *ret = snewn(3 * NCOLOURS, float);
1680
1681 frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
1682
1683 ret[COL_GRID * 3 + 0] = 0.0F;
1684 ret[COL_GRID * 3 + 1] = 0.0F;
1685 ret[COL_GRID * 3 + 2] = 0.0F;
1686
1687 ret[COL_USER * 3 + 0] = 0.0F;
1688 ret[COL_USER * 3 + 1] = 0.6F * ret[COL_BACKGROUND * 3 + 1];
1689 ret[COL_USER * 3 + 2] = 0.0F;
1690
1691 ret[COL_HIGHLIGHT * 3 + 0] = 0.78F * ret[COL_BACKGROUND * 3 + 0];
1692 ret[COL_HIGHLIGHT * 3 + 1] = 0.78F * ret[COL_BACKGROUND * 3 + 1];
1693 ret[COL_HIGHLIGHT * 3 + 2] = 0.78F * ret[COL_BACKGROUND * 3 + 2];
1694
1695 ret[COL_ERROR * 3 + 0] = 1.0F;
1696 ret[COL_ERROR * 3 + 1] = 0.0F;
1697 ret[COL_ERROR * 3 + 2] = 0.0F;
1698
1699 ret[COL_PENCIL * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0];
1700 ret[COL_PENCIL * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1];
1701 ret[COL_PENCIL * 3 + 2] = ret[COL_BACKGROUND * 3 + 2];
1702
1703 ret[COL_DONE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] / 1.5F;
1704 ret[COL_DONE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] / 1.5F;
1705 ret[COL_DONE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] / 1.5F;
1706
1707 *ncolours = NCOLOURS;
1708 return ret;
1709}
1710
1711static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1712{
1713 int w = state->par.w /*, a = w*w */;
1714 struct game_drawstate *ds = snew(struct game_drawstate);
1715 int i;
1716
1717 ds->tilesize = 0;
1718 ds->tiles = snewn((w+2)*(w+2), long);
1719 ds->drawn = snewn((w+2)*(w+2)*4, long);
1720 for (i = 0; i < (w+2)*(w+2)*4; i++)
1721 ds->drawn[i] = -1;
1722 ds->errtmp = snewn((w+2)*(w+2), bool);
1723
1724 return ds;
1725}
1726
1727static void game_free_drawstate(drawing *dr, game_drawstate *ds)
1728{
1729 sfree(ds->errtmp);
1730 sfree(ds->tiles);
1731 sfree(ds->drawn);
1732 sfree(ds);
1733}
1734
1735static void draw_tile(drawing *dr, game_drawstate *ds, const game_ui *ui,
1736 struct clues *clues, int x, int y, long tile)
1737{
1738 int w = clues->w /* , a = w*w */;
1739 int tx, ty, bg;
1740 char str[64];
1741
1742 tx = COORD(x);
1743 ty = COORD(y);
1744
1745 bg = (tile & DF_HIGHLIGHT) ? COL_HIGHLIGHT : COL_BACKGROUND;
1746
1747 /* draw tower */
1748 if (ui->three_d && (tile & DF_PLAYAREA) && (tile & DF_DIGIT_MASK)) {
1749 int coords[8];
1750 int xoff = X_3D_DISP(tile & DF_DIGIT_MASK, w);
1751 int yoff = Y_3D_DISP(tile & DF_DIGIT_MASK, w);
1752
1753 /* left face of tower */
1754 coords[0] = tx;
1755 coords[1] = ty - 1;
1756 coords[2] = tx;
1757 coords[3] = ty + TILESIZE - 1;
1758 coords[4] = coords[2] + xoff;
1759 coords[5] = coords[3] - yoff;
1760 coords[6] = coords[0] + xoff;
1761 coords[7] = coords[1] - yoff;
1762 draw_polygon(dr, coords, 4, bg, COL_GRID);
1763
1764 /* bottom face of tower */
1765 coords[0] = tx + TILESIZE;
1766 coords[1] = ty + TILESIZE - 1;
1767 coords[2] = tx;
1768 coords[3] = ty + TILESIZE - 1;
1769 coords[4] = coords[2] + xoff;
1770 coords[5] = coords[3] - yoff;
1771 coords[6] = coords[0] + xoff;
1772 coords[7] = coords[1] - yoff;
1773 draw_polygon(dr, coords, 4, bg, COL_GRID);
1774
1775 /* now offset all subsequent drawing to the top of the tower */
1776 tx += xoff;
1777 ty -= yoff;
1778 }
1779
1780 /* erase background */
1781 draw_rect(dr, tx, ty, TILESIZE, TILESIZE, bg);
1782
1783 /* pencil-mode highlight */
1784 if (tile & DF_HIGHLIGHT_PENCIL) {
1785 int coords[6];
1786 coords[0] = tx;
1787 coords[1] = ty;
1788 coords[2] = tx+TILESIZE/2;
1789 coords[3] = ty;
1790 coords[4] = tx;
1791 coords[5] = ty+TILESIZE/2;
1792 draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT);
1793 }
1794
1795 /* draw box outline */
1796 if (tile & DF_PLAYAREA) {
1797 int coords[8];
1798 coords[0] = tx;
1799 coords[1] = ty - 1;
1800 coords[2] = tx + TILESIZE;
1801 coords[3] = ty - 1;
1802 coords[4] = tx + TILESIZE;
1803 coords[5] = ty + TILESIZE - 1;
1804 coords[6] = tx;
1805 coords[7] = ty + TILESIZE - 1;
1806 draw_polygon(dr, coords, 4, -1, COL_GRID);
1807 }
1808
1809 /* new number needs drawing? */
1810 if (tile & DF_DIGIT_MASK) {
1811 int color;
1812
1813 str[1] = '\0';
1814 str[0] = (tile & DF_DIGIT_MASK) + '0';
1815
1816 if (tile & DF_ERROR)
1817 color = COL_ERROR;
1818 else if (tile & DF_CLUE_DONE)
1819 color = COL_DONE;
1820 else if (x < 0 || y < 0 || x >= w || y >= w)
1821 color = COL_GRID;
1822 else if (tile & DF_IMMUTABLE)
1823 color = COL_GRID;
1824 else
1825 color = COL_USER;
1826
1827 draw_text(dr, tx + TILESIZE/2, ty + TILESIZE/2, FONT_VARIABLE,
1828 (tile & DF_PLAYAREA ? TILESIZE/2 : TILESIZE*2/5),
1829 ALIGN_VCENTRE | ALIGN_HCENTRE, color, str);
1830 } else {
1831 int i, j, npencil;
1832 int pl, pr, pt, pb;
1833 float bestsize;
1834 int pw, ph, minph, pbest, fontsize;
1835
1836 /* Count the pencil marks required. */
1837 for (i = 1, npencil = 0; i <= w; i++)
1838 if (tile & (1L << (i + DF_PENCIL_SHIFT)))
1839 npencil++;
1840 if (npencil) {
1841
1842 minph = 2;
1843
1844 /*
1845 * Determine the bounding rectangle within which we're going
1846 * to put the pencil marks.
1847 */
1848 /* Start with the whole square, minus space for impinging towers */
1849 pl = tx + (ui->three_d ? X_3D_DISP(w,w) : 0);
1850 pr = tx + TILESIZE;
1851 pt = ty;
1852 pb = ty + TILESIZE - (ui->three_d ? Y_3D_DISP(w,w) : 0);
1853
1854 /*
1855 * We arrange our pencil marks in a grid layout, with
1856 * the number of rows and columns adjusted to allow the
1857 * maximum font size.
1858 *
1859 * So now we work out what the grid size ought to be.
1860 */
1861 bestsize = 0.0;
1862 pbest = 0;
1863 /* Minimum */
1864 for (pw = 3; pw < max(npencil,4); pw++) {
1865 float fw, fh, fs;
1866
1867 ph = (npencil + pw - 1) / pw;
1868 ph = max(ph, minph);
1869 fw = (pr - pl) / (float)pw;
1870 fh = (pb - pt) / (float)ph;
1871 fs = min(fw, fh);
1872 if (fs > bestsize) {
1873 bestsize = fs;
1874 pbest = pw;
1875 }
1876 }
1877 assert(pbest > 0);
1878 pw = pbest;
1879 ph = (npencil + pw - 1) / pw;
1880 ph = max(ph, minph);
1881
1882 /*
1883 * Now we've got our grid dimensions, work out the pixel
1884 * size of a grid element, and round it to the nearest
1885 * pixel. (We don't want rounding errors to make the
1886 * grid look uneven at low pixel sizes.)
1887 */
1888 fontsize = min((pr - pl) / pw, (pb - pt) / ph);
1889
1890 /*
1891 * Centre the resulting figure in the square.
1892 */
1893 pl = pl + (pr - pl - fontsize * pw) / 2;
1894 pt = pt + (pb - pt - fontsize * ph) / 2;
1895
1896 /*
1897 * Now actually draw the pencil marks.
1898 */
1899 for (i = 1, j = 0; i <= w; i++)
1900 if (tile & (1L << (i + DF_PENCIL_SHIFT))) {
1901 int dx = j % pw, dy = j / pw;
1902
1903 str[1] = '\0';
1904 str[0] = i + '0';
1905 draw_text(dr, pl + fontsize * (2*dx+1) / 2,
1906 pt + fontsize * (2*dy+1) / 2,
1907 FONT_VARIABLE, fontsize,
1908 ALIGN_VCENTRE | ALIGN_HCENTRE, COL_PENCIL, str);
1909 j++;
1910 }
1911 }
1912 }
1913}
1914
1915static void game_redraw(drawing *dr, game_drawstate *ds,
1916 const game_state *oldstate, const game_state *state,
1917 int dir, const game_ui *ui,
1918 float animtime, float flashtime)
1919{
1920 int w = state->par.w /*, a = w*w */;
1921 int i, x, y;
1922
1923 check_errors(state, ds->errtmp);
1924
1925 /*
1926 * Work out what data each tile should contain.
1927 */
1928 for (i = 0; i < (w+2)*(w+2); i++)
1929 ds->tiles[i] = 0; /* completely blank square */
1930 /* The clue squares... */
1931 for (i = 0; i < 4*w; i++) {
1932 long tile = state->clues->clues[i];
1933
1934 CLUEPOS(x, y, i, w);
1935
1936 if (ds->errtmp[(y+1)*(w+2)+(x+1)])
1937 tile |= DF_ERROR;
1938 else if (state->clues_done[i])
1939 tile |= DF_CLUE_DONE;
1940
1941 ds->tiles[(y+1)*(w+2)+(x+1)] = tile;
1942 }
1943 /* ... and the main grid. */
1944 for (y = 0; y < w; y++) {
1945 for (x = 0; x < w; x++) {
1946 long tile = DF_PLAYAREA;
1947
1948 if (state->grid[y*w+x])
1949 tile |= state->grid[y*w+x];
1950 else
1951 tile |= (long)state->pencil[y*w+x] << DF_PENCIL_SHIFT;
1952
1953 if (ui->hshow && ui->hx == x && ui->hy == y)
1954 tile |= (ui->hpencil ? DF_HIGHLIGHT_PENCIL : DF_HIGHLIGHT);
1955
1956 if (state->clues->immutable[y*w+x])
1957 tile |= DF_IMMUTABLE;
1958
1959 if (flashtime > 0 &&
1960 (flashtime <= FLASH_TIME/3 ||
1961 flashtime >= FLASH_TIME*2/3))
1962 tile |= DF_HIGHLIGHT; /* completion flash */
1963
1964 if (ds->errtmp[(y+1)*(w+2)+(x+1)])
1965 tile |= DF_ERROR;
1966
1967 ds->tiles[(y+1)*(w+2)+(x+1)] = tile;
1968 }
1969 }
1970
1971 /*
1972 * Now actually draw anything that needs to be changed.
1973 */
1974 for (y = 0; y < w+2; y++) {
1975 for (x = 0; x < w+2; x++) {
1976 long tl, tr, bl, br;
1977 int i = y*(w+2)+x;
1978
1979 tr = ds->tiles[y*(w+2)+x];
1980 tl = (x == 0 ? 0 : ds->tiles[y*(w+2)+(x-1)]);
1981 br = (y == w+1 ? 0 : ds->tiles[(y+1)*(w+2)+x]);
1982 bl = (x == 0 || y == w+1 ? 0 : ds->tiles[(y+1)*(w+2)+(x-1)]);
1983
1984 if (ds->drawn[i*4] != tl || ds->drawn[i*4+1] != tr ||
1985 ds->drawn[i*4+2] != bl || ds->drawn[i*4+3] != br) {
1986 clip(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE);
1987
1988 draw_tile(dr, ds, ui, state->clues, x-1, y-1, tr);
1989 if (x > 0)
1990 draw_tile(dr, ds, ui, state->clues, x-2, y-1, tl);
1991 if (y <= w)
1992 draw_tile(dr, ds, ui, state->clues, x-1, y, br);
1993 if (x > 0 && y <= w)
1994 draw_tile(dr, ds, ui, state->clues, x-2, y, bl);
1995
1996 unclip(dr);
1997 draw_update(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE);
1998
1999 ds->drawn[i*4] = tl;
2000 ds->drawn[i*4+1] = tr;
2001 ds->drawn[i*4+2] = bl;
2002 ds->drawn[i*4+3] = br;
2003 }
2004 }
2005 }
2006}
2007
2008static float game_anim_length(const game_state *oldstate,
2009 const game_state *newstate, int dir, game_ui *ui)
2010{
2011 return 0.0F;
2012}
2013
2014static float game_flash_length(const game_state *oldstate,
2015 const game_state *newstate, int dir, game_ui *ui)
2016{
2017 if (!oldstate->completed && newstate->completed &&
2018 !oldstate->cheated && !newstate->cheated)
2019 return FLASH_TIME;
2020 return 0.0F;
2021}
2022
2023static void game_get_cursor_location(const game_ui *ui,
2024 const game_drawstate *ds,
2025 const game_state *state,
2026 const game_params *params,
2027 int *x, int *y, int *w, int *h)
2028{
2029 if(ui->hshow) {
2030 *x = COORD(ui->hx);
2031 *y = COORD(ui->hy);
2032 *w = *h = TILESIZE;
2033 }
2034}
2035
2036static int game_status(const game_state *state)
2037{
2038 return state->completed ? +1 : 0;
2039}
2040
2041static void game_print_size(const game_params *params, const game_ui *ui,
2042 float *x, float *y)
2043{
2044 int pw, ph;
2045
2046 /*
2047 * We use 9mm squares by default, like Solo.
2048 */
2049 game_compute_size(params, 900, ui, &pw, &ph);
2050 *x = pw / 100.0F;
2051 *y = ph / 100.0F;
2052}
2053
2054static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
2055 int tilesize)
2056{
2057 int w = state->par.w;
2058 int ink = print_mono_colour(dr, 0);
2059 int i, x, y;
2060
2061 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2062 game_drawstate ads, *ds = &ads;
2063 game_set_size(dr, ds, NULL, tilesize);
2064
2065 /*
2066 * Border.
2067 */
2068 print_line_width(dr, 3 * TILESIZE / 40);
2069 draw_rect_outline(dr, BORDER, BORDER, w*TILESIZE, w*TILESIZE, ink);
2070
2071 /*
2072 * Main grid.
2073 */
2074 for (x = 1; x < w; x++) {
2075 print_line_width(dr, TILESIZE / 40);
2076 draw_line(dr, BORDER+x*TILESIZE, BORDER,
2077 BORDER+x*TILESIZE, BORDER+w*TILESIZE, ink);
2078 }
2079 for (y = 1; y < w; y++) {
2080 print_line_width(dr, TILESIZE / 40);
2081 draw_line(dr, BORDER, BORDER+y*TILESIZE,
2082 BORDER+w*TILESIZE, BORDER+y*TILESIZE, ink);
2083 }
2084
2085 /*
2086 * Clues.
2087 */
2088 for (i = 0; i < 4*w; i++) {
2089 char str[128];
2090
2091 if (!state->clues->clues[i])
2092 continue;
2093
2094 CLUEPOS(x, y, i, w);
2095
2096 sprintf (str, "%d", state->clues->clues[i]);
2097
2098 draw_text(dr, BORDER + x*TILESIZE + TILESIZE/2,
2099 BORDER + y*TILESIZE + TILESIZE/2,
2100 FONT_VARIABLE, TILESIZE/2,
2101 ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str);
2102 }
2103
2104 /*
2105 * Numbers for the solution, if any.
2106 */
2107 for (y = 0; y < w; y++)
2108 for (x = 0; x < w; x++)
2109 if (state->grid[y*w+x]) {
2110 char str[2];
2111 str[1] = '\0';
2112 str[0] = state->grid[y*w+x] + '0';
2113 draw_text(dr, BORDER + x*TILESIZE + TILESIZE/2,
2114 BORDER + y*TILESIZE + TILESIZE/2,
2115 FONT_VARIABLE, TILESIZE/2,
2116 ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str);
2117 }
2118}
2119
2120#ifdef COMBINED
2121#define thegame towers
2122#endif
2123
2124const struct game thegame = {
2125 "Towers", "games.towers", "towers",
2126 default_params,
2127 game_fetch_preset, NULL,
2128 decode_params,
2129 encode_params,
2130 free_params,
2131 dup_params,
2132 true, game_configure, custom_params,
2133 validate_params,
2134 new_game_desc,
2135 validate_desc,
2136 new_game,
2137 dup_game,
2138 free_game,
2139 true, solve_game,
2140 true, game_can_format_as_text_now, game_text_format,
2141 get_prefs, set_prefs,
2142 new_ui,
2143 free_ui,
2144 NULL, /* encode_ui */
2145 NULL, /* decode_ui */
2146 game_request_keys,
2147 game_changed_state,
2148 current_key_label,
2149 interpret_move,
2150 execute_move,
2151 PREFERRED_TILESIZE, game_compute_size, game_set_size,
2152 game_colours,
2153 game_new_drawstate,
2154 game_free_drawstate,
2155 game_redraw,
2156 game_anim_length,
2157 game_flash_length,
2158 game_get_cursor_location,
2159 game_status,
2160 true, false, game_print_size, game_print,
2161 false, /* wants_statusbar */
2162 false, NULL, /* timing_state */
2163 REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */
2164};
2165
2166#ifdef STANDALONE_SOLVER
2167
2168#include <stdarg.h>
2169
2170int main(int argc, char **argv)
2171{
2172 game_params *p;
2173 game_state *s;
2174 char *id = NULL, *desc;
2175 const char *err;
2176 bool grade = false;
2177 int ret, diff;
2178 bool really_show_working = false;
2179
2180 while (--argc > 0) {
2181 char *p = *++argv;
2182 if (!strcmp(p, "-v")) {
2183 really_show_working = true;
2184 } else if (!strcmp(p, "-g")) {
2185 grade = true;
2186 } else if (*p == '-') {
2187 fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
2188 return 1;
2189 } else {
2190 id = p;
2191 }
2192 }
2193
2194 if (!id) {
2195 fprintf(stderr, "usage: %s [-g | -v] <game_id>\n", argv[0]);
2196 return 1;
2197 }
2198
2199 desc = strchr(id, ':');
2200 if (!desc) {
2201 fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
2202 return 1;
2203 }
2204 *desc++ = '\0';
2205
2206 p = default_params();
2207 decode_params(p, id);
2208 err = validate_desc(p, desc);
2209 if (err) {
2210 fprintf(stderr, "%s: %s\n", argv[0], err);
2211 return 1;
2212 }
2213 s = new_game(NULL, p, desc);
2214
2215 /*
2216 * When solving an Easy puzzle, we don't want to bother the
2217 * user with Hard-level deductions. For this reason, we grade
2218 * the puzzle internally before doing anything else.
2219 */
2220 ret = -1; /* placate optimiser */
2221 solver_show_working = 0;
2222 for (diff = 0; diff < DIFFCOUNT; diff++) {
2223 memcpy(s->grid, s->clues->immutable, p->w * p->w);
2224 ret = solver(p->w, s->clues->clues, s->grid, diff);
2225 if (ret <= diff)
2226 break;
2227 }
2228
2229 if (really_show_working) {
2230 /*
2231 * Now run the solver again at the last difficulty level we
2232 * tried, but this time with diagnostics enabled.
2233 */
2234 solver_show_working = really_show_working;
2235 memcpy(s->grid, s->clues->immutable, p->w * p->w);
2236 ret = solver(p->w, s->clues->clues, s->grid,
2237 diff < DIFFCOUNT ? diff : DIFFCOUNT-1);
2238 }
2239
2240 if (diff == DIFFCOUNT) {
2241 if (grade)
2242 printf("Difficulty rating: ambiguous\n");
2243 else
2244 printf("Unable to find a unique solution\n");
2245 } else {
2246 if (grade) {
2247 if (ret == diff_impossible)
2248 printf("Difficulty rating: impossible (no solution exists)\n");
2249 else
2250 printf("Difficulty rating: %s\n", towers_diffnames[ret]);
2251 } else {
2252 if (ret != diff)
2253 printf("Puzzle is inconsistent\n");
2254 else
2255 fputs(game_text_format(s), stdout);
2256 }
2257 }
2258
2259 return 0;
2260}
2261
2262#endif
2263
2264/* vim: set shiftwidth=4 tabstop=8: */