예제 소스
장기로 이해하는 규칙 엔진과 평가 함수 탐색 · 파일 59개
types.ts
export type Side = "cho" | "han";
export type PieceType =
| "none"
| "king"
| "advisor"
| "chariot"
| "cannon"
| "horse"
| "elephant"
| "pawn";
export type Formation = "inner" | "outer" | "left" | "right";
export type GameResult = "playing" | "cho_win" | "han_win" | "draw";
export type GameMode = "human_cho" | "human_han" | "human_vs_human" | "ai_vs_ai";
export type Pos = { file: number; rank: number };
export type Piece = { type: PieceType; side: Side };
export type Move = {
from: Pos;
to: Pos;
moving: Piece;
captured: Piece;
pass: boolean;
};
export type GameSettings = {
choFormation: Formation;
hanFormation: Formation;
mode: GameMode;
/** 컴퓨터 깊이 (AI 대 AI에서는 초 쪽) */
aiDepth: number;
/** AI 대 AI에서 한 쪽 깊이 */
hanAiDepth: number;
bikjangEnabled: boolean;
};
export const EMPTY: Piece = { type: "none", side: "cho" };
export function opposite(side: Side): Side {
return side === "cho" ? "han" : "cho";
}
export function posEq(a: Pos, b: Pos): boolean {
return a.file === b.file && a.rank === b.rank;
}
export function inBoard(p: Pos): boolean {
return p.file >= 0 && p.file < 9 && p.rank >= 0 && p.rank < 10;
}
export function inPalace(p: Pos, side: Side): boolean {
if (p.file < 3 || p.file > 5) return false;
if (side === "han") return p.rank >= 0 && p.rank <= 2;
return p.rank >= 7 && p.rank <= 9;
}
export function inAnyPalace(p: Pos): boolean {
return inPalace(p, "han") || inPalace(p, "cho");
}
export function pawnForward(side: Side): number {
return side === "cho" ? -1 : 1;
}
export function pieceEmpty(p: Piece): boolean {
return p.type === "none";
}
export function makePass(): Move {
return {
from: { file: 0, rank: 0 },
to: { file: 0, rank: 0 },
moving: EMPTY,
captured: EMPTY,
pass: true,
};
}
export function pieceGlyph(piece: Piece): string {
if (pieceEmpty(piece)) return "";
if (piece.side === "han") {
switch (piece.type) {
case "king":
return "漢";
case "advisor":
return "士";
case "chariot":
return "車";
case "cannon":
return "包";
case "horse":
return "馬";
case "elephant":
return "象";
case "pawn":
return "兵";
default:
return "";
}
}
switch (piece.type) {
case "king":
return "楚";
case "advisor":
return "士";
case "chariot":
return "車";
case "cannon":
return "包";
case "horse":
return "馬";
case "elephant":
return "象";
case "pawn":
return "卒";
default:
return "";
}
}
export function pieceNameKo(type: PieceType): string {
switch (type) {
case "king":
return "궁";
case "advisor":
return "사";
case "chariot":
return "차";
case "cannon":
return "포";
case "horse":
return "마";
case "elephant":
return "상";
case "pawn":
return "졸";
default:
return "";
}
}
export function formationNameKo(f: Formation): string {
switch (f) {
case "inner":
return "마상상마 (내상)";
case "outer":
return "상마마상 (외상)";
case "left":
return "상마상마 (좌상)";
case "right":
return "마상마상 (우상)";
}
}
export function materialValue(type: PieceType): number {
switch (type) {
case "chariot":
return 130;
case "cannon":
return 70;
case "horse":
return 50;
case "elephant":
return 30;
case "advisor":
return 30;
case "pawn":
return 20;
case "king":
return 100000;
default:
return 0;
}
}
export function posLabel(p: Pos): string {
return `${p.file + 1}${p.rank + 1}`;
}
export function sideNameKo(side: Side): string {
return side === "cho" ? "초 (楚)" : "한 (漢)";
}
export function resultText(result: GameResult): string {
switch (result) {
case "cho_win":
return "초 승리 (외통)";
case "han_win":
return "한 승리 (외통)";
case "draw":
return "무승부";
default:
return "";
}
}
export const FORMATIONS: Formation[] = ["inner", "outer", "left", "right"];
export const DEFAULT_SETTINGS: GameSettings = {
choFormation: "inner",
hanFormation: "inner",
mode: "human_cho",
aiDepth: 3,
hanAiDepth: 3,
bikjangEnabled: true,
};