RULES defines every rule with an example and a lesson; getMoveOutcome works out a move's effect with the engine, explainMove says what happened, and describeMove now tells the kind of capture and how many stones it took.
84 lines
3.3 KiB
TypeScript
84 lines
3.3 KiB
TypeScript
import { LessonTask } from "./MoveOutcome";
|
|
|
|
export type RuleId = "board" | "sowing" | "extraTurn" | "evenCapture" | "emptyPitCapture" | "endOfGame" | "clock";
|
|
|
|
// A rule shown on a board: the position, player 1 (bottom) to move, and the pit played, if any.
|
|
export interface RuleExample {
|
|
board: number[];
|
|
pitIndex?: number;
|
|
}
|
|
|
|
// The rule taught on a prepared position (player 1, bottom, to move) with a task.
|
|
export interface Lesson {
|
|
board: number[];
|
|
task: LessonTask;
|
|
taskKey: string;
|
|
}
|
|
|
|
export interface Rule {
|
|
id: RuleId;
|
|
titleKey: string;
|
|
// At most three sentences.
|
|
textKeys: string[];
|
|
example?: RuleExample;
|
|
lesson?: Lesson;
|
|
}
|
|
|
|
const START = [4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 0];
|
|
const SOWING = [4, 4, 1, 4, 4, 4, 1, 4, 4, 4, 4, 4, 4, 2];
|
|
const EVEN_CAPTURE = [4, 4, 4, 4, 4, 4, 0, 4, 3, 4, 4, 4, 4, 1];
|
|
const EMPTY_PIT_CAPTURE = [2, 0, 4, 4, 4, 4, 3, 4, 4, 4, 4, 5, 4, 2];
|
|
const END_OF_GAME = [0, 0, 0, 0, 0, 1, 20, 2, 3, 1, 0, 2, 1, 18];
|
|
|
|
const texts = (id: string, count: number) => Array.from({ length: count }, (_, i) => `Rule${id}Text${i + 1}`);
|
|
|
|
// The rules of the game in the order they are taught (docs/specs/tutorial). Every board here is checked against the
|
|
// engine by the tests; the boards after a move are never written by hand.
|
|
export const RULES: Rule[] = [
|
|
{
|
|
id: "board", titleKey: "RuleBoardTitle", textKeys: texts("Board", 3),
|
|
example: { board: START },
|
|
lesson: { board: START, task: "anyMove", taskKey: "LessonTaskAnyMove" },
|
|
},
|
|
{
|
|
id: "sowing", titleKey: "RuleSowingTitle", textKeys: texts("Sowing", 3),
|
|
example: { board: SOWING, pitIndex: 0 },
|
|
lesson: { board: SOWING, task: "anyMove", taskKey: "LessonTaskSowing" },
|
|
},
|
|
{
|
|
id: "extraTurn", titleKey: "RuleExtraTurnTitle", textKeys: texts("ExtraTurn", 2),
|
|
example: { board: START, pitIndex: 3 },
|
|
lesson: { board: START, task: "extraTurn", taskKey: "LessonTaskExtraTurn" },
|
|
},
|
|
{
|
|
id: "evenCapture", titleKey: "RuleEvenCaptureTitle", textKeys: texts("EvenCapture", 2),
|
|
example: { board: EVEN_CAPTURE, pitIndex: 5 },
|
|
lesson: { board: EVEN_CAPTURE, task: "evenCapture", taskKey: "LessonTaskEvenCapture" },
|
|
},
|
|
{
|
|
id: "emptyPitCapture", titleKey: "RuleEmptyPitCaptureTitle", textKeys: texts("EmptyPitCapture", 2),
|
|
example: { board: EMPTY_PIT_CAPTURE, pitIndex: 0 },
|
|
lesson: { board: EMPTY_PIT_CAPTURE, task: "emptyPitCapture", taskKey: "LessonTaskEmptyPitCapture" },
|
|
},
|
|
{
|
|
id: "endOfGame", titleKey: "RuleEndOfGameTitle", textKeys: texts("EndOfGame", 3),
|
|
example: { board: END_OF_GAME, pitIndex: 5 },
|
|
lesson: { board: END_OF_GAME, task: "endGame", taskKey: "LessonTaskEndGame" },
|
|
},
|
|
{
|
|
id: "clock", titleKey: "RuleClockTitle", textKeys: texts("Clock", 2),
|
|
},
|
|
];
|
|
|
|
export const LESSON_RULES: Rule[] = RULES.filter((rule) => rule.lesson);
|
|
|
|
export function getRule(id: string | undefined): Rule | undefined {
|
|
return RULES.find((rule) => rule.id === id);
|
|
}
|
|
|
|
// The lesson after the given one, or undefined after the last.
|
|
export function getNextLessonRule(id: RuleId): Rule | undefined {
|
|
const index = LESSON_RULES.findIndex((rule) => rule.id === id);
|
|
return index >= 0 ? LESSON_RULES[index + 1] : undefined;
|
|
}
|