The automatons learn Eric's tactics: roadwork, denial, bursts, breathing room
Per the owner's briefing on how these cards are actually played: - Roadwork on the march: DISPEL CREATION un-creates conjured walls and filled squares; STONE TO WATER melts walls and stone blocks (cast only from outside its own wave); CREATE DOOR plus a lock-opener turns a wall into a doorway; DIMENSIONAL WARP folds a 6+-step detour into one step, and the bot steps through its tokens when the far side is closer. - Path denial grows: JAM LOCK seals doors on a threat's road, ILLUSION WALL stands in for CREATE WALL, the full nuisance shelf (pit, slime, ooze, rosebush, tacks, dust cloud) joins stone and thornbush, and a BOOBYTRAP lands mid-path when nothing can reroute the thief. - Bursts: ADD joins a second number to the march; MAD DASH doubles the sprint to gold (never while carrying); POWER RUN buys the last spaces of a winning delivery with blood. - Breathing room when pressed (worrier, treasure-carrier, or bleeding): FEAR at three paces, UGLY when they crowd in, BUDDY to pacify the hound. - AROUND THE CORNER: an enemy one bend out of sight can be attacked; new bentSightFor mirrors the engine's bentLos from the viewer's knowledge. - GameView gains createdEdges (public — the table watched them conjured). All newly playable cards leave the bottom discard tier via USEFUL_NEUTRALS. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
co-authored by
Claude Fable 5
parent
4e14926c0c
commit
4bda6087b1
@@ -181,7 +181,7 @@ describe("a clogged hand gets shed, not hoarded", () => {
|
||||
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" }
|
||||
{ instanceId: `rotate-sector#${i}`, cardId: "rotate-sector" }
|
||||
));
|
||||
// Walk the bot's turn until it wants to end: it must shed before drawing.
|
||||
for (let guard = 0; guard < 30; guard++) {
|
||||
@@ -244,9 +244,9 @@ describe("the clockwork wields destroy wall", () => {
|
||||
const bot = state.players.find((p) => p.id === "bot")!;
|
||||
bot.hand = [
|
||||
{ instanceId: "destroy-wall#T", cardId: "destroy-wall" },
|
||||
{ instanceId: "buddy#T", cardId: "buddy" },
|
||||
{ instanceId: "ugly#T", cardId: "ugly" },
|
||||
{ instanceId: "fear#T", cardId: "fear" },
|
||||
{ instanceId: "trader#T", cardId: "trader" },
|
||||
{ instanceId: "strength#T", cardId: "strength" },
|
||||
{ instanceId: "adrenaline#T", cardId: "adrenaline" },
|
||||
{ instanceId: "full-shield#T", cardId: "full-shield" },
|
||||
{ instanceId: "fireball#T", cardId: "fireball" },
|
||||
{ instanceId: "number-3#T", cardId: "number-3" },
|
||||
@@ -330,3 +330,47 @@ describe("the clockwork denies the road", () => {
|
||||
expect(target.cell.x).toBe(4);
|
||||
});
|
||||
});
|
||||
|
||||
describe("the widened spellbook", () => {
|
||||
it("dispels a conjured wall standing between it and the only road", () => {
|
||||
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"], deckRev: 24 });
|
||||
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")!;
|
||||
bot.position = { x: 4, y: 4 };
|
||||
for (const side of ["N", "S", "E", "W"] as const) {
|
||||
const k = edgeKey(bot.position, side);
|
||||
state.edgeOverrides[k] = "wall";
|
||||
state.createdEdges[k] = true;
|
||||
}
|
||||
state.players.find((p) => p.id === "other")!.position = { x: 0, y: 0 };
|
||||
bot.hand = [{ instanceId: "dispel-creation#T", cardId: "dispel-creation" }];
|
||||
const cmd = automatonCommand(viewFor(state, "bot"), "hunter", "archmage");
|
||||
expect(cmd).toMatchObject({ type: "cast", instanceId: "dispel-creation#T" });
|
||||
const r = applyCommand(state, "bot", cmd!);
|
||||
if (!r.ok) throw new Error(r.error);
|
||||
});
|
||||
|
||||
it("offers a buddy pact to the hound at its heels", () => {
|
||||
let { state } = createGame({ playerIds: ["bot", "other"], seed: 42, sets: ["basic", "expansion1"], deckRev: 24 });
|
||||
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")!;
|
||||
const hound = state.players.find((p) => p.id === "other")!;
|
||||
hound.position = { ...bot.position };
|
||||
bot.hand = [{ instanceId: "buddy#T", cardId: "buddy" }];
|
||||
const cmd = automatonCommand(viewFor(state, "bot"), "worrier", "archmage");
|
||||
expect(cmd).toEqual({
|
||||
type: "cast", instanceId: "buddy#T",
|
||||
target: { kind: "player", playerId: "other" },
|
||||
});
|
||||
const r = applyCommand(state, "bot", cmd!);
|
||||
if (!r.ok) throw new Error(r.error);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user