diff --git a/src/hack.c b/src/hack.c index e18612cc9..305f8399c 100644 --- a/src/hack.c +++ b/src/hack.c @@ -931,7 +931,42 @@ boolean guess; int nx = x + xdir[ordered[dir]]; int ny = y + ydir[ordered[dir]]; - if (!isok(nx, ny)) + /* + * When guessing and trying to travel as close as possible + * to an unreachable target space, don't include spaces + * that would never be picked as a guessed target in the + * travel matrix describing player-reachable spaces. + * This stops travel from getting confused and moving the + * player back and forth in certain degenerate configurations + * of sight-blocking obstacles, e.g. + * + * T 1. Dig this out and carry enough to not be + * #### able to squeeze through diagonal gaps. + * #--.--- Stand at @ and target travel at space T. + * @..... + * |..... + * + * T 2. couldsee() marks spaces marked a and x as + * #### eligible guess spaces to move the player + * a--.--- towards. Space a is closest to T, so it gets + * @xxxxx chosen. Travel system moves @ right to travel + * |xxxxx to space a. + * + * T 3. couldsee() marks spaces marked b, c and x + * #### as eligible guess spaces to move the player + * a--c--- towards. Since findtravelpath() is called + * b@xxxx repeatedly during travel, it doesn't remember + * |xxxxx that it wanted to go to space a, so in + * comparing spaces b and c, b is chosen, since + * it seems like the closest eligible space to T. + * Travel system moves @ left to go to space b. + * + * 4. Go to 2. + * + * By limiting the travel matrix here, space a in the example + * above is never included in it, preventing the cycle. + */ + if (!isok(nx, ny) || (guess && !couldsee(nx, ny))) continue; if ((!Passes_walls && !can_ooze(&youmonst) && closed_door(x, y)) || sobj_at(BOULDER, x, y)