Files
drinkmarble/app/game/chessman.ts
kimyu fc6eb5fce1 주루마블 기본 알고리즘 생성중.
- 시작위치 생성
- 각 위치별 추가 이벤트시 사용될 이벤트 알고리즘
- Rapier, Three.js를 통한 주사위.
2026-09-07 20:50:21 +09:00

94 lines
2.4 KiB
TypeScript

/** 주사위판 위를 이동하는 말. */
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: 6(또는 escapeOn)으로 탈출 → 이후 정상 이동
* - wait: 턴 소모 후 대기 (turnsLeft 0이면 자동 해제, 이번 턴은 이동 없음)
* - free: 이미 무인도 아님
*/
resolveIslandRoll(roll: number): 'escape' | 'wait' | 'free' {
if (!this.island) return 'free';
if (roll === 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;
}
}