A game told: twenty-seven written moves stepped through on the boards with a callout wherever there is something to see, and a composer to write the next one

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCLa2PaEeCj8njQZSWGqHx
This commit is contained in:
Eric WagonerandClaude Fable 5.1 committed 2026-10-26 18:38:59 -04:00
1 parent c8443c6f50
commit 965a28142c
7 files changed
+298 -4

No files matched your search

+36
View File
@@ -0,0 +1,36 @@
// Composes the told game (src/lib/game/told.ts): its moves are played at
// their plies and the drake plays any ply beyond them, so a longer game can
// be sketched and steered. Prints the chronicle, and with a ply and a
// square, the legal moves of the piece there at that ply.
// npx tsx docs/compose-game.ts [plies] [ply square]
import { createGame, applyMove, validateMove } from '../src/lib/game/index.ts';
import { chooseMove } from '../src/lib/game/bot.ts';
import { narrate } from '../src/lib/game/chronicle.ts';
import { square, squareName, legalMovesFrom, type Side } from '../src/lib/game/board.ts';
import { TOLD_MOVES } from '../src/lib/game/told.ts';
const FORCED: Record<number, [string, string]> = Object.fromEntries(TOLD_MOVES.map((m, n) => [n + 1, m]));
const plies = Number(process.argv[2] ?? 40);
const askPly = process.argv[3] ? Number(process.argv[3]) : 0;
const askSquare = process.argv[4];
let s = createGame({ A: 'Gold', B: 'Scarlet' });
for (let ply = 1; ply <= plies && !s.over; ply++) {
const seat = s.toMove === 'gold' ? 'A' : 'B';
if (ply === askPly && askSquare) {
console.log(`ply ${ply}, ${s.toMove} to move, ${askSquare} may go to: ${legalMovesFrom(s.cells, square(askSquare), 'printed').map(squareName).join(' ')}`);
process.exit(0);
}
const forced = FORCED[ply];
let move: { from: number; to: number };
if (forced) {
move = { from: square(forced[0]), to: square(forced[1]) };
const why = validateMove(s, seat, move);
if (why) {
console.log(`ply ${ply}: forced ${forced[0]}-${forced[1]} refused: ${why}`);
process.exit(1);
}
} else move = chooseMove(s.cells, s.toMove as Side, 'printed', 40000)!;
s = applyMove(s, move.from, move.to);
}
for (const t of narrate(s)) console.log(`${t.ply}${FORCED[t.ply] ? '*' : ' '} ${t.lines.map((l) => l.text).join(' ')}`);
console.log(s.over ? `over: ${s.over.reason}` : `${s.toMove} to move`);