package com.projectsacrifice.game; /** Black-box level-8 scenarios driven only through the production input boundary. */ final class LevelEightScenario { private static final long DECISION_MILLIS = 32L; static final class Result { private final boolean completed; private final int deaths; private final String diagnostic; Result(boolean completed, int deaths, String diagnostic) { this.completed = completed; this.deaths = deaths; this.diagnostic = diagnostic; } boolean completed() { return completed; } int deaths() { return deaths; } String diagnostic() { return diagnostic; } } Result recoverAfterClockExpires(LevelPlaytestBot.Driver driver, long timeoutMillis) { long deadline = driver.currentTimeMillis() + timeoutMillis; driver.startLevel(8); GameView.AutomationSnapshot snapshot = crossPit(driver, deadline); if (failed(snapshot, deadline, driver)) { return failure("Cross the pit before the clock expires", snapshot); } snapshot = await(driver, deadline, "Wait for the far-side trap", LevelPlaytestBot.Input.none(), current -> current.playerX() >= 1_510f && !current.allDoorsOpen()); if (failed(snapshot, deadline, driver)) { return failure("Wait for the far-side trap", snapshot); } snapshot = await(driver, deadline, "Return beneath the recovery relay", LevelPlaytestBot.Input.left(), current -> current.playerX() <= 1_680f && current.playerY() >= 779f); if (failed(snapshot, deadline, driver)) { return failure("Return beneath the recovery relay", snapshot); } snapshot = pulseLeftJumpThenAwait(driver, deadline, "Jump into the recovery relay", current -> current.allDoorsOpen()); if (failed(snapshot, deadline, driver)) { return failure("Jump into the recovery relay", snapshot); } snapshot = await(driver, deadline, "Land after rearming the clock", LevelPlaytestBot.Input.none(), current -> current.playerY() >= 779f); if (failed(snapshot, deadline, driver)) { return failure("Land after rearming the clock", snapshot); } return finishFromFarSide(driver, deadline, snapshot, "Finish after recovery"); } Result completeIntendedRoute(LevelPlaytestBot.Driver driver, long timeoutMillis) { long deadline = driver.currentTimeMillis() + timeoutMillis; driver.startLevel(8); GameView.AutomationSnapshot snapshot = crossPit(driver, deadline); if (failed(snapshot, deadline, driver)) { return failure("Cross the pit before the clock expires", snapshot); } return finishFromFarSide(driver, deadline, snapshot, "Finish on the original timer"); } private GameView.AutomationSnapshot crossPit(LevelPlaytestBot.Driver driver, long deadline) { GameView.AutomationSnapshot snapshot = await(driver, deadline, "Trigger the left timer", LevelPlaytestBot.Input.right(), GameView.AutomationSnapshot::allDoorsOpen); if (failed(snapshot, deadline, driver)) return snapshot; long timerStartedAt = snapshot.elapsedMilliseconds(); snapshot = await(driver, deadline, "Approach the pit", LevelPlaytestBot.Input.right(), current -> current.playerX() >= 760f); if (failed(snapshot, deadline, driver)) return snapshot; snapshot = await(driver, deadline, "Wait for the moving platform", LevelPlaytestBot.Input.none(), current -> current.elapsedMilliseconds() >= timerStartedAt + 2_250L); if (failed(snapshot, deadline, driver)) return snapshot; driver.setInput(false, true, true); driver.waitForNextDecision(64L); driver.setInput(false, true, false); snapshot = await(driver, deadline, "Land on the moving platform", LevelPlaytestBot.Input.right(), current -> current.elapsedMilliseconds() >= timerStartedAt + 3_200L); if (failed(snapshot, deadline, driver)) return snapshot; driver.setInput(false, true, true); driver.waitForNextDecision(64L); driver.setInput(false, true, false); snapshot = await(driver, deadline, "Jump from the moving platform to the far floor", LevelPlaytestBot.Input.right(), current -> current.playerX() >= 1_510f); if (failed(snapshot, deadline, driver)) return snapshot; snapshot = awaitFarFloorLandingOnOriginalTimer(driver, deadline); if (failed(snapshot, deadline, driver)) return snapshot; return await(driver, deadline, "Move under the relay after landing", LevelPlaytestBot.Input.right(), current -> current.playerX() >= 1_600f && current.playerY() >= 779f && current.allDoorsOpen()); } private GameView.AutomationSnapshot awaitFarFloorLandingOnOriginalTimer( LevelPlaytestBot.Driver driver, long deadline ) { boolean moveLeft = true; GameView.AutomationSnapshot snapshot = driver.snapshot(); while (driver.currentTimeMillis() < deadline && snapshot.playerAlive() && !(snapshot.playerX() >= 1_510f && snapshot.playerX() < 1_580f && snapshot.playerY() >= 779f && snapshot.allDoorsOpen())) { driver.setInput(moveLeft, !moveLeft, false); moveLeft = !moveLeft; driver.waitForNextDecision(DECISION_MILLIS); snapshot = driver.snapshot(); } driver.setInput(false, false, false); return snapshot; } private Result finishFromFarSide(LevelPlaytestBot.Driver driver, long deadline, GameView.AutomationSnapshot snapshot, String step) { snapshot = await(driver, deadline, "Reach the open-door jump", LevelPlaytestBot.Input.right(), current -> current.playerX() >= 1_730f && current.allDoorsOpen()); if (failed(snapshot, deadline, driver)) { return failure("Reach the open-door jump", snapshot); } driver.setInput(false, true, true); driver.waitForNextDecision(64L); driver.setInput(false, true, false); snapshot = await(driver, deadline, step, LevelPlaytestBot.Input.right(), GameView.AutomationSnapshot::completed); driver.setInput(false, false, false); if (!snapshot.completed()) return failure(step, snapshot); return new Result(true, snapshot.deaths(), step + " completed; " + state(snapshot)); } private GameView.AutomationSnapshot pulseLeftJumpThenAwait( LevelPlaytestBot.Driver driver, long deadline, String step, LevelPlaytestBot.SnapshotCondition completion ) { driver.setInput(true, false, true); driver.waitForNextDecision(64L); driver.setInput(true, false, false); return await(driver, deadline, step, LevelPlaytestBot.Input.left(), completion); } private GameView.AutomationSnapshot await( LevelPlaytestBot.Driver driver, long deadline, String step, LevelPlaytestBot.Input input, LevelPlaytestBot.SnapshotCondition completion ) { GameView.AutomationSnapshot snapshot = driver.snapshot(); while (driver.currentTimeMillis() < deadline && snapshot.playerAlive() && !snapshot.completed() && !completion.reached(snapshot)) { setInput(driver, input); driver.waitForNextDecision(DECISION_MILLIS); snapshot = driver.snapshot(); } if (driver.currentTimeMillis() >= deadline || !snapshot.playerAlive()) { driver.setInput(false, false, false); } return snapshot; } private static void setInput(LevelPlaytestBot.Driver driver, LevelPlaytestBot.Input input) { if (input == LevelPlaytestBot.Input.right()) { driver.setInput(false, true, false); } else if (input == LevelPlaytestBot.Input.left()) { driver.setInput(true, false, false); } else if (input == LevelPlaytestBot.Input.rightJump()) { driver.setInput(false, true, true); } else { driver.setInput(false, false, false); } } private static boolean failed(GameView.AutomationSnapshot snapshot, long deadline, LevelPlaytestBot.Driver driver) { return !snapshot.completed() && (!snapshot.playerAlive() || driver.currentTimeMillis() >= deadline); } private static Result failure(String step, GameView.AutomationSnapshot snapshot) { return new Result(false, snapshot.deaths(), step + " failed; " + state(snapshot)); } private static String state(GameView.AutomationSnapshot snapshot) { return "x=" + snapshot.playerX() + ", y=" + snapshot.playerY() + ", alive=" + snapshot.playerAlive() + ", doorOpen=" + snapshot.allDoorsOpen() + ", completed=" + snapshot.completed() + ", elapsedMs=" + snapshot.elapsedMilliseconds() + ", deaths=" + snapshot.deaths(); } }