Echoesdev blog

Searching the levels for shortcuts

Acts IV and V were next. Before any new level got drawn, the rules for drawing one had to be settled, and that meant measuring what a player can actually do. Measuring it turned up three shipped levels a player could finish without understanding them.

What a player can do

Every number here was measured in the simulation, not guessed. They are the ones the rest of this post leans on:

The last one matters most. A ghost doesn’t have to stand on a plate to open its door. It only has to cross it at the right moment.

Eight rules

Every new level follows eight rules:

  1. One insight per room, and one room per screen.
  2. Rooms chain as teach, test and twist. The first room shows the idea cheaply, the second takes away the weaker method, and the third changes one parameter.
  3. The insight is discoverable from the room’s waystone, before the first death. The key tiles are in sight, one tile in each room tells you what goes there, and the hint names the rule, never the solution.
  4. Red herrings fail for a reason the player can see.
  5. Hardness comes from reasoning about time, space or resources, never from execution. Every decision a player makes gets at least 30 frames or 24 px of slack.
  6. Difficulty rises within a level and across acts.
  7. Failure is cheap. A full retry of the twist room takes under 15 seconds.
  8. Shortcuts are detected, not hoped against.

Rule 5 is the lesson from Ferry, and --slack enforces it. Rule 8 needed a tool of its own.

–cheese

love game --cheese N isn’t a solver. It plays the moves a player tries before understanding anything, which are running, jumping and pressing X somewhere, and it reports any that reach the end of a room. There are four families of these shallow strategies:

Each family is a small policy that turns the world into one frame of input. The autorun is the base the others build on. It holds one direction and jumps at every wall, drop, spike or stall:

-- Runs one way and jumps, holding for `hold` frames, at every wall, drop, spike or stall.
local function autorun(dir, hold)
  return function(w, s)
    local p = w.player
    local input = { right = dir > 0, left = dir < 0 }
    if s.holdLeft > 0 then
      s.holdLeft = s.holdLeft - 1
      input.jump = true
    elseif p.state == 'ground' and s.frame > 1 and not s.prevJump
        and (solidAhead(w, p, dir) or dropAhead(w, p, dir) or spikeAhead(w, p, dir) or (s.frame > 20 and p.vx == 0)) then
      s.holdLeft = hold - 1
      s.jumps, s.jumpY, s.jumpFromEcho = s.jumps + 1, p.y, type(p.support) == 'table'
      input.jump = true
    end
    s.prevJump = input.jump or false
    return input
  end
end

The cast families wrap it. withCast(policy, castAt, wait) presses X on one frame and stands still for a while, and the search sweeps castAt along the whole run. withRiseCasts casts partway up a jump, at a swept height, because a frozen echo is only a step if it hangs low enough to land on.

The search plays 1180 of these on Other Side in 1.7 s, and 2760 per room on the four-room finale, 11,040 in all, in 21.2 s. To check the search itself, the game plants walls in a test corridor. A 5-tile wall has to be caught by the single cast and a 9-tile wall by the ladder, and a 10-tile wall has to come back clean.

Three levels fell to it

Run against the first twelve levels, the tutorials hit as expected, because their solutions are meant to be shallow. Ferry and Confluence came back clean. Three levels that were supposed to be puzzles didn’t. Level 6 shows the problem in one line:

level 6 "Other Side": 1 rooms, 533 runs in 0.7 s
  CHEESE room 1 "whole level": one cast on the natural path: autorun R hold 12, cast at frame 74, wait 0 reaches the goal at frame 116

The search prints up to four hits per family, and level 6 filled all four. Each one is the same move. Hold right, press X once, and the level is over in under two seconds.

Other Side

Level 6 asks you to find where the plate’s reflection lies. It lay on the floor between the start and the shrine. Running to the door and casting at the shrine replayed that run in mirror image, so the ghost crossed the plate on the other side of the wall for 14 frames. The door opened in front of the player, who never had to look for the reflection.

