+
+#ifdef STANDALONE_SOLVER
+
+#include <stdarg.h>
+
+void frontend_default_colour(frontend *fe, float *output) {}
+void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize,
+ int align, int colour, char *text) {}
+void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) {}
+void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) {}
+void draw_polygon(drawing *dr, int *coords, int npoints,
+ int fillcolour, int outlinecolour) {}
+void draw_circle(drawing *dr, int cx, int cy, int radius,
+ int fillcolour, int outlinecolour) {}
+void clip(drawing *dr, int x, int y, int w, int h) {}
+void unclip(drawing *dr) {}
+void start_draw(drawing *dr) {}
+void draw_update(drawing *dr, int x, int y, int w, int h) {}
+void end_draw(drawing *dr) {}
+blitter *blitter_new(drawing *dr, int w, int h) {return NULL;}
+void blitter_free(drawing *dr, blitter *bl) {}
+void blitter_save(drawing *dr, blitter *bl, int x, int y) {}
+void blitter_load(drawing *dr, blitter *bl, int x, int y) {}
+int print_mono_colour(drawing *dr, int grey) { return 0; }
+int print_rgb_colour(drawing *dr, int hatch, float r, float g, float b)
+{ return 0; }
+void print_line_width(drawing *dr, int width) {}
+
+void fatal(char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "fatal error: ");
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ game_params *p;
+ game_state *s;
+ char *id = NULL, *desc, *err;
+ int grade = FALSE;
+ int ret, diff, really_verbose = FALSE;
+ struct solver_scratch *sc;
+ int i;
+
+ while (--argc > 0) {
+ char *p = *++argv;
+ if (!strcmp(p, "-v")) {
+ really_verbose = TRUE;
+ } else 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);
+
+ sc = new_scratch(s->map->graph, s->map->n, s->map->ngraph);
+
+ /*
+ * 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 < DIFFCOUNT; diff++) {
+ for (i = 0; i < s->map->n; i++)
+ if (!s->map->immutable[i])
+ s->colouring[i] = -1;
+ ret = map_solver(sc, s->map->graph, s->map->n, s->map->ngraph,
+ s->colouring, diff);
+ if (ret < 2)
+ break;
+ }
+
+ if (diff == DIFFCOUNT) {
+ 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", map_diffnames[diff]);
+ } else {
+ verbose = really_verbose;
+ for (i = 0; i < s->map->n; i++)
+ if (!s->map->immutable[i])
+ s->colouring[i] = -1;
+ ret = map_solver(sc, s->map->graph, s->map->n, s->map->ngraph,
+ s->colouring, diff);
+ if (ret == 0)
+ printf("Puzzle is inconsistent\n");
+ else {
+ int col = 0;
+
+ for (i = 0; i < s->map->n; i++) {
+ printf("%5d <- %c%c", i, colnames[s->colouring[i]],
+ (col < 6 && i+1 < s->map->n ? ' ' : '\n'));
+ if (++col == 7)
+ col = 0;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+#endif