+ return NULL;
+ }
+}
+
+static game_state *execute_move(game_state *from, char *move)
+{
+ game_state *ret;
+ int tx, ty, n, noanim, orig;
+
+ ret = dup_game(from);
+ ret->just_used_solve = FALSE;
+
+ if (move[0] == 'J' || move[0] == 'S') {
+ if (move[0] == 'S')
+ ret->just_used_solve = ret->used_solve = TRUE;
+
+ move++;
+ if (*move == ';')
+ move++;
+ noanim = TRUE;
+ } else
+ noanim = FALSE;
+
+ ret->last_rotate_dir = 0; /* suppress animation */
+ ret->last_rotate_x = ret->last_rotate_y = 0;
+
+ while (*move) {
+ if ((move[0] == 'A' || move[0] == 'C' ||
+ move[0] == 'F' || move[0] == 'L') &&
+ sscanf(move+1, "%d,%d%n", &tx, &ty, &n) >= 2 &&
+ tx >= 0 && tx < from->width && ty >= 0 && ty < from->height) {
+ orig = tile(ret, tx, ty);
+ if (move[0] == 'A') {
+ tile(ret, tx, ty) = A(orig);
+ if (!noanim)
+ ret->last_rotate_dir = +1;
+ } else if (move[0] == 'F') {
+ tile(ret, tx, ty) = F(orig);
+ if (!noanim)
+ ret->last_rotate_dir = +2; /* + for sake of argument */
+ } else if (move[0] == 'C') {
+ tile(ret, tx, ty) = C(orig);
+ if (!noanim)
+ ret->last_rotate_dir = -1;
+ } else {
+ assert(move[0] == 'L');
+ tile(ret, tx, ty) ^= LOCKED;
+ }
+
+ move += 1 + n;
+ if (*move == ';') move++;
+ } else {
+ free_game(ret);
+ return NULL;
+ }
+ }
+ if (!noanim) {
+ ret->last_rotate_x = tx;
+ ret->last_rotate_y = ty;