refactor: use part map for tictactoe

This commit is contained in:
hypercross 2026-04-03 13:09:28 +08:00
parent eb0ebf5411
commit 8b2a8888d3
2 changed files with 10 additions and 10 deletions

View File

@ -24,7 +24,7 @@ export function createInitialState() {
{ name: 'x', min: 0, max: BOARD_SIZE - 1 }, { name: 'x', min: 0, max: BOARD_SIZE - 1 },
{ name: 'y', min: 0, max: BOARD_SIZE - 1 }, { name: 'y', min: 0, max: BOARD_SIZE - 1 },
]), ]),
parts: [] as TicTacToePart[], parts: {} as Record<string, TicTacToePart>,
currentPlayer: 'X' as PlayerType, currentPlayer: 'X' as PlayerType,
winner: null as WinnerType, winner: null as WinnerType,
turn: 0, turn: 0,
@ -104,7 +104,7 @@ export function hasWinningLine(positions: number[][]): boolean {
} }
export function checkWinner(host: Entity<TicTacToeState>): WinnerType { export function checkWinner(host: Entity<TicTacToeState>): WinnerType {
const parts = host.value.parts; const parts = Object.values(host.value.parts);
const xPositions = parts.filter((p: TicTacToePart) => p.player === 'X').map((p: TicTacToePart) => p.position); const xPositions = parts.filter((p: TicTacToePart) => p.player === 'X').map((p: TicTacToePart) => p.position);
const oPositions = parts.filter((p: TicTacToePart) => p.player === 'O').map((p: TicTacToePart) => p.position); const oPositions = parts.filter((p: TicTacToePart) => p.player === 'O').map((p: TicTacToePart) => p.position);
@ -118,7 +118,7 @@ export function checkWinner(host: Entity<TicTacToeState>): WinnerType {
export function placePiece(host: Entity<TicTacToeState>, row: number, col: number, player: PlayerType) { export function placePiece(host: Entity<TicTacToeState>, row: number, col: number, player: PlayerType) {
const board = host.value.board; const board = host.value.board;
const moveNumber = host.value.parts.length + 1; const moveNumber = Object.keys(host.value.parts).length + 1;
const piece: TicTacToePart = { const piece: TicTacToePart = {
id: `piece-${player}-${moveNumber}`, id: `piece-${player}-${moveNumber}`,
regionId: 'board', regionId: 'board',
@ -126,7 +126,7 @@ export function placePiece(host: Entity<TicTacToeState>, row: number, col: numbe
player, player,
}; };
host.produce(state => { host.produce(state => {
state.parts.push(piece); state.parts[piece.id] = piece;
board.childIds.push(piece.id); board.childIds.push(piece.id);
board.partMap[`${row},${col}`] = piece.id; board.partMap[`${row},${col}`] = piece.id;
}); });

View File

@ -163,9 +163,9 @@ describe('TicTacToe - helper functions', () => {
const state = getState(ctx); const state = getState(ctx);
placePiece(state, 1, 1, 'X'); placePiece(state, 1, 1, 'X');
expect(state.value.parts.length).toBe(1); expect(Object.keys(state.value.parts).length).toBe(1);
expect(state.value.parts[0].position).toEqual([1, 1]); expect(state.value.parts['piece-X-1'].position).toEqual([1, 1]);
expect(state.value.parts[0].player).toBe('X'); expect(state.value.parts['piece-X-1'].player).toBe('X');
}); });
it('should add piece to board region children', () => { it('should add piece to board region children', () => {
@ -183,7 +183,7 @@ describe('TicTacToe - helper functions', () => {
placePiece(state, 0, 0, 'X'); placePiece(state, 0, 0, 'X');
placePiece(state, 0, 1, 'O'); placePiece(state, 0, 1, 'O');
const ids = state.value.parts.map(p => p.id); const ids = Object.keys(state.value.parts);
expect(new Set(ids).size).toBe(2); expect(new Set(ids).size).toBe(2);
}); });
}); });
@ -229,8 +229,8 @@ describe('TicTacToe - game flow', () => {
const result = await runPromise; const result = await runPromise;
expect(result.success).toBe(true); expect(result.success).toBe(true);
if (result.success) expect(result.result.winner).toBeNull(); if (result.success) expect(result.result.winner).toBeNull();
expect(ctx.state.value.parts.length).toBe(1); expect(Object.keys(ctx.state.value.parts).length).toBe(1);
expect(ctx.state.value.parts[0].position).toEqual([1, 1]); expect(ctx.state.value.parts['piece-X-1'].position).toEqual([1, 1]);
}); });
it('should reject move for wrong player and re-prompt', async () => { it('should reject move for wrong player and re-prompt', async () => {