diff --git a/inertia.c b/inertia.c index 7bd73c1..4cbdd52 100644 --- a/inertia.c +++ b/inertia.c @@ -735,7 +735,7 @@ static int compare_integers(const void *av, const void *bv) static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { - int w = state->p.w, h = state->p.h, wh = w*h; + int w = currstate->p.w, h = currstate->p.h, wh = w*h; int *nodes, *nodeindex, *edges, *backedges, *edgei, *backedgei, *circuit; int nedges; int *dist, *dist2, *list; @@ -1645,6 +1645,38 @@ static char *interpret_move(const game_state *state, game_ui *ui, return dupstr(buf); } +static void install_new_solution(game_state *ret, const char *move) +{ + int i; + soln *sol; + assert (*move == 'S'); + ++move; + + sol = snew(soln); + sol->len = strlen(move); + sol->list = snewn(sol->len, unsigned char); + for (i = 0; i < sol->len; ++i) sol->list[i] = move[i] - '0'; + + if (ret->soln && --ret->soln->refcount == 0) { + sfree(ret->soln->list); + sfree(ret->soln); + } + + ret->soln = sol; + sol->refcount = 1; + + ret->cheated = TRUE; + ret->solnpos = 0; +} + +static void discard_solution(game_state *ret) +{ + --ret->soln->refcount; + assert(ret->soln->refcount > 0); /* ret has a soln-pointing dup */ + ret->soln = NULL; + ret->solnpos = 0; +} + static game_state *execute_move(const game_state *state, const char *move) { int w = state->p.w, h = state->p.h /*, wh = w*h */; @@ -1652,29 +1684,12 @@ static game_state *execute_move(const game_state *state, const char *move) game_state *ret; if (*move == 'S') { - int len, i; - soln *sol; - /* * This is a solve move, so we don't actually _change_ the * grid but merely set up a stored solution path. */ - move++; - len = strlen(move); - sol = snew(soln); - sol->len = len; - sol->list = snewn(len, unsigned char); - for (i = 0; i < len; i++) - sol->list[i] = move[i] - '0'; ret = dup_game(state); - ret->cheated = TRUE; - if (ret->soln && --ret->soln->refcount == 0) { - sfree(ret->soln->list); - sfree(ret->soln); - } - ret->soln = sol; - ret->solnpos = 0; - sol->refcount = 1; + install_new_solution(ret, move); return ret; } @@ -1715,22 +1730,18 @@ static game_state *execute_move(const game_state *state, const char *move) } if (ret->soln) { - /* - * If this move is the correct next one in the stored - * solution path, advance solnpos. - */ - if (ret->soln->list[ret->solnpos] == dir && - ret->solnpos+1 < ret->soln->len) { - ret->solnpos++; + if (ret->dead || ret->gems == 0) + discard_solution(ret); + else if (ret->soln->list[ret->solnpos] == dir) { + ++ret->solnpos; + assert(ret->solnpos < ret->soln->len); /* or gems == 0 */ + assert(!ret->dead); /* or not a solution */ } else { - /* - * Otherwise, the user has strayed from the path, so - * the path is no longer valid. - */ - ret->soln->refcount--; - assert(ret->soln->refcount > 0);/* `state' at least still exists */ - ret->soln = NULL; - ret->solnpos = 0; + char *error = NULL, *soln = solve_game(NULL, ret, NULL, &error); + if (!error) { + install_new_solution(ret, soln); + sfree(soln); + } else discard_solution(ret); } } diff --git a/puzzles.but b/puzzles.but index 113f462..b220ca2 100644 --- a/puzzles.but +++ b/puzzles.but @@ -2032,9 +2032,7 @@ begin on this path. If you then move in that direction, the arrow will update to indicate the next direction on the path. You can also press Space to automatically move in the direction of the hint arrow. If you move in a different direction from the one shown by -the arrow, the hint arrows will stop appearing because you have -strayed from the provided path; you can then use \q{Solve} again to -generate a new path if you want to. +the arrow, arrows will be shown only if the puzzle is still solvable. All the actions described in \k{common-actions} are also available. In particular, if you do run into a mine and die, you can use the