The clockwork plays at a watchable pace

One command per beat — 1.5 seconds, the replay's 1x cadence — each
broadcast with its board state as it lands, starting a beat after
the human's own action settles. The pump is per-room, re-entrancy
guarded, and stops the moment the maze wants a human (or the game
ends). Watching an automaton stalk your treasure across the maze is
now a spectacle instead of a teleport.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-16 16:17:28 -04:00
co-authored by Claude Fable 5
parent ab52628d2f
commit 3842307bf0
3 changed files with 129 additions and 26 deletions
+15 -19
View File
@@ -262,29 +262,25 @@ function actingSeat(room: Room): PlayerId | null {
}
/**
* Let the automatons play until the maze wants a human again. Returns the
* event batches produced, one per command, for per-step broadcasting.
* One automaton command, if the maze is waiting on clockwork. Null when a
* human holds the floor (or the game is over, or the clockwork is wedged).
*/
export function driveAutomatons(room: Room): { seat: PlayerId; events: GameEvent[] }[] {
const out: { seat: PlayerId; events: GameEvent[] }[] = [];
for (let i = 0; i < 300; i++) {
const seat = actingSeat(room);
if (!seat || !room.bots.has(seat)) break;
const view = viewFor(room.state!, seat);
const cmd = automatonCommand(view) ?? automatonFallback(view);
let r = runCommand(room, seat, cmd);
export function driveOneAutomaton(room: Room): { seat: PlayerId; events: GameEvent[] } | null {
const seat = actingSeat(room);
if (!seat || !room.bots.has(seat)) return null;
const view = viewFor(room.state!, seat);
const cmd = automatonCommand(view) ?? automatonFallback(view);
let r = runCommand(room, seat, cmd);
if ("error" in r) {
r = runCommand(room, seat, automatonFallback(view));
if ("error" in r) r = runCommand(room, seat, { type: "endTurn", draw: 0 });
if ("error" in r) r = runCommand(room, seat, { type: "pass" });
if ("error" in r) {
r = runCommand(room, seat, automatonFallback(view));
if ("error" in r) r = runCommand(room, seat, { type: "endTurn", draw: 0 });
if ("error" in r) r = runCommand(room, seat, { type: "pass" });
if ("error" in r) {
console.error(`automaton ${seat} wedged in ${room.id}: ${r.error}`);
break;
}
console.error(`automaton ${seat} wedged in ${room.id}: ${r.error}`);
return null;
}
out.push({ seat, events: r.events });
}
return out;
return { seat, events: r.events };
}
export interface GameSummary {