boardgame-core/src/games/tictactoe/TicTacToeState.ts

162 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 井字棋游戏状态扩展
*/
/**
* 玩家类型
*/
export type Player = 'X' | 'O';
/**
* 单元格状态
*/
export interface CellState {
/** 单元格 ID如 A1, B2, C3 */
id: string;
/** 行索引 (0-2) */
row: number;
/** 列索引 (0-2) */
col: number;
/** 当前玩家标记null 表示空 */
player: Player | null;
}
/**
* 井字棋游戏元数据
*/
export interface TicTacToeMetadata {
/** 当前玩家 */
currentPlayer: Player;
/** 游戏是否结束 */
gameEnded: boolean;
/** 获胜者null 表示平局或未结束 */
winner: Player | null;
/** 获胜的组合(如果有) */
winningCombination?: string[];
/** 游戏历史 */
moveHistory: MoveRecord[];
/** 总回合数 */
totalMoves: number;
}
/**
* 移动记录
*/
export interface MoveRecord {
/** 移动的玩家 */
player: Player;
/** 移动的单元格 ID */
cellId: string;
/** 移动时间戳 */
timestamp: number;
}
/**
* 获胜组合类型
*/
export type WinningLine =
| { type: 'row'; index: number }
| { type: 'column'; index: number }
| { type: 'diagonal'; direction: 'main' | 'anti' };
/**
* 井字棋棋盘配置
*/
export interface TicTacToeBoardConfig {
/** 棋盘大小(默认 3x3 */
size: number;
/** 单元格 ID 前缀 */
cellIdPrefix: string;
}
/**
* 默认的 3x3 棋盘配置
*/
export const DEFAULT_BOARD_CONFIG: TicTacToeBoardConfig = {
size: 3,
cellIdPrefix: 'cell',
};
/**
* 获取单元格 ID
*/
export function getCellId(row: number, col: number, prefix: string = 'cell'): string {
const rowLabel = String.fromCharCode('A'.charCodeAt(0) + row);
return `${prefix}-${rowLabel}${col + 1}`;
}
/**
* 解析单元格 ID
*/
export function parseCellId(cellId: string): { row: number; col: number } | null {
const match = cellId.match(/^cell-([A-Z])(\d+)$/);
if (!match) return null;
return {
row: match[1].charCodeAt(0) - 'A'.charCodeAt(0),
col: parseInt(match[2], 10) - 1,
};
}
/**
* 检查是否是有效的单元格 ID
*/
export function isValidCellId(cellId: string, size: number = 3): boolean {
const parsed = parseCellId(cellId);
if (!parsed) return false;
return parsed.row >= 0 && parsed.row < size && parsed.col >= 0 && parsed.col < size;
}
/**
* 生成所有单元格 ID
*/
export function getAllCellIds(size: number = 3, prefix: string = 'cell'): string[] {
const cells: string[] = [];
for (let row = 0; row < size; row++) {
for (let col = 0; col < size; col++) {
cells.push(getCellId(row, col, prefix));
}
}
return cells;
}
/**
* 获取所有可能的获胜组合
*/
export function getWinningCombinations(size: number = 3): string[][] {
const combinations: string[][] = [];
// 行
for (let row = 0; row < size; row++) {
const rowCells: string[] = [];
for (let col = 0; col < size; col++) {
rowCells.push(getCellId(row, col));
}
combinations.push(rowCells);
}
// 列
for (let col = 0; col < size; col++) {
const colCells: string[] = [];
for (let row = 0; row < size; row++) {
colCells.push(getCellId(row, col));
}
combinations.push(colCells);
}
// 主对角线
const mainDiagonal: string[] = [];
for (let i = 0; i < size; i++) {
mainDiagonal.push(getCellId(i, i));
}
combinations.push(mainDiagonal);
// 反对角线
const antiDiagonal: string[] = [];
for (let i = 0; i < size; i++) {
antiDiagonal.push(getCellId(i, size - 1 - i));
}
combinations.push(antiDiagonal);
return combinations;
}