Learn the pieces: fifteen scenes and a checkmate, each a small position with a move to make and a word on what came of it

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:30:55 -04:00
1 parent 808c27e5d3
commit c8443c6f50
7 files changed
+595 -2

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
import { describe, expect, it } from 'vitest';
import { SCENES, sceneCells } from './lessons';
import { frozen, hasLegalMove, inCheck, kindOf, legalMovesFrom, movesFrom, other, playOn, square } from './board';
describe('the lessons', () => {
it('every scene’s move is legal for the side to move, and only the asked-for moves count', () => {
for (const scene of SCENES) {
const cells = sceneCells(scene);
for (const [from, to] of scene.moves) {
const legal = legalMovesFrom(cells, square(from), 'printed');
expect(legal, `${scene.id}: ${from} to ${to}`).toContain(square(to));
}
// The piece asked for is the player's.
for (const [from] of scene.moves) expect(cells[square(from)][0], scene.id).toBe(scene.side === 'gold' ? 'g' : 's');
// The scene draws every board its move touches.
for (const [from, to] of scene.moves) {
expect(scene.levels, scene.id).toContain(Number(from[0]));
expect(scene.levels, scene.id).toContain(Number(to[0]));
}
}
});
it('the scenes do what their words say', () => {
const at = (id: string) => SCENES.find((s) => s.id === id)!;
const play = (id: string) => {
const s = at(id);
const cells = sceneCells(s);
const [from, to] = s.moves[0];
return { cells, after: playOn(cells, square(from), square(to)), s };
};
// The Warrior's step is blocked and its capture is not.
expect(movesFrom(sceneCells(at('warrior')), square('2c2')).map((i) => i)).toEqual([square('2d3')]);
// The Hero leaps the Warrior and takes the Mage.
expect(play('hero').after.captured).toBe('M');
// The Mage comes down two boards onto the Basilisk.
expect(play('mage').after.captured).toBe('B');
// The Paladin vaults over the Dwarf at 1c5.
expect(play('paladin').after.captured).toBe('D');
// The Sylph's dive and the Dragon's strike take what they say.
expect(play('sylph').after.captured).toBe('O');
const dragon = play('dragon');
expect(dragon.after.afar).toBe(true);
expect(dragon.after.captured).toBe('M');
expect(dragon.after.cells[square('3c4')]).toBe('gR');
// The Basilisk's arrival freezes the Mage above.
const basilisk = play('basilisk');
expect(frozen(basilisk.after.cells, square('2e4'))).toBe(true);
expect(movesFrom(basilisk.after.cells, square('2e4'))).toEqual([]);
// The Elemental climbs onto the Thief.
expect(play('elemental').after.captured).toBe('T');
// The King is in check before it moves, and out of it after either move; up or down leaves it off the land.
const king = sceneCells(at('king'));
expect(inCheck(king, 'gold')).toBe(true);
expect(legalMovesFrom(king, square('2g1'), 'printed').map((i) => i).sort()).toEqual([square('1g1'), square('2f1'), square('2h1'), square('3g1')].sort());
// The last scene is mate in one, and only that move mates.
const mate = play('mate');
expect(inCheck(mate.after.cells, 'scarlet')).toBe(true);
expect(hasLegalMove(mate.after.cells, 'scarlet', 'printed')).toBe(false);
expect(kindOf(mate.cells[square('2d4')])).toBe('K');
expect(frozen(mate.cells, square('2d4'))).toBe(true);
void other;
});
});