+ sprintf(buf, "M%d,%d", dx, dy);
+ return dupstr(buf);
+}
+
+static game_state *execute_move(game_state *from, char *move)
+{
+ int gx, gy, dx, dy, ux, uy, up, p;
+ game_state *ret;
+
+ if (!strcmp(move, "S")) {
+ int i;
+
+ ret = dup_game(from);
+
+ /*
+ * 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.
+ */
+ for (i = 0; i < ret->n; i++)
+ ret->tiles[i] = (i+1) % ret->n;
+ ret->gap_pos = ret->n-1;
+ ret->used_solve = ret->just_used_solve = TRUE;
+ ret->completed = ret->movecount = 1;
+
+ return ret;
+ }
+
+ gx = X(from, from->gap_pos);
+ gy = Y(from, from->gap_pos);
+
+ if (move[0] != 'M' ||
+ sscanf(move+1, "%d,%d", &dx, &dy) != 2 ||
+ (dx == gx && dy == gy) || (dx != gx && dy != gy) ||
+ dx < 0 || dx >= from->w || dy < 0 || dy >= from->h)
+ return NULL;
+