Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CCLa2PaEeCj8njQZSWGqHx
233 lines
16 KiB
TypeScript
233 lines
16 KiB
TypeScript
// The lessons: one scene a piece, each a small position with something to
|
||
// see and a move to make. The page shows the boards the scene needs, says
|
||
// what to look at, takes the move from the player, and tells what came of
|
||
// it. Every scene's move is checked legal by a test, and every claim in
|
||
// the words is checked against board.ts there too.
|
||
|
||
import { type Cell, type Side, CELLS, square } from './board';
|
||
|
||
export interface Scene {
|
||
id: string;
|
||
title: string;
|
||
/** The pieces, by square name. Kings are added at 2l1 and 2a8 where the scene gives none. */
|
||
pieces: Record<string, Cell>;
|
||
/** Whose move it is: the player's side. */
|
||
side: Side;
|
||
/** The boards to draw, top first. */
|
||
levels: number[];
|
||
/** What to look at before moving. */
|
||
before: string;
|
||
/** The move to make, in the player's words. */
|
||
task: string;
|
||
/** The move itself, from and to; any of these counts. */
|
||
moves: [string, string][];
|
||
/** What came of it. */
|
||
after: string;
|
||
/** Said when a legal move is made that is not the one to look at. */
|
||
aside?: string;
|
||
}
|
||
|
||
export const SCENES: Scene[] = [
|
||
{
|
||
id: 'warrior',
|
||
title: 'The Warrior',
|
||
pieces: { '2c2': 'gW', '2d3': 'sW', '2c3': 'sU' },
|
||
side: 'gold',
|
||
levels: [2],
|
||
before: 'Twelve of these stand in a wall at the start. A Warrior steps one square straight ahead, never two, and takes one square diagonally ahead, as a pawn does. The Unicorn at 2c3 blocks this one’s step, but the Warrior at 2d3 is on its diagonal.',
|
||
task: 'Take the Scarlet Warrior. Tap your Warrior at 2c2, then 2d3.',
|
||
moves: [['2c2', '2d3']],
|
||
after: 'The Warrior falls, and yours stands on the d file now. A Warrior that reaches the far rank stands up a Hero, with no choice about it, which is a real gain but not a queen. There is no double step and no capture in passing, because Gygax limited the Warrior to the old single step of shatranj, and so every advance is a commitment.',
|
||
aside: 'That is a legal move, but the Warrior at 2d3 is the one to take. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'oliphant',
|
||
title: 'The Oliphant',
|
||
pieces: { '2a1': 'gO', '2a6': 'sT', '2d1': 'gT' },
|
||
side: 'gold',
|
||
levels: [2],
|
||
before: 'The war elephant is a rook by another name. It runs any distance along a rank or a file while the way is clear, and never leaves the land. The a file is open from your corner to the Thief at 2a6.',
|
||
task: 'Take the Thief. Tap the Oliphant at 2a1, then 2a6.',
|
||
moves: [['2a1', '2a6']],
|
||
after: 'On a board twelve squares wide an open file runs a long way, and the Oliphant is the piece that owns it. Remember what the sky can do, though: an Oliphant standing on the land beneath an enemy Dragon is as good as lost, because it cannot strike back upward.',
|
||
aside: 'A legal move, but the Thief at 2a6 is the one to take. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'unicorn',
|
||
title: 'The Unicorn',
|
||
pieces: { '2b1': 'gU', '2a2': 'gW', '2b2': 'gW', '2c2': 'gW', '2c3': 'sT' },
|
||
side: 'gold',
|
||
levels: [2],
|
||
before: 'A knight, and the only piece of the land that leaps. Your Warriors wall it in, and the Unicorn does not care. It goes one square along a rank or file and one diagonally outward, over whatever is between.',
|
||
task: 'Leap the wall and take the Thief at 2c3. Tap the Unicorn, then 2c3.',
|
||
moves: [['2b1', '2c3']],
|
||
after: 'The Thief is gone and the wall never moved. Early in a game the Unicorns are the pieces to bring out first, for just this reason. Gygax rates them low, below a Basilisk, because a knight is slow on so wide a board, so trade one gladly for a Hero or a Thief.',
|
||
aside: 'A legal move, but the leap to 2c3 is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'thief',
|
||
title: 'The Thief',
|
||
pieces: { '2d1': 'gT', '2h5': 'sO' },
|
||
side: 'gold',
|
||
levels: [2],
|
||
before: 'The bishop of the land, quick along the diagonals. From 2d1 the diagonal runs e2, f3, g4 and on to the Oliphant at 2h5, with nothing in the way.',
|
||
task: 'Take the Oliphant. Tap the Thief, then 2h5.',
|
||
moves: [['2d1', '2h5']],
|
||
after: 'Five squares in one move, and a five-point piece for a four-point one. A Thief’s work is in the middle ranks, which is where the Dragon hunts from the air, so it is the piece most often lost to a strike from above. Two Thieves cover both colours of square.',
|
||
aside: 'A legal move, but the Oliphant at 2h5 is the one to take. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'hero',
|
||
title: 'The Hero',
|
||
pieces: { '2c1': 'gH', '2d2': 'gW', '2e3': 'sM' },
|
||
side: 'gold',
|
||
levels: [2],
|
||
before: 'A champion who goes one or two squares along a diagonal and leaps the square between. Your own Warrior stands at 2d2, in the way of nothing. Beyond it, the Scarlet Mage.',
|
||
task: 'Leap over the Warrior and take the Mage at 2e3. Tap the Hero, then 2e3.',
|
||
moves: [['2c1', '2e3']],
|
||
after: 'The Mage, worth eleven, to a Hero worth four and a half. The Hero can also rise to the air or drop to the underworld, onto any of the four squares diagonally beside the square above or below it, and take a piece as it goes. Off the land its only move is back, so it goes up to kill and comes straight home.',
|
||
aside: 'A legal move, but the leap to 2e3 is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'cleric',
|
||
title: 'The Cleric',
|
||
pieces: { '2e4': 'gC', '3e4': 'sS' },
|
||
side: 'gold',
|
||
levels: [3, 2],
|
||
before: 'The one piece at home on every board. It moves one square in any direction wherever it stands, and it can step straight up or down to the board above or below. A Scarlet Sylph hovers directly over it.',
|
||
task: 'Step up into the air and take the Sylph. Tap the Cleric, then 3e4 on the upper board.',
|
||
moves: [['2e4', '3e4']],
|
||
after: 'The Cleric is in the air now and moves there exactly as it did on the land. Gygax says not to underestimate it. Of the five kinds of piece that can visit all three boards, it is the only one that plays the same on each, and he values it at nine, above the Dragon.',
|
||
aside: 'A legal move, but the step up to 3e4 is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'mage',
|
||
title: 'The Mage',
|
||
pieces: { '3c4': 'gM', '1c4': 'sB' },
|
||
side: 'gold',
|
||
levels: [3, 2, 1],
|
||
before: 'On the land the Mage is a queen. Here it is in the air, where it can only step one square along a rank or file, or move straight up or down. Straight down two boards is the underworld, and a Scarlet Basilisk sits there at 1c4. The land square between, 2c4, is empty, and it has to be: the Mage does not vault.',
|
||
task: 'Descend two boards and take the Basilisk. Tap the Mage, then 1c4 on the lowest board.',
|
||
moves: [['3c4', '1c4']],
|
||
after: 'The Basilisk is crushed and the Mage stands in the underworld, where it is a shadow of itself, one step at a time. Gygax warns against bringing the Mage out early, since lesser pieces develop by chasing it. Use its moves between boards to escape, and seldom to visit.',
|
||
aside: 'A legal move, but the drop to 1c4 is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'paladin',
|
||
title: 'The Paladin',
|
||
pieces: { '2c4': 'gP', '1c6': 'sD', '1c5': 'sD' },
|
||
side: 'gold',
|
||
levels: [2, 1],
|
||
before: 'On the land the Paladin has the king’s step and the knight’s leap together. Between boards it leaps the way a knight does, one board up or down and two squares along a rank or file, or two boards and one square, over anything in the way. Two Dwarves wait below.',
|
||
task: 'Vault down to the underworld and take the Dwarf at 1c6. Tap the Paladin, then 1c6.',
|
||
moves: [['2c4', '1c6']],
|
||
after: 'One board down and two squares forward, over the Dwarf at 1c5, which never had a say. In the underworld the Paladin keeps only the king’s step. Worth ten by Gygax’s count, it is the piece that can be on any board from any other in one move, and he counsels keeping it back until the lesser pieces are out.',
|
||
aside: 'A legal move, but the vault to 1c6 is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'sylph',
|
||
title: 'The Sylph',
|
||
pieces: { '3e4': 'gS', '2e4': 'sO', '3e5': 'sW' },
|
||
side: 'gold',
|
||
levels: [3, 2],
|
||
before: 'A pawn turned inside out. In the air the Sylph drifts one square diagonally forward and captures by stepping straight ahead, so the Warrior at 3e5 is in its sights. But look down: a Scarlet Oliphant stands on the land directly beneath it, and a Sylph can strike straight down.',
|
||
task: 'Dive and take the Oliphant on the land. Tap the Sylph, then 2e4 on the middle board.',
|
||
moves: [['3e4', '2e4']],
|
||
after: 'A one-point piece has taken a five-point one. Now the Sylph is grounded. On the land it cannot move at all except to rise again, to the square above it or to any empty square the Sylphs began on, and it takes nothing on the way up. Spend them this way and climb them home.',
|
||
aside: 'A legal move, but the dive onto the Oliphant at 2e4 is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'griffon',
|
||
title: 'The Griffon',
|
||
pieces: { '3d4': 'gG', '2e5': 'sT', '3f7': 'sW' },
|
||
side: 'gold',
|
||
levels: [3, 2],
|
||
before: 'Half eagle and half lion. In the air the Griffon leaps two squares one way and three the other, so the Warrior at 3f7 is one leap away. It can also swoop to the land, onto any of the four squares diagonally beside the square beneath it. The Thief at 2e5 is one of those four.',
|
||
task: 'Swoop down and take the Thief. Tap the Griffon, then 2e5 on the middle board.',
|
||
moves: [['3d4', '2e5']],
|
||
after: 'The Thief is gone, and the Griffon is on the land, where it has lost its wings and creeps one square diagonally until it climbs back. Drop to pick off a defender and climb before the land can gather. In the air it is worth a little more than a Hero, and nothing on the land sees its leap coming.',
|
||
aside: 'A legal move, but the swoop onto the Thief at 2e5 is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'dragon',
|
||
title: 'The Dragon',
|
||
pieces: { '3c4': 'gR', '2d4': 'sM', '2c4': 'sW' },
|
||
side: 'gold',
|
||
levels: [3, 2],
|
||
before: 'The wyrm never leaves the air. It slides the diagonals and steps one square in any direction, and it strikes from afar: without moving, it can take an enemy on the land directly beneath it or on any of the four squares beside that one. Beneath it at 2c4 stands a Warrior, and beside that, at 2d4, the Scarlet Mage.',
|
||
task: 'Strike the Mage from afar. Tap the Dragon, then 2d4 on the middle board.',
|
||
moves: [['3c4', '2d4']],
|
||
after: 'The Mage is lifted from the land and the Dragon has not moved. That strike was its whole move. Gygax set each Dragon directly over its King for this reason: a Dragon at home is a roof over the five squares beneath it, and a Dragon that flies off to hunt leaves its King under the other Dragon’s shadow.',
|
||
aside: 'A legal move, but the strike at the Mage on 2d4 is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'dwarf',
|
||
title: 'The Dwarf',
|
||
pieces: { '1d4': 'gD', '2d4': 'sH', '1e5': 'sW' },
|
||
side: 'gold',
|
||
levels: [2, 1],
|
||
before: 'A miner of the underworld. It walks one square forward or sideways without taking, and takes one square diagonally ahead, so the Warrior at 1e5 is in reach. It can also strike straight up at the land. A Scarlet Hero has stopped at 2d4, directly over it.',
|
||
task: 'Burst up and take the Hero. Tap the Dwarf, then 2d4 on the middle board.',
|
||
moves: [['1d4', '2d4']],
|
||
after: 'A Dwarf is a mine beneath the land, and a piece that settles above one is taken. On the land it keeps the same moves, and it comes back down only onto an empty square beneath it. Gygax says the Dwarves play little part early, and make the best outposts late, if you have not hurried them forward.',
|
||
aside: 'A legal move, but the strike up at the Hero on 2d4 is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'basilisk',
|
||
title: 'The Basilisk',
|
||
pieces: { '1e3': 'gB', '2e4': 'sM', '2h7': 'sK' },
|
||
side: 'gold',
|
||
levels: [2, 1],
|
||
before: 'The serpent whose gaze turns to stone. A Basilisk moves one square forward or diagonally forward, taking what is there, or one square straight back, and never leaves the underworld. Whatever enemy stands on the land directly above it cannot move, take or threaten anything. The Scarlet Mage stands at 2e4. The square beneath it, 1e4, is one step ahead of your Basilisk.',
|
||
task: 'Slither under the Mage. Tap the Basilisk, then 1e4.',
|
||
moves: [['1e3', '1e4']],
|
||
after: 'The Mage is frozen where it stands, and will be until the Basilisk moves or is taken. Gygax says an immobilised piece can be treated as if it did not exist, except that it still blocks its square. His own trick runs the other way too: stand a piece of yours over your own Basilisk, and whatever takes it is frozen on the spot for you to take at your leisure.',
|
||
aside: 'A legal move, but 1e4, beneath the Mage, is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'elemental',
|
||
title: 'The Elemental',
|
||
pieces: { '1d4': 'gE', '2e4': 'sT', '1d6': 'sD' },
|
||
side: 'gold',
|
||
levels: [2, 1],
|
||
before: 'The one heavy thing in the underworld. It moves one or two squares along a rank or file and takes the same way, so the Dwarf at 1d6 is in reach. It climbs to the land only to capture, one square along a rank or file onto an empty square and then straight up onto an enemy. The square beside it at 1e4 is empty, and above that stands a Thief.',
|
||
task: 'Heave up and take the Thief. Tap the Elemental, then 2e4 on the middle board.',
|
||
moves: [['1d4', '2e4']],
|
||
after: 'The Thief is shattered and the Elemental stands on the land, where it is a rock. Its only move there is back down, straight through an empty square and then one square along a rank or file. Plan its climb: an empty square beside it and an enemy above that square, and nothing else will do.',
|
||
aside: 'A legal move, but the climb onto the Thief at 2e4 is the one to see. Tap the board’s title to set the scene again.'
|
||
},
|
||
{
|
||
id: 'king',
|
||
title: 'The King',
|
||
pieces: { '2g1': 'gK', '2g8': 'sO', '2f2': 'gW', '2h2': 'gW' },
|
||
side: 'gold',
|
||
levels: [3, 2, 1],
|
||
before: 'The whole game. The King moves one square in any direction on the land, and one step straight up or down between boards. Here it is in check: the Scarlet Oliphant looks down the open g file. Nothing of yours can take the Oliphant or step into the file, so the King must move. Two squares on the land are safe, and it could also climb into the air or dig into the underworld.',
|
||
task: 'Step out of check along the rank. Tap the King, then 2f1 or 2h1.',
|
||
moves: [['2g1', '2f1'], ['2g1', '2h1']],
|
||
after: 'Safe, and still on the land. The King could have climbed or dug instead, but off the land a King can do nothing except come straight back, and Gygax calls it a sitting duck there. Keep two more things in mind at the table: the square beneath your King, where an enemy Basilisk would freeze it, and your Dragon above it, which is its roof.',
|
||
aside: 'That is out of check, but off the land the King can only come back. Set the scene again and stay on the land.'
|
||
},
|
||
{
|
||
id: 'mate',
|
||
title: 'Checkmate',
|
||
pieces: { '2d4': 'sK', '1d4': 'gB', '2a1': 'gO', '2g1': 'gK' },
|
||
side: 'gold',
|
||
levels: [2, 1],
|
||
before: 'Your Basilisk sits beneath the Scarlet King at 2d4, so the King is frozen: it cannot step out of anything. Gygax wrote that a frozen King is checkmated by any attack it cannot capture or block. Your Oliphant stands on the a file with the fourth rank empty between it and the King.',
|
||
task: 'Give checkmate. Tap the Oliphant, then 2a4.',
|
||
moves: [['2a1', '2a4']],
|
||
after: 'Checkmate. The King is attacked along the rank, it cannot move, nothing of Scarlet’s can take the Oliphant, and nothing can step between. That is the Basilisk’s other gift: a well-timed move beneath a King, or beneath the piece that guards it, ends a game.',
|
||
aside: 'A legal move, but the Oliphant to 2a4 is the mate. Tap the board’s title to set the scene again.'
|
||
}
|
||
];
|
||
|
||
/** The scene's position as cells, Kings supplied where the scene gives none. */
|
||
export function sceneCells(scene: Scene): Cell[] {
|
||
const cells: Cell[] = new Array(CELLS).fill('');
|
||
for (const [name, cell] of Object.entries(scene.pieces)) cells[square(name)] = cell;
|
||
if (!cells.includes('gK')) cells[square('2l1')] = 'gK';
|
||
if (!cells.includes('sK')) cells[square('2a8')] = 'sK';
|
||
return cells;
|
||
}
|