The RNRX coma: tacks are scattered, not thrown
Automaton II froze for three turns of game four: pathDenial proposed
HANDFUL OF TACKS on a square four steps away, the engine refused the
cast every turn ("you must be adjacent to scatter tacks"), and the
refusal-fallback loop read as a coma. The denial planner now offers
tacks only at the caster's feet — and the walker learns tacks are a
floor hazard, so a bot no longer mines its own doorstep and strolls
straight into it (also RNRX, seq 194-195). The frozen ledger moment
replays cured; a regression pins the planner's proposals to
engine-accepted commands. 288 tests; 24 ledgers verified.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
co-authored by
Claude Fable 5
parent
6d88b35516
commit
75f1217c77
@@ -370,7 +370,12 @@ function pathDenial(view: GameView): Command | null {
|
||||
);
|
||||
}
|
||||
// Never brick the square the treasure needs to stay reachable on.
|
||||
if (filler && cellKey(b) !== cellKey(goal) && cellCastable(cellKey(b))) {
|
||||
// TACKS are scattered at the caster's feet ("you must be adjacent"),
|
||||
// not thrown — offering a distant square wedges the whole brain on
|
||||
// an eternally refused cast.
|
||||
const fillerReaches = !filler || filler.cardId !== "handful-of-tacks" ||
|
||||
Math.abs(b.x - me(view).position.x) + Math.abs(b.y - me(view).position.y) <= 1;
|
||||
if (filler && fillerReaches && cellKey(b) !== cellKey(goal) && cellCastable(cellKey(b))) {
|
||||
consider(
|
||||
{ type: "cast", instanceId: filler.instanceId, target: { kind: "cell", cell: b } },
|
||||
{ avoidCell: cellKey(b) },
|
||||
@@ -609,7 +614,7 @@ function pathToward(
|
||||
const hazard = view.squareContents[k]?.kind;
|
||||
if (!opts.throughHazards &&
|
||||
(hazard === "pit" || hazard === "ooze" || hazard === "thornbush" ||
|
||||
hazard === "rosebush" || hazard === "slime")) continue;
|
||||
hazard === "rosebush" || hazard === "slime" || hazard === "tacks")) continue;
|
||||
if (opts.avoidNearEnemies && nearEnemy(to)) continue;
|
||||
next.push(to);
|
||||
}
|
||||
|
||||
@@ -922,3 +922,35 @@ describe("lessons from the human duels", () => {
|
||||
expect(cmd).toMatchObject({ type: "cast", instanceId: "LB" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("the denial planner offers only castable blocks", () => {
|
||||
it("tacks at range are never proposed — the RNRX coma", () => {
|
||||
// Room RNRX froze Automaton II for three turns: pathDenial proposed
|
||||
// scattering tacks four squares away, the engine refused ("you must
|
||||
// be adjacent"), and the refusal-fallback loop read as a coma.
|
||||
let { state } = createGame({ playerIds: ["foe", "bot"], seed: 42, sets: ["basic", "expansion1"] });
|
||||
while (state.turn.round < 2 || state.players[state.turn.activeIndex]!.id !== "bot") {
|
||||
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
|
||||
if (!r.ok) throw new Error(r.error);
|
||||
state = r.state;
|
||||
}
|
||||
const bot = state.players.find((p) => p.id === "bot")!;
|
||||
const foe = state.players.find((p) => p.id === "foe")!;
|
||||
// The bot's floor gold with a raider closing on it, and only TACKS
|
||||
// in hand to deny the road — from a stand-off distance.
|
||||
const gold = state.treasures.find((t) => t.owner === "bot" && t.position)!;
|
||||
foe.position = { ...gold.position! };
|
||||
bot.position = { ...bot.home };
|
||||
bot.hand = [{ cardId: "handful-of-tacks", instanceId: "HT" } as never];
|
||||
for (let guard = 0; guard < 6; guard++) {
|
||||
const cmd = automatonCommand(viewFor(state, "bot"), "hunter", "archmage");
|
||||
if (!cmd) break;
|
||||
const r = applyCommand(state, "bot", cmd);
|
||||
// Whatever the brain proposes, the engine must accept it.
|
||||
expect(r.ok, `refused: ${JSON.stringify(cmd)} — ${!r.ok ? r.error : ""}`).toBe(true);
|
||||
if (!r.ok) break;
|
||||
state = r.state;
|
||||
if (cmd.type === "endTurn") break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user