mancala/packages/core/src/tutorial/Rules.ts

84 lines
3.3 KiB
TypeScript
Raw Normal View History

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;
}