Before the fix, run right and cast once at the shrine. A moment after the cast, the violet ghost crosses the plate behind the wall and the door beside the light is open.
Before the fix, run right and cast once at the shrine. A moment after the cast, the violet ghost crosses the plate behind the wall and the door beside the light is open.
After the fix, the same keys at the same moment. The plate now sits on a ledge at the right, the reflection stays on the floor, and the door is shut.
After the fix, the same keys at the same moment. The plate now sits on a ledge at the right, the reflection stays on the floor, and the door is shut.

The fix puts the plate on a ledge in the sealed room and a matching ledge on the player’s side. A body on the floor passes under the plate’s reflection, and a jump past the ledge hits it. Only standing on the ledge presses the plate.

The intended solve. The light stood on its own ledge before casting, so the reflection is up on the sealed room's ledge by the plate, and the door is open.
The intended solve. The light stood on its own ledge before casting, so the reflection is up on the sealed room’s ledge by the plate, and the door is open.

Underfoot

Level 9’s door is a hatch in the floor. A ghost replays a crossing of the plate exactly 3 seconds after it happened, and the hatch was 2.5 seconds of running from the plate. So you could run across the plate, stand on the hatch and cast. The replayed run opened the hatch under you, with no ghost ever left on the plate.

The fix puts the plate on a pedestal behind the start, off the run, and moves the hatch 4 seconds of running away across crumble bridges. Now the replayed crossing comes while you’re still on the bridge, 45 frames too early. Only a ghost left standing on the plate holds the hatch open long enough.

Underfoot after the fix. The ghost stands on the plate on the pedestal behind the start, and the light heads right toward the crumble bridges.
Underfoot after the fix. The ghost stands on the plate on the pedestal behind the start, and the light heads right toward the crumble bridges.

Short Memory

The search found one cast, about four seconds into a plain run to the right. That’s the move a player who mashes X at the door would find. That ghost’s memory began while the player ran across the block, its first frames ran over the three-plate pad, and the plate next to the veil let a ghost frozen in the veil stand on it. That left a 24-frame window that needed no insight.

The fix shrinks the pad to one plate, two tiles clear of the veil. Past the door, the way on is now a hatch in a one-tile shaft that takes 28 frames to reach from the door. A running ghost holds the plate for 14 frames, or 18 counting the frames the player holds the door open themselves. Neither is enough. The spot where the player has to stand is one plate wide, 22 px. That’s under rule 5’s 24 px, so the level states the 20 px it needs, with the reason next to it:

{ name = 'standX', unit = 'px', nominal = 87, min = 55, max = 111, step = 2, need = 20, note = 'one plate: a wider pad would let a running ghost hold the door' },
Short Memory after the fix. The ghost holds the single plate on its block, two tiles from the veil, and the light is past the door on its way down the shaft.
Short Memory after the fix. The ghost holds the single plate on its block, two tiles from the veil, and the light is past the door on its way down the shaft.

Each shortcut became a check

Finding a shortcut once isn’t enough, because the next map edit can bring it back. So each fixed level now declares its rooms, and each room lists its naive approaches next to its solve. Here is level 6’s list, with the scripts left out:

naive = {
  { 'run to the door and cast at the shrine every half second', ... },
  { 'run under the ledge to the wall and back, then cast at the shrine every half second', ... },
  { 'stand three seconds under the ledge, then cast at the shrine', ... },
  { 'stand three seconds on the ledge and cast there', ... },
},

The game plays each naive and fails if any of them reaches the exit. Underfoot has three naives and Short Memory has five, including mashing X every 2, 10 and 30 frames.

--cheese agrees. It plays 1180 runs on Other Side, 1400 on Underfoot and 1180 on Short Memory, and finds no shallow strategy that reaches the goal in any of them.

A clean result means none of the four families works. It doesn’t mean no shortcut exists. That’s why each room’s naive list is written by hand as well, from what a player would try at that room in particular. Every new room in acts IV and V had to pass both.