Стабилизировать посадку бота на платформу уровня 8
This commit is contained in:
@@ -3,6 +3,9 @@ package com.projectsacrifice.game;
|
|||||||
/** Black-box level-8 scenarios driven only through the production input boundary. */
|
/** Black-box level-8 scenarios driven only through the production input boundary. */
|
||||||
final class LevelEightScenario {
|
final class LevelEightScenario {
|
||||||
private static final long DECISION_MILLIS = 32L;
|
private static final long DECISION_MILLIS = 32L;
|
||||||
|
private static final float LAUNCH_PLATFORM_X = 1_150f;
|
||||||
|
|
||||||
|
private String lastStep = "Start level 8";
|
||||||
|
|
||||||
static final class Result {
|
static final class Result {
|
||||||
private final boolean completed;
|
private final boolean completed;
|
||||||
@@ -21,145 +24,161 @@ final class LevelEightScenario {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Result recoverAfterClockExpires(LevelPlaytestBot.Driver driver, long timeoutMillis) {
|
Result recoverAfterClockExpires(LevelPlaytestBot.Driver driver, long timeoutMillis) {
|
||||||
long deadline = driver.currentTimeMillis() + timeoutMillis;
|
|
||||||
driver.startLevel(8);
|
driver.startLevel(8);
|
||||||
GameView.AutomationSnapshot snapshot = crossPit(driver, deadline);
|
GameView.AutomationSnapshot snapshot = driver.snapshot();
|
||||||
if (failed(snapshot, deadline, driver)) {
|
PlaytestSimulationBudget budget = PlaytestSimulationBudget.start(
|
||||||
return failure("Cross the pit before the clock expires", snapshot);
|
snapshot.elapsedMilliseconds(), driver.currentTimeMillis(), timeoutMillis);
|
||||||
|
snapshot = crossPit(driver, budget);
|
||||||
|
if (failed(snapshot, budget, driver)) {
|
||||||
|
return failure("Cross the pit before the clock expires", snapshot, budget, driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot = await(driver, deadline, "Wait for the far-side trap",
|
snapshot = await(driver, budget, "Wait for the far-side trap",
|
||||||
LevelPlaytestBot.Input.none(),
|
LevelPlaytestBot.Input.none(),
|
||||||
current -> current.playerX() >= 1_510f && !current.allDoorsOpen());
|
current -> current.playerX() >= 1_510f && !current.allDoorsOpen());
|
||||||
if (failed(snapshot, deadline, driver)) {
|
if (failed(snapshot, budget, driver)) {
|
||||||
return failure("Wait for the far-side trap", snapshot);
|
return failure("Wait for the far-side trap", snapshot, budget, driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot = await(driver, deadline, "Return beneath the recovery relay",
|
snapshot = await(driver, budget, "Return beneath the recovery relay",
|
||||||
LevelPlaytestBot.Input.left(),
|
LevelPlaytestBot.Input.left(),
|
||||||
current -> current.playerX() <= 1_680f && current.playerY() >= 779f);
|
current -> current.playerX() <= 1_680f && current.playerY() >= 779f);
|
||||||
if (failed(snapshot, deadline, driver)) {
|
if (failed(snapshot, budget, driver)) {
|
||||||
return failure("Return beneath the recovery relay", snapshot);
|
return failure("Return beneath the recovery relay", snapshot, budget, driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot = pulseLeftJumpThenAwait(driver, deadline, "Jump into the recovery relay",
|
snapshot = pulseLeftJumpThenAwait(driver, budget, "Jump into the recovery relay",
|
||||||
current -> current.allDoorsOpen());
|
current -> current.allDoorsOpen());
|
||||||
if (failed(snapshot, deadline, driver)) {
|
if (failed(snapshot, budget, driver)) {
|
||||||
return failure("Jump into the recovery relay", snapshot);
|
return failure("Jump into the recovery relay", snapshot, budget, driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot = await(driver, deadline, "Land after rearming the clock",
|
snapshot = await(driver, budget, "Land after rearming the clock",
|
||||||
LevelPlaytestBot.Input.none(), current -> current.playerY() >= 779f);
|
LevelPlaytestBot.Input.none(), current -> current.playerY() >= 779f);
|
||||||
if (failed(snapshot, deadline, driver)) {
|
if (failed(snapshot, budget, driver)) {
|
||||||
return failure("Land after rearming the clock", snapshot);
|
return failure("Land after rearming the clock", snapshot, budget, driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
return finishFromFarSide(driver, deadline, snapshot, "Finish after recovery");
|
return finishFromFarSide(driver, budget, snapshot, "Finish after recovery");
|
||||||
}
|
}
|
||||||
|
|
||||||
Result completeIntendedRoute(LevelPlaytestBot.Driver driver, long timeoutMillis) {
|
Result completeIntendedRoute(LevelPlaytestBot.Driver driver, long timeoutMillis) {
|
||||||
long deadline = driver.currentTimeMillis() + timeoutMillis;
|
|
||||||
driver.startLevel(8);
|
driver.startLevel(8);
|
||||||
GameView.AutomationSnapshot snapshot = crossPit(driver, deadline);
|
GameView.AutomationSnapshot snapshot = driver.snapshot();
|
||||||
if (failed(snapshot, deadline, driver)) {
|
PlaytestSimulationBudget budget = PlaytestSimulationBudget.start(
|
||||||
return failure("Cross the pit before the clock expires", snapshot);
|
snapshot.elapsedMilliseconds(), driver.currentTimeMillis(), timeoutMillis);
|
||||||
|
snapshot = crossPit(driver, budget);
|
||||||
|
if (failed(snapshot, budget, driver)) {
|
||||||
|
return failure("Cross the pit before the clock expires", snapshot, budget, driver);
|
||||||
}
|
}
|
||||||
return finishFromFarSide(driver, deadline, snapshot, "Finish on the original timer");
|
return finishFromFarSide(driver, budget, snapshot, "Finish on the original timer");
|
||||||
}
|
}
|
||||||
|
|
||||||
private GameView.AutomationSnapshot crossPit(LevelPlaytestBot.Driver driver, long deadline) {
|
private GameView.AutomationSnapshot crossPit(LevelPlaytestBot.Driver driver,
|
||||||
GameView.AutomationSnapshot snapshot = await(driver, deadline, "Trigger the left timer",
|
PlaytestSimulationBudget budget) {
|
||||||
|
GameView.AutomationSnapshot snapshot = await(driver, budget, "Trigger the left timer",
|
||||||
LevelPlaytestBot.Input.right(), GameView.AutomationSnapshot::allDoorsOpen);
|
LevelPlaytestBot.Input.right(), GameView.AutomationSnapshot::allDoorsOpen);
|
||||||
if (failed(snapshot, deadline, driver)) return snapshot;
|
if (failed(snapshot, budget, driver)) return snapshot;
|
||||||
long timerStartedAt = snapshot.elapsedMilliseconds();
|
long timerStartedAt = snapshot.elapsedMilliseconds();
|
||||||
|
|
||||||
snapshot = await(driver, deadline, "Approach the pit",
|
snapshot = await(driver, budget, "Approach the pit",
|
||||||
LevelPlaytestBot.Input.right(), current -> current.playerX() >= 760f);
|
LevelPlaytestBot.Input.right(), current -> current.playerX() >= 760f);
|
||||||
if (failed(snapshot, deadline, driver)) return snapshot;
|
if (failed(snapshot, budget, driver)) return snapshot;
|
||||||
|
|
||||||
snapshot = await(driver, deadline, "Wait for the moving platform",
|
snapshot = await(driver, budget, "Wait for the moving platform",
|
||||||
LevelPlaytestBot.Input.none(),
|
LevelPlaytestBot.Input.none(),
|
||||||
current -> current.elapsedMilliseconds() >= timerStartedAt + 2_250L
|
current -> current.elapsedMilliseconds() >= timerStartedAt + 2_250L
|
||||||
&& current.firstMovingPlatformX() <= 1_050f);
|
&& current.firstMovingPlatformX() <= 1_050f);
|
||||||
if (failed(snapshot, deadline, driver)) return snapshot;
|
if (failed(snapshot, budget, driver)) return snapshot;
|
||||||
|
|
||||||
driver.setInput(false, true, true);
|
driver.setInput(false, true, true);
|
||||||
driver.waitForNextDecision(64L);
|
driver.waitForNextDecision(64L);
|
||||||
driver.setInput(false, true, false);
|
driver.setInput(false, true, false);
|
||||||
snapshot = await(driver, deadline, "Land on the moving platform",
|
snapshot = await(driver, budget, "Land on the moving platform",
|
||||||
LevelPlaytestBot.Input.right(),
|
LevelPlaytestBot.Input.right(),
|
||||||
GameView.AutomationSnapshot::playerOnMovingPlatform);
|
GameView.AutomationSnapshot::playerOnMovingPlatform);
|
||||||
if (failed(snapshot, deadline, driver)) return snapshot;
|
if (failed(snapshot, budget, driver)) return snapshot;
|
||||||
|
|
||||||
|
snapshot = await(driver, budget, "Ride the moving platform to the launch zone",
|
||||||
|
LevelPlaytestBot.Input.none(),
|
||||||
|
current -> MovingPlatformLaunchPolicy.ready(current, LAUNCH_PLATFORM_X));
|
||||||
|
if (failed(snapshot, budget, driver)) return snapshot;
|
||||||
|
|
||||||
driver.setInput(false, true, true);
|
driver.setInput(false, true, true);
|
||||||
driver.waitForNextDecision(64L);
|
driver.waitForNextDecision(64L);
|
||||||
driver.setInput(false, true, false);
|
driver.setInput(false, true, false);
|
||||||
snapshot = await(driver, deadline, "Jump from the moving platform to the far floor",
|
snapshot = await(driver, budget, "Jump from the moving platform to the far floor",
|
||||||
LevelPlaytestBot.Input.right(), current -> current.playerX() >= 1_510f);
|
LevelPlaytestBot.Input.right(), current -> current.playerX() >= 1_510f);
|
||||||
if (failed(snapshot, deadline, driver)) return snapshot;
|
if (failed(snapshot, budget, driver)) return snapshot;
|
||||||
snapshot = awaitFarFloorLandingOnOriginalTimer(driver, deadline);
|
snapshot = awaitFarFloorLandingOnOriginalTimer(driver, budget);
|
||||||
if (failed(snapshot, deadline, driver)) return snapshot;
|
if (failed(snapshot, budget, driver)) return snapshot;
|
||||||
return await(driver, deadline, "Move under the relay after landing",
|
return await(driver, budget, "Move under the relay after landing",
|
||||||
LevelPlaytestBot.Input.right(),
|
LevelPlaytestBot.Input.right(),
|
||||||
current -> current.playerX() >= 1_600f
|
current -> current.playerX() >= 1_600f
|
||||||
&& current.playerY() >= 779f && current.allDoorsOpen());
|
&& current.playerY() >= 779f && current.allDoorsOpen());
|
||||||
}
|
}
|
||||||
|
|
||||||
private GameView.AutomationSnapshot awaitFarFloorLandingOnOriginalTimer(
|
private GameView.AutomationSnapshot awaitFarFloorLandingOnOriginalTimer(
|
||||||
LevelPlaytestBot.Driver driver, long deadline
|
LevelPlaytestBot.Driver driver, PlaytestSimulationBudget budget
|
||||||
) {
|
) {
|
||||||
GameView.AutomationSnapshot snapshot = await(driver, deadline,
|
GameView.AutomationSnapshot snapshot = await(driver, budget,
|
||||||
"Land on the far floor", LevelPlaytestBot.Input.right(),
|
"Land on the far floor", LevelPlaytestBot.Input.right(),
|
||||||
current -> current.playerX() >= 1_510f
|
current -> current.playerX() >= 1_510f
|
||||||
&& current.playerY() >= 779f && current.allDoorsOpen());
|
&& current.playerY() >= 779f && current.allDoorsOpen());
|
||||||
if (failed(snapshot, deadline, driver)) return snapshot;
|
if (failed(snapshot, budget, driver)) return snapshot;
|
||||||
return await(driver, deadline, "Stabilize on the far floor",
|
return await(driver, budget, "Stabilize on the far floor",
|
||||||
LevelPlaytestBot.Input.left(),
|
LevelPlaytestBot.Input.left(),
|
||||||
current -> current.playerX() < 1_580f
|
current -> current.playerX() < 1_580f
|
||||||
&& current.playerY() >= 779f && current.allDoorsOpen());
|
&& current.playerY() >= 779f && current.allDoorsOpen());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Result finishFromFarSide(LevelPlaytestBot.Driver driver, long deadline,
|
private Result finishFromFarSide(LevelPlaytestBot.Driver driver,
|
||||||
|
PlaytestSimulationBudget budget,
|
||||||
GameView.AutomationSnapshot snapshot, String step) {
|
GameView.AutomationSnapshot snapshot, String step) {
|
||||||
snapshot = await(driver, deadline, "Reach the open-door jump",
|
snapshot = await(driver, budget, "Reach the open-door jump",
|
||||||
LevelPlaytestBot.Input.right(),
|
LevelPlaytestBot.Input.right(),
|
||||||
current -> current.playerX() >= 1_730f && current.allDoorsOpen());
|
current -> current.playerX() >= 1_730f && current.allDoorsOpen());
|
||||||
if (failed(snapshot, deadline, driver)) {
|
if (failed(snapshot, budget, driver)) {
|
||||||
return failure("Reach the open-door jump", snapshot);
|
return failure("Reach the open-door jump", snapshot, budget, driver);
|
||||||
}
|
}
|
||||||
|
|
||||||
driver.setInput(false, true, true);
|
driver.setInput(false, true, true);
|
||||||
driver.waitForNextDecision(64L);
|
driver.waitForNextDecision(64L);
|
||||||
driver.setInput(false, true, false);
|
driver.setInput(false, true, false);
|
||||||
snapshot = await(driver, deadline, step, LevelPlaytestBot.Input.right(),
|
snapshot = await(driver, budget, step, LevelPlaytestBot.Input.right(),
|
||||||
GameView.AutomationSnapshot::completed);
|
GameView.AutomationSnapshot::completed);
|
||||||
driver.setInput(false, false, false);
|
driver.setInput(false, false, false);
|
||||||
if (!snapshot.completed()) return failure(step, snapshot);
|
if (!snapshot.completed()) return failure(step, snapshot, budget, driver);
|
||||||
return new Result(true, snapshot.deaths(), step + " completed; " + state(snapshot));
|
return new Result(true, snapshot.deaths(), step + " completed; "
|
||||||
|
+ budget.timingState(snapshot.elapsedMilliseconds(), driver.currentTimeMillis())
|
||||||
|
+ "; " + state(snapshot));
|
||||||
}
|
}
|
||||||
|
|
||||||
private GameView.AutomationSnapshot pulseLeftJumpThenAwait(
|
private GameView.AutomationSnapshot pulseLeftJumpThenAwait(
|
||||||
LevelPlaytestBot.Driver driver, long deadline, String step,
|
LevelPlaytestBot.Driver driver, PlaytestSimulationBudget budget, String step,
|
||||||
LevelPlaytestBot.SnapshotCondition completion
|
LevelPlaytestBot.SnapshotCondition completion
|
||||||
) {
|
) {
|
||||||
driver.setInput(true, false, true);
|
driver.setInput(true, false, true);
|
||||||
driver.waitForNextDecision(64L);
|
driver.waitForNextDecision(64L);
|
||||||
driver.setInput(true, false, false);
|
driver.setInput(true, false, false);
|
||||||
return await(driver, deadline, step, LevelPlaytestBot.Input.left(), completion);
|
return await(driver, budget, step, LevelPlaytestBot.Input.left(), completion);
|
||||||
}
|
}
|
||||||
|
|
||||||
private GameView.AutomationSnapshot await(
|
private GameView.AutomationSnapshot await(
|
||||||
LevelPlaytestBot.Driver driver, long deadline, String step,
|
LevelPlaytestBot.Driver driver, PlaytestSimulationBudget budget, String step,
|
||||||
LevelPlaytestBot.Input input, LevelPlaytestBot.SnapshotCondition completion
|
LevelPlaytestBot.Input input, LevelPlaytestBot.SnapshotCondition completion
|
||||||
) {
|
) {
|
||||||
|
lastStep = step;
|
||||||
GameView.AutomationSnapshot snapshot = driver.snapshot();
|
GameView.AutomationSnapshot snapshot = driver.snapshot();
|
||||||
while (driver.currentTimeMillis() < deadline && snapshot.playerAlive()
|
while (!budget.exhausted(snapshot.elapsedMilliseconds(), driver.currentTimeMillis())
|
||||||
|
&& snapshot.playerAlive()
|
||||||
&& !snapshot.completed() && !completion.reached(snapshot)) {
|
&& !snapshot.completed() && !completion.reached(snapshot)) {
|
||||||
setInput(driver, input);
|
setInput(driver, input);
|
||||||
driver.waitForNextDecision(DECISION_MILLIS);
|
driver.waitForNextDecision(DECISION_MILLIS);
|
||||||
snapshot = driver.snapshot();
|
snapshot = driver.snapshot();
|
||||||
}
|
}
|
||||||
if (driver.currentTimeMillis() >= deadline || !snapshot.playerAlive()) {
|
if (budget.exhausted(snapshot.elapsedMilliseconds(), driver.currentTimeMillis())
|
||||||
|
|| !snapshot.playerAlive()) {
|
||||||
driver.setInput(false, false, false);
|
driver.setInput(false, false, false);
|
||||||
}
|
}
|
||||||
return snapshot;
|
return snapshot;
|
||||||
@@ -177,14 +196,20 @@ final class LevelEightScenario {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean failed(GameView.AutomationSnapshot snapshot, long deadline,
|
private static boolean failed(GameView.AutomationSnapshot snapshot,
|
||||||
|
PlaytestSimulationBudget budget,
|
||||||
LevelPlaytestBot.Driver driver) {
|
LevelPlaytestBot.Driver driver) {
|
||||||
return !snapshot.completed()
|
return !snapshot.completed()
|
||||||
&& (!snapshot.playerAlive() || driver.currentTimeMillis() >= deadline);
|
&& (!snapshot.playerAlive()
|
||||||
|
|| budget.exhausted(snapshot.elapsedMilliseconds(), driver.currentTimeMillis()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Result failure(String step, GameView.AutomationSnapshot snapshot) {
|
private Result failure(String step, GameView.AutomationSnapshot snapshot,
|
||||||
return new Result(false, snapshot.deaths(), step + " failed; " + state(snapshot));
|
PlaytestSimulationBudget budget, LevelPlaytestBot.Driver driver) {
|
||||||
|
return new Result(false, snapshot.deaths(), step + " failed; lastStep=" + lastStep
|
||||||
|
+ "; " + budget.timingState(
|
||||||
|
snapshot.elapsedMilliseconds(), driver.currentTimeMillis())
|
||||||
|
+ "; " + state(snapshot));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String state(GameView.AutomationSnapshot snapshot) {
|
private static String state(GameView.AutomationSnapshot snapshot) {
|
||||||
@@ -194,6 +219,11 @@ final class LevelEightScenario {
|
|||||||
+ ", doorOpen=" + snapshot.allDoorsOpen()
|
+ ", doorOpen=" + snapshot.allDoorsOpen()
|
||||||
+ ", completed=" + snapshot.completed()
|
+ ", completed=" + snapshot.completed()
|
||||||
+ ", elapsedMs=" + snapshot.elapsedMilliseconds()
|
+ ", elapsedMs=" + snapshot.elapsedMilliseconds()
|
||||||
+ ", deaths=" + snapshot.deaths();
|
+ ", deaths=" + snapshot.deaths()
|
||||||
|
+ ", platformX=" + snapshot.firstMovingPlatformX()
|
||||||
|
+ ", platformY=" + snapshot.firstMovingPlatformY()
|
||||||
|
+ ", onMovingPlatform=" + snapshot.playerOnMovingPlatform()
|
||||||
|
+ ", onGround=" + snapshot.playerOnGround()
|
||||||
|
+ ", platformPowered=" + snapshot.firstMovingPlatformPowered();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.projectsacrifice.game;
|
||||||
|
|
||||||
|
/** Stable public-state gate for a single moving-platform launch. */
|
||||||
|
final class MovingPlatformLaunchPolicy {
|
||||||
|
private MovingPlatformLaunchPolicy() {}
|
||||||
|
|
||||||
|
static boolean ready(GameView.AutomationSnapshot snapshot, float minimumPlatformX) {
|
||||||
|
return snapshot.playerOnMovingPlatform()
|
||||||
|
&& snapshot.playerOnGround()
|
||||||
|
&& snapshot.firstMovingPlatformPowered()
|
||||||
|
&& snapshot.firstMovingPlatformX() >= minimumPlatformX;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package com.projectsacrifice.game;
|
||||||
|
|
||||||
|
/** Simulation-first timeout with a separate watchdog for a stalled device. */
|
||||||
|
final class PlaytestSimulationBudget {
|
||||||
|
private static final long MIN_WALL_WATCHDOG_MILLIS = 120_000L;
|
||||||
|
private static final long WALL_WATCHDOG_MULTIPLIER = 10L;
|
||||||
|
|
||||||
|
private final long simulationStartedAt;
|
||||||
|
private final long wallStartedAt;
|
||||||
|
private final long simulationBudgetMillis;
|
||||||
|
private final long wallWatchdogMillis;
|
||||||
|
|
||||||
|
private PlaytestSimulationBudget(long simulationStartedAt, long wallStartedAt,
|
||||||
|
long simulationBudgetMillis) {
|
||||||
|
this.simulationStartedAt = simulationStartedAt;
|
||||||
|
this.wallStartedAt = wallStartedAt;
|
||||||
|
this.simulationBudgetMillis = simulationBudgetMillis;
|
||||||
|
this.wallWatchdogMillis = wallWatchdogMillis(simulationBudgetMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PlaytestSimulationBudget start(long simulationStartedAt, long wallStartedAt,
|
||||||
|
long simulationBudgetMillis) {
|
||||||
|
return new PlaytestSimulationBudget(
|
||||||
|
simulationStartedAt, wallStartedAt, simulationBudgetMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean exhausted(long simulationNow, long wallNow) {
|
||||||
|
return simulationElapsed(simulationNow) >= simulationBudgetMillis
|
||||||
|
|| wallElapsed(wallNow) >= wallWatchdogMillis;
|
||||||
|
}
|
||||||
|
|
||||||
|
String timingState(long simulationNow, long wallNow) {
|
||||||
|
return "simulationElapsed=" + simulationElapsed(simulationNow)
|
||||||
|
+ ", wallElapsed=" + wallElapsed(wallNow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long simulationElapsed(long simulationNow) {
|
||||||
|
return elapsed(simulationNow, simulationStartedAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long wallElapsed(long wallNow) {
|
||||||
|
return elapsed(wallNow, wallStartedAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long wallWatchdogMillis(long simulationBudgetMillis) {
|
||||||
|
if (simulationBudgetMillis > Long.MAX_VALUE / WALL_WATCHDOG_MULTIPLIER) {
|
||||||
|
return Long.MAX_VALUE;
|
||||||
|
}
|
||||||
|
return Math.max(MIN_WALL_WATCHDOG_MILLIS,
|
||||||
|
simulationBudgetMillis * WALL_WATCHDOG_MULTIPLIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long elapsed(long current, long startedAt) {
|
||||||
|
return Math.max(0L, current - startedAt);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.projectsacrifice.game;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public final class MovingPlatformLaunchPolicyTest {
|
||||||
|
@Test
|
||||||
|
public void launchRequiresStablePoweredSupportInTheLaunchZone() {
|
||||||
|
assertFalse(MovingPlatformLaunchPolicy.ready(snapshot(910f, true, true, true), 1_150f));
|
||||||
|
assertFalse(MovingPlatformLaunchPolicy.ready(snapshot(1_150f, false, true, true), 1_150f));
|
||||||
|
assertFalse(MovingPlatformLaunchPolicy.ready(snapshot(1_150f, true, false, true), 1_150f));
|
||||||
|
assertFalse(MovingPlatformLaunchPolicy.ready(snapshot(1_150f, true, true, false), 1_150f));
|
||||||
|
assertTrue(MovingPlatformLaunchPolicy.ready(snapshot(1_150f, true, true, true), 1_150f));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GameView.AutomationSnapshot snapshot(
|
||||||
|
float platformX, boolean supported, boolean grounded, boolean powered
|
||||||
|
) {
|
||||||
|
return new GameView.AutomationSnapshot(
|
||||||
|
false, true, true, false, false, 8,
|
||||||
|
4_000L, 1_100f, 670f, 0, 0,
|
||||||
|
platformX, 770f, supported, powered, Float.NaN, grounded
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.projectsacrifice.game;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public final class PlaytestSimulationBudgetTest {
|
||||||
|
@Test
|
||||||
|
public void slowRenderingUsesSimulationBudgetWithASeparateWallWatchdog() {
|
||||||
|
PlaytestSimulationBudget budget = PlaytestSimulationBudget.start(0L, 0L, 500L);
|
||||||
|
|
||||||
|
assertFalse("Host time may outrun active simulation", budget.exhausted(96L, 1_000L));
|
||||||
|
assertTrue("Simulation budget remains authoritative", budget.exhausted(500L, 5_000L));
|
||||||
|
|
||||||
|
PlaytestSimulationBudget frozen = PlaytestSimulationBudget.start(0L, 0L, 5_000L);
|
||||||
|
assertFalse(frozen.exhausted(0L, 119_999L));
|
||||||
|
assertTrue("Frozen rendering stops at the same watchdog as the generic bot",
|
||||||
|
frozen.exhausted(0L, 120_000L));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user