26 KiB
Графы решений уровней 1–10
Документ фиксирует предполагаемый авторский маршрут каждого уровня текущего vertical slice. Он получен из LevelCatalog, моделей LevelDefinition и фактической логики GameView, а не из ручного прохождения. targetDeaths ниже — целевое число жертв для результата уровня, но оно не доказывает минимальность решения.
На 18 августа 2026 года автоматически доказан только уровень 5: LevelFivePlaythroughTest управляет production GameView через те же флаги движения и прыжка, что и touch-контролы. Все остальные графы имеют статус «предполагаемый, не доказан ботом» до появления воспроизводимого connectedDebugAndroidTest.
Семантика, общая для графов
PRESSUREактивен, пока с егоboxпересекается достаточная масса живого игрока и/или тел (requiredMass). Сигнал не защёлкивается.TOGGLEменяет значение сигнала только на фронте контакта; повторный вход переключает его обратно.TIMEDзапускает таймер только на фронте контакта; удержание на переключателе не перезапускает истёкший таймер.Door.requiredSignalsиспользует AND-семантику: дверь открыта, только когда активны все указанные сигналы.- Управляемая движущаяся платформа накапливает
motionTimeтолько при активномcontrolId; при потере сигнала она замирает в текущей фазеGameMath.pingPong. SPIKESоставляет закреплённое тело над шипами;SAWпередаёт телуimpulseX/impulseY;FREEZERсоздаёт неподвижный блок104×104;ELECTRICоставляет закреплённое проводящее тело внутри опасности;PITтела не оставляет.- Тела являются твёрдыми опорами для игрока. Смерть сохраняет тела и состояния уровня, respawn возвращает нового игрока в
spawnX/spawnY; restart очищает состояние. - Пересечение живого игрока с
goalпереводит сцену вCOMPLETE.
Уровень 1 — The Volunteer
Статус: предполагаемый маршрут, ботом не доказан.
Ожидаемые смерти: 0 (targetDeaths=0).
Источник: LevelCatalog.level1(); уступы (640,760,230) и (1060,690,250); goal=(1690,770,86,110).
Solution graph 1
Goal расположен справа от двух перекрывающих путь уступов
→ разогнаться вправо и запрыгнуть на уступ x=640..870
→ сохранить движение и перепрыгнуть на более высокий уступ x=1060..1310
→ спуститься на сплошной floor(0,1920)
→ пересечь goal x=1690..1776
→ COMPLETE без смерти
Механика и сигналы: только движение, прыжок и статические Platform; сигналов и дверей нет.
Bot checkpoints: playerX>640 при playerY≤660 → playerX>1060 при playerY≤590 → playerX>1310 → completed=true, deaths=0.
Softlock/неопределённость: blocker-softlock по данным модели не ожидается; точные окна двух прыжков и возможность альтернативного прохода под/мимо уступов автоматически не проверены.
Уровень 2 — A Useful End
Статус: предполагаемый маршрут, ботом не доказан.
Ожидаемые смерти: 3 (targetDeaths=3).
Источник: LevelCatalog.level2(); SPIKES=(610,850,260,30); статичный уступ (1180,740,240); goal=(1830,770,86,110).
Solution graph 2
Spike lane x=610..870 перекрывает наземный маршрут
→ первый доброволец погибает на ближнем краю SPIKES
→ закреплённое тело становится первой твёрдой опорой
→ следующие добровольцы продвигаются прыжками и оставляют ещё два тела
→ цепочка из трёх тел образует предусмотренный путь через lane
→ следующий доброволец пересекает тела, возвращается на floor
→ проходит уступ x=1180..1420 и достигает goal
→ COMPLETE с целевыми тремя смертями
Механика и сигналы: SPIKES закрепляет каждое тело на hazard.box.y-corpse.height; двери и сигналы отсутствуют.
Bot checkpoints: после каждой предусмотренной жертвы deaths/corpseCount=1/1, 2/2, 3/3; затем живой игрок playerX>870; финально completed=true, deaths=3.
Softlock/неопределённость: тела становятся горизонтальными коллайдерами и требуют прыжка уже после первой смерти. При текущих RUN_SPEED/JUMP_SPEED ширина lane может допускать перепрыгивание с меньшим числом смертей; это возможный sequence break, а не подтверждённый маршрут. Нужны бот-проверка intended route и отдельный negative/alternative-solution тест.
Уровень 3 — Dead Weight
Статус: предполагаемый маршрут, ботом не доказан.
Ожидаемые смерти: 1 (targetDeaths=1).
Источник: LevelCatalog.level3(); SAW=(565,760,92,92), impulse (0,-150); PRESSURE=(540,860,150,20), signalId="gate"; дверь (1110,570,78,310) требует "gate".
Solution graph 3
Door закрывает путь к goal
→ для Door требуется активный signal "gate"
→ PRESSURE удерживает "gate" только при постоянной массе
→ первый доброволец входит в SAW над зоной плиты
→ тело с нулевым horizontal impulse оседает на PRESSURE
→ "gate" становится active и Door открывается
→ respawn следующего добровольца
→ перепрыгнуть SAW/тело, пройти открытую Door
→ пересечь goal и получить COMPLETE
Механика и сигналы: checkpoint цепочки — corpseCount=1 → switchContact(PRESSURE)=true → signalActive("gate")=true → doorOpen=true.
Bot checkpoints: deaths=1, corpseCount=1; после respawn playerAlive=true; требуется расширить snapshot состоянием "gate" либо использовать allDoorsOpen=true; затем playerX>1188 и completed=true.
Softlock/неопределённость: успех зависит от фактической точки первого пересечения игрока с SAW, потому что тело сохраняет player.x; достаточное перекрытие с плитой ботом ещё не доказано. Если тело не удержит плиту, продолжение невозможно без дополнительной жертвы или restart.
Уровень 4 — The Long Lift
Статус: предполагаемый маршрут, ботом не доказан.
Ожидаемые смерти: 0 (targetDeaths=0).
Источник: LevelCatalog.level4(); TOGGLE=(520,820,72,60), signalId="lift"; moving platform (1040,790,260,34), travel (0,-390), period 5.2, controlId="lift"; PIT=(1500,880,320,200); верхний уступ (1660,500,540); goal=(1960,390,86,110).
Solution graph 4
Goal находится на верхней галерее за PIT
→ обычный прыжок с floor не даёт требуемой высоты
→ один раз войти в TOGGLE и включить signal "lift"
→ активный "lift" запускает вертикальный цикл moving platform
→ запрыгнуть на platform x=1040..1300 и подняться
→ в верхней фазе прыгнуть вправо через край PIT на ledge x=1660..2200
→ пройти по галерее до goal
→ COMPLETE без смерти
Механика и сигналы: фронт контакта TOGGLE → toggleSignals["lift"]=true → растёт motionTime платформы → travelY*pingPong поднимает её максимум на 390.
Bot checkpoints: signal "lift"=true; координата платформы уменьшается от y=790; игрок получает supportIndex движущейся платформы; затем playerX≥1660, playerY≤400; финально completed=true, deaths=0. Для этого snapshot нужно расширить сигналами, supportIndex и состоянием платформы.
Softlock/неопределённость: повторный контакт с TOGGLE выключит сигнал и заморозит платформу в текущей фазе. Прыжок от правого края платформы к началу галереи имеет небольшой геометрический запас и не подтверждён ботом; это риск точного тайминга/непроходимости.
Уровень 5 — Express Delivery
Статус: автоматически доказан LevelFivePlaythroughTest на production GameView.
Ожидаемые смерти: 1 (targetDeaths=1); acceptance-тест требует минимум одну.
Источник: LevelCatalog.level5(); SAW=(570,760,96,96), impulse (500,-700); уступ (850,800,330); PRESSURE=(930,780,160,20), signalId="gate"; дверь (1390,560,82,320) требует "gate"; goal=(2080,770,86,110).
Solution graph 5
Door закрывает путь к goal
→ для Door требуется signal "gate"
→ удалённую PRESSURE нужно удерживать постоянной массой
→ первый доброволец идёт вправо в SAW
→ SAW убивает и запускает тело impulse (500,-700)
→ тело приземляется на уступе/плите x=930..1090
→ PRESSURE активирует "gate", Door открывается
→ следующий доброволец respawn-ится
→ прыжками пересекает SAW и зону доставленного тела
→ проходит открытую Door и достигает goal
→ COMPLETE
Механика и сигналы: SAW создаёт динамическое тело → контакт тела с PRESSURE → signalActive("gate")=true → allDoorsOpen=true.
Bot checkpoints: реализованы в LevelPlaytestBot.proveLevelFive: первая смерть; corpseCount≥1; allDoorsOpen=true; прыжок после playerX≥390, дополнительный прыжок после playerX≥750; затем completed=true. Тест проверяет completed, смерть, сохранённое тело и факт открытия двери.
Softlock/неопределённость: основной маршрут воспроизводимо подтверждён одним device-level acceptance-тестом, но пока не выполняется требование roadmap о трёх последовательных прогонах. Альтернативные решения, restart и физическая стабильность на нескольких frame rates этим тестом не покрыты.
Уровень 6 — Cold Comfort
Статус: предполагаемый маршрут, ботом не доказан.
Ожидаемые смерти: 1 (targetDeaths=1).
Источник: LevelCatalog.level6(); FREEZER=(690,776,100,104); floor заканчивается на x=1120; уступы (810,590,520) и (1430,610,570); goal=(1880,500,86,110).
Solution graph 6
Высокий уступ x=810..1330 недоступен с уровня floor обычным прыжком
→ первый доброволец входит в FREEZER
→ смерть создаёт неподвижный frozen corpse block 104×104 у x=688
→ следующий доброволец respawn-ится
→ запрыгивает на frozen block как на промежуточную ступень
→ с блока прыгает на высокий уступ x=810..1330
→ пересекает разрыв до уступа x=1430..2000
→ достигает goal на втором уступе
→ COMPLETE с одной смертью
Механика и сигналы: FREEZER принудительно ставит frozen=true, размеры 104×104, позицию (source.x-2, 880-height); тело не обновляется физикой и остаётся твёрдой ступенью. Сигналов нет.
Bot checkpoints: deaths=1, corpseCount=1; после respawn игрок стоит на блоке около playerY=676; затем на первом уступе playerY=490, playerX≥810; на втором playerY=510, playerX≥1430; финально completed=true.
Softlock/неопределённость: маршрут зависит от возможности запрыгнуть на блок рядом с активным FREEZER, а затем набрать высоту до уступа; оба перехода ботом не проверены. Frozen block фиксирован детерминированно, поэтому физический дрейф тела не ожидается.
Уровень 7 — Live Wire
Статус: предполагаемый маршрут, ботом не доказан.
Ожидаемые смерти: 1 (targetDeaths=1).
Источник: LevelCatalog.level7(); ELECTRIC=(650,780,110,100), relayId="power"; дверь (1130,560,84,320) требует "power"; goal=(1930,770,86,110).
Solution graph 7
Door закрывает путь к goal
→ Door требует signal "power"
→ "power" активен только от conductive corpse внутри ELECTRIC relay
→ первый доброволец входит в ELECTRIC
→ смерть оставляет закреплённое проводящее тело внутри hazard.box
→ relay "power" становится active и Door открывается
→ следующий доброволец respawn-ится
→ перепрыгивает ELECTRIC/тело и проходит открытую Door
→ достигает goal
→ COMPLETE с одной смертью
Механика и сигналы: ELECTRIC выставляет conductive=true, центрирует тело внутри hazard и закрепляет его; signalActive("power") требует пересечения этого тела с relay hazard.
Bot checkpoints: deaths=1, corpseCount=1; allDoorsOpen=true после появления conductive corpse; после respawn playerX>1214; финально completed=true, deaths=1. Для прямой проверки механики snapshot должен отдельно сообщать conductive state или активный "power".
Softlock/неопределённость: позиция relay-тела задаётся детерминированно, поэтому потеря сигнала не ожидается. Не доказано, что следующий игрок стабильно перепрыгивает совмещённые hazard/body без дополнительной смерти.
Уровень 8 — Borrowed Time
Статус: предполагаемый маршрут, ботом не доказан.
Ожидаемые смерти: 0 (targetDeaths=0).
Источник: LevelCatalog.level8(); TIMED=(560,810,90,70), signalId="clock", duration 5.5; moving platform (990,770,240,34), travel (380,0), period 4.0, controlId="clock"; PIT=(900,880,610,200); дверь (1770,560,82,320) требует "clock"; goal=(2220,600,86,110).
Solution graph 8
PIT разрывает floor, а Door закрывает дальнейший путь
→ войти в TIMED и запустить signal "clock" на 5.5 s
→ "clock" одновременно запускает horizontal moving platform и открывает Door
→ без задержки добежать до края floor x=900
→ прыгнуть на moving platform и пересечь PIT
→ сойти на правый floor x≥1510
→ пройти Door x=1770..1852 до истечения "clock"
→ запрыгнуть на ledge x=1980..2450
→ пересечь goal и получить COMPLETE без смерти
Механика и сигналы: фронт контакта TIMED → timedSignals["clock"]=5.5 → движение платформы по travelX=380 и открытие Door; таймер уменьшается каждый update.
Bot checkpoints: "clock" active с remaining time; platform x>990; игрок получает её supportIndex; затем playerX≥1510; Door остаётся open при playerX>1852; финально completed=true, deaths=0. Требуется добавить в snapshot remaining time и координаты платформы.
Softlock/неопределённость: если "clock" истечёт после пересечения PIT, Door закроется, платформа замрёт, а переключатель останется на левой стороне; это потенциальный blocker-softlock до restart. Достаточность 5.5 s и синхронизация прыжка на платформу ботом не доказаны.
Уровень 9 — Two Good Reasons
Статус: предполагаемый маршрут, ботом не доказан.
Ожидаемые смерти: 2 (targetDeaths=2).
Источник: LevelCatalog.level9(); SPIKES=(520,850,130,30); PRESSURE=(510,842,160,38), signalId="weight"; ELECTRIC=(910,780,110,100), relayId="power"; дверь (1510,540,86,340) требует "weight" и "power"; goal=(2310,770,86,110).
Solution graph 9
Final Door использует AND из "weight" и "power"
→ первый доброволец погибает на SPIKES внутри зоны PRESSURE
→ закреплённое spike-тело удерживает signal "weight"
→ следующий доброволец пересекает spike-тело и погибает в ELECTRIC
→ закреплённое conductive body удерживает relay signal "power"
→ "weight" AND "power" одновременно active
→ Door открывается
→ третий доброволец respawn-ится
→ перепрыгивает обе опасности, проходит открытую Door
→ достигает goal и получает COMPLETE
Механика и сигналы: spike corpse → switchContact(PRESSURE) → "weight"; conductive corpse в relay → "power"; doorOpen проверяет оба requiredSignals.
Bot checkpoints: после первой смерти deaths/corpses=1/1, "weight"=true, Door ещё closed; после второй 2/2, "power"=true, allDoorsOpen=true; после respawn playerX>1596; финально completed=true, deaths=2. Snapshot нужно расширить поимёнными сигналами, чтобы доказать AND, а не только открытие двери.
Softlock/неопределённость: первое тело сохраняет player.x в момент контакта со SPIKES; нужно подтвердить, что его пересечение с узкой общей зоной PRESSURE стабильно. Если "weight" не удерживается, дополнительная spike-смерть может изменить счётчик, но не гарантирует предусмотренное решение.
Уровень 10 — The Last Procession
Статус: предполагаемый mastery-маршрут, ботом не доказан.
Ожидаемые смерти: 3 (targetDeaths=3).
Источник: LevelCatalog.level10(); SAW=(520,760,96,96), impulse (700,-240); PRESSURE=(860,860,160,20), signalId="lift"; FREEZER=(1110,750,100,130); ELECTRIC=(1510,780,110,100), relayId="power"; moving platform (1840,790,250,34), travel (0,-410), period 5.0, controlId="lift"; PIT=(1880,880,260,200); дверь (2310,310,82,570) требует "power"; верхний уступ (2420,440,680); goal=(2880,330,86,110).
Solution graph 10
Goal расположен на верхнем уступе за PIT и закрытой высокой Door
→ первый доброволец входит в SAW
→ impulse (700,-240) доставляет тело на PRESSURE x=860..1020
→ тело удерживает signal "lift" и запускает вертикальную moving platform
→ следующий доброволец погибает в FREEZER
→ frozen corpse становится стабильной ступенью для повторного прохода этой зоны
→ следующий доброволец погибает в ELECTRIC
→ conductive corpse удерживает relay signal "power" и открывает Door
→ четвёртый доброволец respawn-ится и пересекает сохранённые тела/опасности
→ садится на активную platform у x=1840..2090
→ поднимается над PIT и в верхней фазе прыгает вправо через открытую Door
→ приземляется на ledge x=2420..3100
→ достигает goal и получает COMPLETE с тремя смертями
Механика и сигналы: launched saw corpse → "lift" → vertical platform; frozen corpse → твёрдая ступень; conductive corpse → "power" → Door open; platform и Door используют независимые постоянные сигналы от сохранённых тел.
Bot checkpoints: после SAW deaths=1, "lift"=true, platform y<790; после FREEZER deaths=2 и наличие frozen corpse; после ELECTRIC deaths=3, "power"=true, allDoorsOpen=true; затем игрок на moving-platform supportIndex, в верхней фазе playerY≤280; после прыжка playerX≥2420, playerY≤340; финально completed=true. Snapshot должен различать типы тел, оба сигнала, platform position/support.
Softlock/неопределённость: обязательность frozen corpse не следует однозначно из текущей геометрии — FREEZER потенциально можно перепрыгнуть, сохранив только две необходимые сигнальные жертвы. Доставка saw-тела на плиту зависит от динамического торможения, а прыжок с платформы к ledge имеет небольшой горизонтальный запас. Это два sequence-break/проходимость follow-up, которые нельзя считать решёнными до acceptance-бота.
Проверки, следующие из графов
- Обобщить
AutomationSnapshot: поимённые сигналы, состояния/координаты платформ,supportIndex, типы и флаги тел. - Для уровней 1–4 и 6–10 реализовать production-input acceptance-ботов; каждый intended route выполнить три раза подряд.
- Отдельно проверить предполагаемые sequence break уровня 2 и необязательность
FREEZERна уровне 10. - Проверить blocker-softlock уровня 8 после истечения
"clock"справа отPIT. - Проверить узкие/динамические места: тело на плите уровней 3 и 9, прыжок lift→ledge уровней 4 и 10.