Engine: the facade re-exports the board in one block; describe() and the dead letters preference, void ply, the King-taken line, the identity maps and the unused imports are gone; SIDE_NAMES is the one spelling of a side; the drake's hunter comment no longer claims only four kinds reach the air. Prose: no shatranj and no sitting duck, which Gygax never wrote; the Thief statistic and the Basilisk's "one trick" are gone; lessons say what the board shows instead of repeating the panel; a Thief's leap counts four. Browser: one keyboard walk, in BoardArtwork; the lesson board and page share one game and one inspected piece; the chronicle's possessive is told, not patched by a regex; the chronicle colours and the reading layout are global rules instead of three copies; the guide and the about panel say what the code and the article actually do. Server and docs: the room server states that it is the kit's, kept whole; the skills, the deploy README and the share card name files that exist. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CCLa2PaEeCj8njQZSWGqHx
37 lines
1.8 KiB
TypeScript
37 lines
1.8 KiB
TypeScript
// 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 } 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), s.setup).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, s.setup, 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`);
|