/** 주사위판 위를 이동하는 말. */ export class Chessman { private index: number; private readonly boardLength: number; /** 1: 시계방향, -1: 반시계방향 */ private direction: 1 | -1 = 1; /** 무인도: 남은 대기 턴, 탈출 가능 눈 */ private island: { turnsLeft: number; escapeOn: number } | null = null; constructor(boardLength: number, startIndex = 0) { if (boardLength <= 0) { throw new Error('Chessman boardLength must be positive'); } this.boardLength = boardLength; this.index = ((startIndex % boardLength) + boardLength) % boardLength; } get position(): number { return this.index; } get facing(): 1 | -1 { return this.direction; } get isOnIsland(): boolean { return this.island != null; } get islandTurnsLeft(): number { return this.island?.turnsLeft ?? 0; } reverseDirection(): 1 | -1 { this.direction = this.direction === 1 ? -1 : 1; return this.direction; } enterIsland(turns: number, escapeOn = 6) { this.island = { turnsLeft: Math.max(1, Math.trunc(turns)), escapeOn }; } clearIsland() { this.island = null; } /** * 무인도 상태에서의 주사위 처리. * - escape: escapeOn(기본 6)이 한 면이라도 나오면 탈출 → 이후 정상 이동 * - wait: 턴 소모 후 대기 (turnsLeft 0이면 자동 해제, 이번 턴은 이동 없음) * - free: 이미 무인도 아님 */ resolveIslandRoll(roll: number, faces?: number[]): 'escape' | 'wait' | 'free' { if (!this.island) return 'free'; const values = faces && faces.length > 0 ? faces : [roll]; if (values.some((value) => value === this.island!.escapeOn)) { this.island = null; return 'escape'; } this.island.turnsLeft -= 1; if (this.island.turnsLeft <= 0) { this.island = null; } return 'wait'; } teleport(index: number): number { this.index = ((index % this.boardLength) + this.boardLength) % this.boardLength; return this.index; } moveOne(): number { return this.move(1); } /** steps칸만큼 현재 방향으로 이동 */ move(steps: number): number { const amount = Math.trunc(steps); if (amount === 0) return this.index; const delta = amount * this.direction; this.index = (this.index + delta) % this.boardLength; if (this.index < 0) this.index += this.boardLength; return this.index; } reset(startIndex = 0): number { this.index = ((startIndex % this.boardLength) + this.boardLength) % this.boardLength; this.direction = 1; this.island = null; return this.index; } }