+static int compare_int(const void *av, const void *bv)
+{
+ const int *a = (const int *)av;
+ const int *b = (const int *)bv;
+ if (*a < *b)
+ return -1;
+ else if (*a > *b)
+ return +1;
+ else
+ return 0;
+}
+
+static game_state *solve_game(game_state *state, game_aux_info *aux,
+ char **error)
+{
+ game_state *ret = dup_game(state);
+ int i;
+
+ /*
+ * Simply replace the grid with a solved one. For this game,
+ * this isn't a useful operation for actually telling the user
+ * what they should have done, but it is useful for
+ * conveniently being able to get hold of a clean state from
+ * which to practise manoeuvres.
+ */
+ qsort(ret->grid, ret->w*ret->h, sizeof(int), compare_int);
+ for (i = 0; i < ret->w*ret->h; i++)
+ ret->grid[i] &= ~3;
+ ret->used_solve = ret->just_used_solve = TRUE;
+ ret->completed = ret->movecount;
+
+ return ret;
+}
+
+static char *game_text_format(game_state *state)
+{
+ char *ret, *p, buf[80];
+ int i, x, y, col, o, maxlen;
+
+ /*
+ * First work out how many characters we need to display each
+ * number. We're pretty flexible on grid contents here, so we
+ * have to scan the entire grid.
+ */
+ col = 0;
+ for (i = 0; i < state->w * state->h; i++) {
+ x = sprintf(buf, "%d", state->grid[i] / 4);
+ if (col < x) col = x;
+ }
+ o = (state->orientable ? 1 : 0);
+
+ /*
+ * Now we know the exact total size of the grid we're going to
+ * produce: it's got h rows, each containing w lots of col+o,
+ * w-1 spaces and a trailing newline.
+ */
+ maxlen = state->h * state->w * (col+o+1);
+
+ ret = snewn(maxlen, char);
+ p = ret;
+
+ for (y = 0; y < state->h; y++) {
+ for (x = 0; x < state->w; x++) {
+ int v = state->grid[state->w*y+x];
+ sprintf(buf, "%*d", col, v/4);
+ memcpy(p, buf, col);
+ p += col;
+ if (o)
+ *p++ = "^<v>"[v & 3];
+ if (x+1 == state->w)
+ *p++ = '\n';
+ else
+ *p++ = ' ';
+ }
+ }
+
+ assert(p - ret == maxlen);
+ *p = '\0';
+ return ret;
+}
+