Initialize Project Sacrifice backlog and source baseline

This commit is contained in:
2026-08-18 00:46:42 +03:00
parent d28ea8c3fd
commit 29d4a2d8d8
34 changed files with 4630 additions and 151 deletions
@@ -0,0 +1,91 @@
package com.projectsacrifice.game;
/**
* Black-box playtest bot for the fifth level. It operates through the same input
* flags used by touch controls and observes only player-visible session state.
*/
public final class LevelPlaytestBot {
public interface Driver {
void startLevel(int oneBasedLevelNumber);
void setInput(boolean moveLeft, boolean moveRight, boolean jump);
GameView.AutomationSnapshot snapshot();
void waitForNextDecision(long millis);
}
public static final class Result {
private final boolean completed;
private final boolean doorOpened;
private final int deaths;
private final int corpseCount;
private final String diagnostic;
Result(boolean completed, boolean doorOpened, int deaths, int corpseCount, String diagnostic) {
this.completed = completed;
this.doorOpened = doorOpened;
this.deaths = deaths;
this.corpseCount = corpseCount;
this.diagnostic = diagnostic;
}
public boolean completed() { return completed; }
public boolean doorOpened() { return doorOpened; }
public int deaths() { return deaths; }
public int corpseCount() { return corpseCount; }
public String diagnostic() { return diagnostic; }
}
public Result proveLevelFive(Driver driver, long timeoutMillis) {
driver.startLevel(5);
long deadline = System.currentTimeMillis() + timeoutMillis;
boolean doorOpened = false;
int jumpStage = 0;
int respawnsAfterSacrifice = 0;
boolean wasAlive = true;
GameView.AutomationSnapshot last = driver.snapshot();
while (System.currentTimeMillis() < deadline) {
last = driver.snapshot();
doorOpened |= last.allDoorsOpen();
if (last.completed()) {
driver.setInput(false, false, false);
return new Result(true, doorOpened, last.deaths(), last.corpseCount(),
"Level 5 completed by bot: deaths=" + last.deaths()
+ ", corpses=" + last.corpseCount() + ", doorOpened=" + doorOpened);
}
if (!last.playerAlive()) {
driver.setInput(false, false, false);
wasAlive = false;
} else if (last.deaths() == 0) {
driver.setInput(false, true, false);
} else if (!doorOpened) {
driver.setInput(false, false, false);
} else {
if (!wasAlive) {
respawnsAfterSacrifice++;
jumpStage = 0;
}
if (jumpStage == 0 && last.playerX() < 390f) {
driver.setInput(false, true, false);
} else if (jumpStage == 0) {
driver.setInput(false, true, true);
jumpStage = 1;
} else if (jumpStage == 1 && last.playerX() >= 750f) {
driver.setInput(false, true, true);
jumpStage = 2;
} else {
driver.setInput(false, true, false);
}
wasAlive = true;
}
driver.waitForNextDecision(32L);
}
driver.setInput(false, false, false);
return new Result(false, doorOpened, last.deaths(), last.corpseCount(),
"Bot timed out on level 5: x=" + last.playerX() + ", y=" + last.playerY()
+ ", alive=" + last.playerAlive() + ", deaths=" + last.deaths()
+ ", corpses=" + last.corpseCount() + ", doorOpened=" + doorOpened
+ ", respawnsAfterSacrifice=" + respawnsAfterSacrifice);
}
}