The clockwork learns to shed a dead hand — if its tier knows how
Two archmages idled turn after turn: hands clogged with situational neutrals, and doEndTurn caps the draw by the room left, so a full hand never refreshed. Nothing to cast, nothing to draw, nothing done. The brain now sheds dead weight before ending the turn — only cards it has no play for; good counters and attacks stay hoarded — so the draw always has room. The trick is repertoire, so it is tier-gated: adepts and archmages churn, the apprentice hoards like the novice it is. Measured across forty berserker mirrors that sharpened the handicap from two-to-one to three-to-one with zero stalled games. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
9493873b64
commit
ef5336caa8
@@ -123,10 +123,13 @@ describe("the clockwork does not waste counters on pointless targets", () => {
|
||||
// burn round 1
|
||||
for (let i = 0; i < 2; i++) {
|
||||
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
|
||||
if (!r.ok) throw new Error(`setup: ${r.error}`);
|
||||
state = r.state;
|
||||
}
|
||||
while (actingSeat(state) !== "human") {
|
||||
state = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 }).state;
|
||||
const r = applyCommand(state, actingSeat(state), { type: "endTurn", draw: 0 });
|
||||
if (!r.ok) throw new Error(`setup: ${r.error}`);
|
||||
state = r.state;
|
||||
}
|
||||
const human = state.players.find((p: { id: string }) => p.id === "human")!;
|
||||
const bot = state.players.find((p: { id: string }) => p.id === "bot")!;
|
||||
@@ -165,3 +168,38 @@ describe("the clockwork does not waste counters on pointless targets", () => {
|
||||
expect(cmd).toEqual({ type: "counteract", instanceId: "full-shield#T" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("a clogged hand gets shed, not hoarded", () => {
|
||||
it("the bot discards dead weight so the end-of-turn draw has room", () => {
|
||||
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic"], deckRev: 13 });
|
||||
while (actingSeat(state) !== "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")!;
|
||||
// Seven situational neutrals the brain has no play for: a dead hand.
|
||||
bot.hand = Array.from({ length: 7 }, (_, i) => (
|
||||
{ instanceId: `illusion-wall#${i}`, cardId: "illusion-wall" }
|
||||
));
|
||||
// Walk the bot's turn until it wants to end: it must shed before drawing.
|
||||
for (let guard = 0; guard < 30; guard++) {
|
||||
const view = viewFor(state, "bot");
|
||||
const cmd = automatonCommand(view, "hunter", "archmage")!;
|
||||
if (cmd.type === "discard") {
|
||||
expect(cmd.instanceIds.length).toBe(2);
|
||||
const r = applyCommand(state, "bot", cmd);
|
||||
if (!r.ok) throw new Error(r.error);
|
||||
state = r.state;
|
||||
const next = automatonCommand(viewFor(state, "bot"), "hunter", "archmage")!;
|
||||
expect(next).toEqual({ type: "endTurn", draw: 2 });
|
||||
return;
|
||||
}
|
||||
if (cmd.type === "endTurn") throw new Error("ended the turn without shedding a dead hand");
|
||||
const r = applyCommand(state, "bot", cmd);
|
||||
if (!r.ok) throw new Error(`${cmd.type}: ${r.error}`);
|
||||
state = r.state;
|
||||
}
|
||||
throw new Error("never reached the end of the turn");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user