ref: d9e39add3ace098d22d356b3852028aca7b822c5
parent: 7888d8db677e25d2401914e6aacb1be02301d15f
author: Simon Tatham <[email protected]>
date: Wed Jan 7 16:55:21 EST 2009
Standalone solver for Loopy. Bit half-hearted, since the solver doesn't have diagnostics embedded and the ASCII formatter can't print non-square puzzles anyway; but it can grade difficulty, which is what I most immediately want it for. [originally from svn r8397]
--- a/loopy.R
+++ b/loopy.R
@@ -6,6 +6,9 @@
loopy : [G] WINDOWS COMMON loopy LOOPY_EXTRA loopy.res|noicon.res
+loopysolver : [U] loopy[STANDALONE_SOLVER] LOOPY_EXTRA STANDALONE m.lib
+loopysolver : [C] loopy[STANDALONE_SOLVER] LOOPY_EXTRA STANDALONE
+
ALL += loopy[COMBINED] LOOPY_EXTRA
!begin gtk
--- a/loopy.c
+++ b/loopy.c
@@ -3635,3 +3635,130 @@
FALSE, game_timing_state,
0, /* mouse_priorities */
};
+
+#ifdef STANDALONE_SOLVER
+
+/*
+ * Half-hearted standalone solver. It can't output the solution to
+ * anything but a square puzzle, and it can't log the deductions
+ * it makes either. But it can solve square puzzles, and more
+ * importantly it can use its solver to grade the difficulty of
+ * any puzzle you give it.
+ */
+
+#include <stdarg.h>
+
+int main(int argc, char **argv)
+{
+ game_params *p;
+ game_state *s;
+ char *id = NULL, *desc, *err;
+ int grade = FALSE;
+ int ret, diff;
+#if 0 /* verbose solver not supported here (yet) */
+ int really_verbose = FALSE;
+#endif
+
+ while (--argc > 0) {
+ char *p = *++argv;
+#if 0 /* verbose solver not supported here (yet) */
+ if (!strcmp(p, "-v")) {
+ really_verbose = TRUE;
+ } else
+#endif
+ if (!strcmp(p, "-g")) {
+ grade = TRUE;
+ } else if (*p == '-') {
+ fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p);
+ return 1;
+ } else {
+ id = p;
+ }
+ }
+
+ if (!id) {
+ fprintf(stderr, "usage: %s [-g | -v] <game_id>\n", argv[0]);
+ return 1;
+ }
+
+ desc = strchr(id, ':');
+ if (!desc) {
+ fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]);
+ return 1;
+ }
+ *desc++ = '\0';
+
+ p = default_params();
+ decode_params(p, id);
+ err = validate_desc(p, desc);
+ if (err) {
+ fprintf(stderr, "%s: %s\n", argv[0], err);
+ return 1;
+ }
+ s = new_game(NULL, p, desc);
+
+ /*
+ * When solving an Easy puzzle, we don't want to bother the
+ * user with Hard-level deductions. For this reason, we grade
+ * the puzzle internally before doing anything else.
+ */
+ ret = -1; /* placate optimiser */
+ for (diff = 0; diff < DIFF_MAX; diff++) {
+ solver_state *sstate_new;
+ solver_state *sstate = new_solver_state((game_state *)s, diff);
+
+ sstate_new = solve_game_rec(sstate, diff);
+
+ if (sstate_new->solver_status == SOLVER_MISTAKE)
+ ret = 0;
+ else if (sstate_new->solver_status == SOLVER_SOLVED)
+ ret = 1;
+ else
+ ret = 2;
+
+ free_solver_state(sstate_new);
+ free_solver_state(sstate);
+
+ if (ret < 2)
+ break;
+ }
+
+ if (diff == DIFF_MAX) {
+ if (grade)
+ printf("Difficulty rating: harder than Hard, or ambiguous\n");
+ else
+ printf("Unable to find a unique solution\n");
+ } else {
+ if (grade) {
+ if (ret == 0)
+ printf("Difficulty rating: impossible (no solution exists)\n");
+ else if (ret == 1)
+ printf("Difficulty rating: %s\n", diffnames[diff]);
+ } else {
+ solver_state *sstate_new;
+ solver_state *sstate = new_solver_state((game_state *)s, diff);
+
+ /* If we supported a verbose solver, we'd set verbosity here */
+
+ sstate_new = solve_game_rec(sstate, diff);
+
+ if (sstate_new->solver_status == SOLVER_MISTAKE)
+ printf("Puzzle is inconsistent\n");
+ else {
+ assert(sstate_new->solver_status == SOLVER_SOLVED);
+ if (s->grid_type == 0) {
+ fputs(game_text_format(sstate_new->state), stdout);
+ } else {
+ printf("Unable to output non-square grids\n");
+ }
+ }
+
+ free_solver_state(sstate_new);
+ free_solver_state(sstate);
+ }
+ }
+
+ return 0;
+}
+
+#endif