refactor: add some part management utilities

This commit is contained in:
2026-04-03 15:00:25 +08:00
parent 86714e7837
commit 4bf6eb2f6b
9 changed files with 170 additions and 63 deletions
+8 -15
View File
@@ -1,4 +1,4 @@
import {createGameCommandRegistry, Part, MutableSignal, createRegion} from '@/index';
import {createGameCommandRegistry, Part, MutableSignal, createRegion, createPart, isCellOccupied as isCellOccupiedUtil, getPartAtPosition} from '@/index';
const BOARD_SIZE = 6;
const MAX_PIECES_PER_PLAYER = 8;
@@ -8,7 +8,7 @@ export type PlayerType = 'white' | 'black';
export type PieceType = 'kitten' | 'cat';
export type WinnerType = PlayerType | 'draw' | null;
type BoopPart = Part & { player: PlayerType; pieceType: PieceType };
type BoopPart = Part<{ player: PlayerType; pieceType: PieceType }>;
type PieceSupply = { supply: number; placed: number };
@@ -157,15 +157,11 @@ export function getBoardRegion(host: MutableSignal<BoopState>) {
}
export function isCellOccupied(host: MutableSignal<BoopState>, row: number, col: number): boolean {
const board = getBoardRegion(host);
return board.partMap[`${row},${col}`] !== undefined;
return isCellOccupiedUtil(host.value.pieces, 'board', [row, col]);
}
export function getPartAt(host: MutableSignal<BoopState>, row: number, col: number): BoopPart | null {
const board = getBoardRegion(host);
const partId = board.partMap[`${row},${col}`];
if (!partId) return null;
return host.value.pieces.find(p => p.id === partId) || null;
return getPartAtPosition(host.value.pieces, 'board', [row, col]) || null;
}
export function placePiece(host: MutableSignal<BoopState>, row: number, col: number, player: PlayerType, pieceType: PieceType) {
@@ -173,13 +169,10 @@ export function placePiece(host: MutableSignal<BoopState>, row: number, col: num
const playerData = getPlayer(host, player);
const count = playerData[pieceType].placed + 1;
const piece: BoopPart = {
id: `${player}-${pieceType}-${count}`,
regionId: 'board',
position: [row, col],
player,
pieceType,
};
const piece = createPart<{ player: PlayerType; pieceType: PieceType }>(
{ regionId: 'board', position: [row, col], player, pieceType },
`${player}-${pieceType}-${count}`
);
host.produce(s => {
s.pieces.push(piece);
board.childIds.push(piece.id);
+11 -14
View File
@@ -1,4 +1,4 @@
import {createGameCommandRegistry, Part, MutableSignal, createRegion, moveToRegion} from '@/index';
import {createGameCommandRegistry, Part, MutableSignal, createRegion, createPart, isCellOccupied as isCellOccupiedUtil} from '@/index';
const BOARD_SIZE = 3;
const MAX_TURNS = BOARD_SIZE * BOARD_SIZE;
@@ -16,7 +16,7 @@ const WINNING_LINES: number[][][] = [
export type PlayerType = 'X' | 'O';
export type WinnerType = PlayerType | 'draw' | null;
type TicTacToePart = Part & { player: PlayerType };
type TicTacToePart = Part<{ player: PlayerType }>;
export function createInitialState() {
return {
@@ -24,7 +24,7 @@ export function createInitialState() {
{ name: 'x', min: 0, max: BOARD_SIZE - 1 },
{ name: 'y', min: 0, max: BOARD_SIZE - 1 },
]),
parts: {} as Record<string, TicTacToePart>,
parts: [] as TicTacToePart[],
currentPlayer: 'X' as PlayerType,
winner: null as WinnerType,
turn: 0,
@@ -91,8 +91,7 @@ function isValidMove(row: number, col: number): boolean {
}
export function isCellOccupied(host: MutableSignal<TicTacToeState>, row: number, col: number): boolean {
const board = host.value.board;
return board.partMap[`${row},${col}`] !== undefined;
return isCellOccupiedUtil(host.value.parts, 'board', [row, col]);
}
export function hasWinningLine(positions: number[][]): boolean {
@@ -104,7 +103,7 @@ export function hasWinningLine(positions: number[][]): boolean {
}
export function checkWinner(host: MutableSignal<TicTacToeState>): WinnerType {
const parts = Object.values(host.value.parts);
const parts = host.value.parts;
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);
@@ -118,15 +117,13 @@ export function checkWinner(host: MutableSignal<TicTacToeState>): WinnerType {
export function placePiece(host: MutableSignal<TicTacToeState>, row: number, col: number, player: PlayerType) {
const board = host.value.board;
const moveNumber = Object.keys(host.value.parts).length + 1;
const piece: TicTacToePart = {
id: `piece-${player}-${moveNumber}`,
regionId: 'board',
position: [row, col],
player,
};
const moveNumber = host.value.parts.length + 1;
const piece = createPart<{ player: PlayerType }>(
{ regionId: 'board', position: [row, col], player },
`piece-${player}-${moveNumber}`
);
host.produce(state => {
state.parts[piece.id] = piece;
state.parts.push(piece);
board.childIds.push(piece.id);
board.partMap[`${row},${col}`] = piece.id;
});