The clockwork learns three lessons from losing to Kestrel

Game six's table play, distilled into rungs. LOCK IN PLACE now roots
an enemy carrier closing on their home — the tempo theft that opened
game five, turned against the table. A pressed carrier of ANY
temperament casts MIST-BODY with its biggest number: an untouchable
delivery beats fear's radius, as the winning heist demonstrated. And
the pathfinder learns the thornbush is a jail, not a wade — entering
ends the turn, eats the next, and stings — so only a wizard with no
road at all dives in ("few will dive into one unless they are
desperate"). Also acquits Automaton II of game-six dithering: replay
showed its loop-de-loop was the true 13-step shortest path through a
walled quadrant.

Brains ship ungated; all 28 ledgers replay clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
Eric Wagoner
2026-08-27 21:53:47 -04:00
co-authored by Claude Fable 5
parent 3c70b9aedc
commit cbd4d80dea
2 changed files with 123 additions and 3 deletions
+40 -3
View File
@@ -586,7 +586,7 @@ function pathToward(
view: GameView,
from: Cell,
goals: Set<string>,
opts: { avoidNearEnemies?: boolean; canUnlock?: boolean; throughHazards?: boolean } = {},
opts: { avoidNearEnemies?: boolean; canUnlock?: boolean; throughHazards?: boolean; throughJails?: boolean } = {},
): PathResult | null {
if (goals.size === 0 || goals.has(cellKey(from))) return null;
const enemyCells = livingEnemies(view).map((p) => p.position);
@@ -611,9 +611,14 @@ function pathToward(
cameBy.set(k, { prev: cellKey(c), dir, viaDoor });
if (goals.has(k)) { found = k; break; }
// Hazards end a clean path but are waded through when asked to.
// THORNBUSH is never a wade: entering ends the turn, eats the NEXT
// turn, and stings — a jail with foliage. Only a wizard with no
// road at all (throughJails) dives in. "Few will dive into one
// unless they are desperate."
const hazard = view.squareContents[k]?.kind;
if (hazard === "thornbush" && !opts.throughJails) continue;
if (!opts.throughHazards &&
(hazard === "pit" || hazard === "ooze" || hazard === "thornbush" ||
(hazard === "pit" || hazard === "ooze" ||
hazard === "rosebush" || hazard === "slime" || hazard === "tacks")) continue;
if (opts.avoidNearEnemies && nearEnemy(to)) continue;
next.push(to);
@@ -1100,6 +1105,19 @@ function selfCare(view: GameView, style: AutomatonStyle, tier: TierTraits): Comm
// wizard hauling gold, anyone bleeding out.
const pressed = enemyNear &&
(style === "worrier" || self.carriedTreasureId != null || self.life <= 5);
// MIST-BODY turns a pressed carrier into an untouchable delivery — no
// attack, drop, exile, or thief finds fog. Any temperament takes this
// armor, and the biggest number rides it so the whole haul fits inside.
if (pressed && self.carriedTreasureId) {
const fog = inHand(view, "mist-body");
if (fog && !view.sustained.some((s) => s.cardId === "mist-body" && s.targetId === view.you)) {
const biggest = numbersInHand(view).at(-1);
return {
type: "cast", instanceId: fog.instanceId,
...(biggest ? { numberInstanceIds: [biggest.instanceId] } : {}),
};
}
}
if (pressed && style !== "berserker") {
// FEAR keeps every pursuer three spaces off.
const scare = inHand(view, "fear");
@@ -1367,6 +1385,22 @@ export function automatonCommand(
};
}
}
// LOCK IN PLACE roots a delivery mid-stride: a carrier closing on
// their home loses a whole turn of legs and warp-steps.
{
const root = inHand(view, "lock-in-place");
const runner = root ? visible.find((p) =>
p.carriedTreasureId != null &&
Math.abs(p.position.x - p.home.x) + Math.abs(p.position.y - p.home.y) <= 7) : undefined;
if (root && runner) {
const smallest = numbersInHand(view)[0];
return {
type: "cast", instanceId: root.instanceId,
target: { kind: "player", playerId: runner.id },
...(smallest ? { numberInstanceIds: [smallest.instanceId] } : {}),
};
}
}
if (tier.buffs && !view.turn.attackUsed) {
const smallest = numbersInHand(view)[0];
// ADRENALINE: when no single blow finishes the target but two would.
@@ -1575,7 +1609,10 @@ export function automatonCommand(
pathToward(view, self.position, enemyCells, { canUnlock }) ??
// No clean road to anything: grit the teeth and wade the hazards,
// as any wizard would rather than stand in a pocket forever.
pathToward(view, self.position, enemyCells, { canUnlock, throughHazards: true });
pathToward(view, self.position, enemyCells, { canUnlock, throughHazards: true }) ??
// And only when even the hazard roads are severed does desperation
// dive through a thornbush jail.
pathToward(view, self.position, objectives, { canUnlock, throughHazards: true, throughJails: true });
// A shimmering illusion on the best crossing costs nothing to doubt:
// roll the free test before spending any card on that wall.
const doubted = bestWallCrossing(view, self, objectives, canUnlock);