+ return dupstr("S");
+}
+
+static int game_can_format_as_text_now(game_params *params)
+{
+ return TRUE;
+}
+
+static char *game_text_format(game_state *state)
+{
+ char *ret, *p, buf[80];
+ int x, y, col, maxlen;
+
+ /*
+ * First work out how many characters we need to display each
+ * number.
+ */
+ col = sprintf(buf, "%d", state->n);
+
+ /*
+ * 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, w-1
+ * spaces and a trailing newline.
+ */
+ maxlen = state->h * state->w * (col+1);
+
+ ret = snewn(maxlen+1, char);
+ p = ret;
+
+ for (y = 0; y < state->h; y++) {
+ for (x = 0; x < state->w; x++) {
+ int v = state->tiles[state->w*y+x];
+ sprintf(buf, "%*d", col, v);
+ memcpy(p, buf, col);
+ p += col;
+ if (x+1 == state->w)
+ *p++ = '\n';
+ else
+ *p++ = ' ';
+ }
+ }
+
+ assert(p - ret == maxlen);
+ *p = '\0';
+ return ret;
+}
+
+struct game_ui {
+ int cur_x, cur_y;
+ int cur_visible;
+};
+
+static game_ui *new_ui(game_state *state)
+{
+ game_ui *ui = snew(game_ui);
+ ui->cur_x = 0;
+ ui->cur_y = -1;
+ ui->cur_visible = FALSE;
+
+ return ui;
+}
+
+static void free_ui(game_ui *ui)
+{
+ sfree(ui);
+}
+
+static char *encode_ui(game_ui *ui)
+{
+ return NULL;
+}
+
+static void decode_ui(game_ui *ui, char *encoding)
+{
+}
+
+static void game_changed_state(game_ui *ui, game_state *oldstate,
+ game_state *newstate)
+{
+}
+
+struct game_drawstate {
+ int started;
+ int w, h, bgcolour;
+ int *tiles;
+ int tilesize;
+ int cur_x, cur_y;
+};
+
+static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
+ int x, int y, int button)
+{
+ int cx = -1, cy = -1, dx, dy;
+ char buf[80];
+
+ button &= ~MOD_MASK;
+
+ if (IS_CURSOR_MOVE(button)) {
+ /* right/down rotates cursor clockwise,
+ * left/up rotates anticlockwise. */
+ int cpos, diff;
+ cpos = c2pos(state->w, state->h, ui->cur_x, ui->cur_y);
+ diff = c2diff(state->w, state->h, ui->cur_x, ui->cur_y, button);
+
+ cpos += diff;
+ pos2c(state->w, state->h, cpos, &ui->cur_x, &ui->cur_y);
+
+ ui->cur_visible = 1;
+ return "";
+ }
+
+ if (button == LEFT_BUTTON || button == RIGHT_BUTTON) {
+ cx = FROMCOORD(x);
+ cy = FROMCOORD(y);
+ ui->cur_visible = 0;
+ } else if (IS_CURSOR_SELECT(button)) {
+ if (ui->cur_visible) {
+ cx = ui->cur_x;
+ cy = ui->cur_y;
+ } else {
+ ui->cur_visible = 1;
+ return "";
+ }
+ } else {
+ return NULL;
+ }
+
+ if (cx == -1 && cy >= 0 && cy < state->h)
+ dx = -1, dy = 0;
+ else if (cx == state->w && cy >= 0 && cy < state->h)
+ dx = +1, dy = 0;
+ else if (cy == -1 && cx >= 0 && cx < state->w)
+ dy = -1, dx = 0;
+ else if (cy == state->h && cx >= 0 && cx < state->w)
+ dy = +1, dx = 0;
+ else
+ return ""; /* invalid click location */
+
+ /* reverse direction if right hand button is pressed */
+ if (button == RIGHT_BUTTON || button == CURSOR_SELECT2) {
+ dx = -dx;
+ dy = -dy;
+ }