Стабилизировать проходы пилы уровня 10

This commit is contained in:
2026-08-18 17:32:01 +03:00
parent 650bfb3533
commit da3777b4cc
3 changed files with 79 additions and 9 deletions
@@ -122,13 +122,19 @@ final class LateLevelScenarios {
snapshot -> snapshot.playerAlive() && snapshot.playerX() < 250f)
.step("Approach the launch saw", 2_500L,
LevelPlaytestBot.Input.right(),
snapshot -> snapshot.playerX() >= 350f)
LevelPlaytestBot.whileDeathsAtMost(1,
LevelPlaytestBot.groundedAliveAtOrBeyond(280f)))
.step("Take off before the launch saw", 1_000L,
LevelPlaytestBot.Input.rightJump(),
snapshot -> snapshot.playerAlive() && snapshot.playerY() <= 680f)
LevelPlaytestBot.whileDeathsAtMost(1,
snapshot -> snapshot.playerAlive()
&& !snapshot.playerOnGround()
&& snapshot.playerY() <= 680f))
.step("Clear the launch saw", 2_000L,
LevelPlaytestBot.Input.right(),
snapshot -> snapshot.playerAlive() && snapshot.playerX() >= 680f)
LevelPlaytestBot.whileDeathsAtMost(1,
snapshot -> snapshot.playerAlive()
&& snapshot.playerX() >= 680f))
.step("Approach the delivered lift body", 1_500L,
LevelPlaytestBot.Input.right(),
snapshot -> snapshot.playerX() >= 730f)
@@ -143,13 +149,19 @@ final class LateLevelScenarios {
snapshot -> snapshot.playerAlive() && snapshot.playerX() < 250f)
.step("Return to the launch saw", 2_500L,
LevelPlaytestBot.Input.right(),
snapshot -> snapshot.playerX() >= 350f)
LevelPlaytestBot.whileDeathsAtMost(2,
LevelPlaytestBot.groundedAliveAtOrBeyond(280f)))
.step("Take off before the saw again", 1_000L,
LevelPlaytestBot.Input.rightJump(),
snapshot -> snapshot.playerAlive() && snapshot.playerY() <= 680f)
LevelPlaytestBot.whileDeathsAtMost(2,
snapshot -> snapshot.playerAlive()
&& !snapshot.playerOnGround()
&& snapshot.playerY() <= 680f))
.step("Clear the saw again", 2_000L,
LevelPlaytestBot.Input.right(),
snapshot -> snapshot.playerAlive() && snapshot.playerX() >= 680f)
LevelPlaytestBot.whileDeathsAtMost(2,
snapshot -> snapshot.playerAlive()
&& snapshot.playerX() >= 680f))
.step("Approach the lift body again", 1_500L,
LevelPlaytestBot.Input.right(),
snapshot -> snapshot.playerX() >= 730f)
@@ -190,13 +202,19 @@ final class LateLevelScenarios {
snapshot -> snapshot.playerAlive() && snapshot.playerX() < 250f)
.step("Approach the saw for the final crossing", 2_500L,
LevelPlaytestBot.Input.right(),
snapshot -> snapshot.playerX() >= 350f)
LevelPlaytestBot.whileDeathsAtMost(3,
LevelPlaytestBot.groundedAliveAtOrBeyond(280f)))
.step("Take off for the final saw crossing", 1_000L,
LevelPlaytestBot.Input.rightJump(),
snapshot -> snapshot.playerAlive() && snapshot.playerY() <= 680f)
LevelPlaytestBot.whileDeathsAtMost(3,
snapshot -> snapshot.playerAlive()
&& !snapshot.playerOnGround()
&& snapshot.playerY() <= 680f))
.step("Clear the saw for the final crossing", 2_000L,
LevelPlaytestBot.Input.right(),
snapshot -> snapshot.playerAlive() && snapshot.playerX() >= 680f)
LevelPlaytestBot.whileDeathsAtMost(3,
snapshot -> snapshot.playerAlive()
&& snapshot.playerX() >= 680f))
.step("Approach the retained lift body", 1_500L,
LevelPlaytestBot.Input.right(),
snapshot -> snapshot.playerX() >= 730f)
@@ -47,6 +47,23 @@ public final class LevelPlaytestBot {
boolean reached(GameView.AutomationSnapshot snapshot);
}
public static SnapshotCondition groundedAliveAtOrBeyond(float minimumX) {
return snapshot -> snapshot.playerAlive()
&& snapshot.playerOnGround()
&& snapshot.playerX() >= minimumX;
}
public static SnapshotCondition whileDeathsAtMost(
int maximumDeaths, SnapshotCondition completion) {
return snapshot -> {
if (snapshot.deaths() > maximumDeaths) {
throw new AssertionError("Route expected at most " + maximumDeaths
+ " deaths but observed " + snapshot.deaths());
}
return completion.reached(snapshot);
};
}
public static final class Scenario {
private final int levelNumber;
private final String name;
@@ -3,6 +3,7 @@ package com.projectsacrifice.game;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Test;
@@ -127,6 +128,40 @@ public final class LevelPlaytestBotTest {
assertFalse(snapshot.playerOnMovingPlatform());
}
@Test
public void groundedApproachWaitsForAliveGroundedPlayerAtCheckpoint() {
LevelPlaytestBot.SnapshotCondition checkpoint =
LevelPlaytestBot.groundedAliveAtOrBeyond(280f);
assertFalse(checkpoint.reached(snapshot(true, true, 279f, 1)));
assertFalse(checkpoint.reached(snapshot(false, true, 280f, 1)));
assertFalse(checkpoint.reached(snapshot(true, false, 280f, 1)));
assertTrue(checkpoint.reached(snapshot(true, true, 280f, 1)));
}
@Test
public void expectedDeathGuardFailsBeforeAnAccidentalRetry() {
LevelPlaytestBot.SnapshotCondition guarded = LevelPlaytestBot.whileDeathsAtMost(
1, snapshot -> snapshot.playerX() >= 280f);
assertTrue(guarded.reached(snapshot(true, false, 320f, 1)));
try {
guarded.reached(snapshot(false, false, 470f, 2));
fail("An accidental second death must fail the route immediately");
} catch (AssertionError expected) {
assertTrue(expected.getMessage(), expected.getMessage().contains("expected at most 1"));
assertTrue(expected.getMessage(), expected.getMessage().contains("observed 2"));
}
}
private static GameView.AutomationSnapshot snapshot(
boolean alive, boolean onGround, float x, int deaths) {
return new GameView.AutomationSnapshot(
false, alive, false, false, false,
10, 0L, x, 760f, deaths, deaths,
Float.NaN, Float.NaN, false, false, Float.NaN, onGround);
}
private static final class ScriptedDriver implements LevelPlaytestBot.Driver {
private int startedLevel;
private long nowMillis;