refactor: fix boop placement
This commit is contained in:
+66
-49
@@ -4,18 +4,26 @@ const BOARD_SIZE = 6;
|
||||
const MAX_PIECES_PER_PLAYER = 8;
|
||||
const WIN_LENGTH = 3;
|
||||
|
||||
const DIRECTIONS = [
|
||||
[-1, -1], [-1, 0], [-1, 1],
|
||||
[0, -1], [0, 1],
|
||||
[1, -1], [1, 0], [1, 1],
|
||||
];
|
||||
|
||||
export type PlayerType = 'white' | 'black';
|
||||
export type PieceType = 'kitten' | 'cat';
|
||||
export type WinnerType = PlayerType | 'draw' | null;
|
||||
|
||||
type BoopPart = Part & { player: PlayerType; pieceType: PieceType };
|
||||
|
||||
type PieceSupply = { supply: number; placed: number };
|
||||
|
||||
type PlayerSupply = {
|
||||
kitten: PieceSupply;
|
||||
cat: PieceSupply;
|
||||
};
|
||||
|
||||
function createPlayerSupply(): PlayerSupply {
|
||||
return {
|
||||
kitten: { supply: MAX_PIECES_PER_PLAYER, placed: 0 },
|
||||
cat: { supply: 0, placed: 0 },
|
||||
};
|
||||
}
|
||||
|
||||
export function createInitialState() {
|
||||
return {
|
||||
board: new RegionEntity('board', {
|
||||
@@ -26,13 +34,12 @@ export function createInitialState() {
|
||||
],
|
||||
children: [],
|
||||
}),
|
||||
parts: [] as Entity<BoopPart>[],
|
||||
currentPlayer: 'white' as PlayerType,
|
||||
winner: null as WinnerType,
|
||||
whiteKittensInSupply: MAX_PIECES_PER_PLAYER,
|
||||
blackKittensInSupply: MAX_PIECES_PER_PLAYER,
|
||||
whiteCatsInSupply: 0,
|
||||
blackCatsInSupply: 0,
|
||||
players: {
|
||||
white: createPlayerSupply(),
|
||||
black: createPlayerSupply(),
|
||||
},
|
||||
};
|
||||
}
|
||||
export type BoopState = ReturnType<typeof createInitialState>;
|
||||
@@ -65,23 +72,23 @@ registration.add('turn <player>', async function(cmd) {
|
||||
|
||||
while (retries < maxRetries) {
|
||||
retries++;
|
||||
const playCmd = await this.prompt('play <player> <row:number> <col:number>');
|
||||
const [player, row, col] = playCmd.params as [PlayerType, number, number];
|
||||
const playCmd = await this.prompt('play <player> <row:number> <col:number> [type:string]');
|
||||
const [player, row, col, type] = playCmd.params as [PlayerType, number, number, PieceType?];
|
||||
const pieceType = type === 'cat' ? 'cat' : 'kitten';
|
||||
|
||||
if (player !== turnPlayer) continue;
|
||||
if (!isValidMove(row, col)) continue;
|
||||
if (isCellOccupied(this.context, row, col)) continue;
|
||||
|
||||
const state = this.context.value;
|
||||
const kittensInSupply = player === 'white' ? state.whiteKittensInSupply : state.blackKittensInSupply;
|
||||
if (kittensInSupply <= 0) continue;
|
||||
const supply = this.context.value.players[player][pieceType].supply;
|
||||
if (supply <= 0) continue;
|
||||
|
||||
placeKitten(this.context, row, col, turnPlayer);
|
||||
applyBoops(this.context, row, col, 'kitten');
|
||||
placePiece(this.context, row, col, turnPlayer, pieceType);
|
||||
applyBoops(this.context, row, col, pieceType);
|
||||
|
||||
const graduatedRows = checkGraduation(this.context, turnPlayer);
|
||||
if (graduatedRows.length > 0) {
|
||||
processGraduation(this.context, turnPlayer, graduatedRows);
|
||||
const graduatedLines = checkGraduation(this.context, turnPlayer);
|
||||
if (graduatedLines.length > 0) {
|
||||
processGraduation(this.context, turnPlayer, graduatedLines);
|
||||
}
|
||||
|
||||
const winner = checkWinner(this.context);
|
||||
@@ -111,21 +118,21 @@ export function getPartAt(host: Entity<BoopState>, row: number, col: number): En
|
||||
return (board.partsMap.value[`${row},${col}`] as Entity<BoopPart> | undefined) || null;
|
||||
}
|
||||
|
||||
export function placeKitten(host: Entity<BoopState>, row: number, col: number, player: PlayerType) {
|
||||
export function placePiece(host: Entity<BoopState>, row: number, col: number, player: PlayerType, pieceType: PieceType) {
|
||||
const board = getBoardRegion(host);
|
||||
const moveNumber = host.value.parts.length + 1;
|
||||
const count = host.value.players[player][pieceType].placed + 1;
|
||||
|
||||
const piece: BoopPart = {
|
||||
id: `piece-${player}-${moveNumber}`,
|
||||
id: `${player}-${pieceType}-${count}`,
|
||||
region: board,
|
||||
position: [row, col],
|
||||
player,
|
||||
pieceType: 'kitten',
|
||||
pieceType,
|
||||
};
|
||||
host.produce(state => {
|
||||
host.produce(s => {
|
||||
const e = entity(piece.id, piece);
|
||||
state.parts.push(e);
|
||||
if (player === 'white') state.whiteKittensInSupply--;
|
||||
else state.blackKittensInSupply--;
|
||||
s.players[player][pieceType].supply--;
|
||||
s.players[player][pieceType].placed++;
|
||||
board.produce(draft => {
|
||||
draft.children.push(e);
|
||||
});
|
||||
@@ -162,11 +169,11 @@ export function applyBoops(host: Entity<BoopState>, placedRow: number, placedCol
|
||||
const newCol = c + dc;
|
||||
|
||||
if (newRow < 0 || newRow >= BOARD_SIZE || newCol < 0 || newCol >= BOARD_SIZE) {
|
||||
const pt = part.value.pieceType;
|
||||
const pl = part.value.player;
|
||||
removePieceFromBoard(host, part);
|
||||
const player = part.value.player;
|
||||
host.produce(state => {
|
||||
if (player === 'white') state.whiteKittensInSupply++;
|
||||
else state.blackKittensInSupply++;
|
||||
state.players[pl][pt].supply++;
|
||||
});
|
||||
continue;
|
||||
}
|
||||
@@ -181,17 +188,22 @@ export function applyBoops(host: Entity<BoopState>, placedRow: number, placedCol
|
||||
|
||||
export function removePieceFromBoard(host: Entity<BoopState>, part: Entity<BoopPart>) {
|
||||
const board = getBoardRegion(host);
|
||||
host.produce(state => {
|
||||
state.parts = state.parts.filter(p => p.id !== part.id);
|
||||
board.produce(draft => {
|
||||
draft.children = draft.children.filter(p => p.id !== part.id);
|
||||
});
|
||||
board.produce(draft => {
|
||||
draft.children = draft.children.filter(p => p.id !== part.id);
|
||||
});
|
||||
}
|
||||
|
||||
export function checkGraduation(host: Entity<BoopState>, player: PlayerType): number[][][] {
|
||||
const parts = host.value.parts.filter(p => p.value.player === player && p.value.pieceType === 'kitten');
|
||||
const positions = parts.map(p => p.value.position);
|
||||
const board = getBoardRegion(host);
|
||||
const partsMap = board.partsMap.value;
|
||||
const positions: number[][] = [];
|
||||
|
||||
for (const key in partsMap) {
|
||||
const part = partsMap[key] as Entity<BoopPart>;
|
||||
if (part.value.player === player && part.value.pieceType === 'kitten') {
|
||||
positions.push(part.value.position);
|
||||
}
|
||||
}
|
||||
|
||||
const winningLines: number[][][] = [];
|
||||
|
||||
@@ -271,25 +283,30 @@ export function processGraduation(host: Entity<BoopState>, player: PlayerType, l
|
||||
|
||||
const count = partsToRemove.length;
|
||||
host.produce(state => {
|
||||
const catsInSupply = player === 'white' ? state.whiteCatsInSupply : state.blackCatsInSupply;
|
||||
if (player === 'white') state.whiteCatsInSupply = catsInSupply + count;
|
||||
else state.blackCatsInSupply = catsInSupply + count;
|
||||
state.players[player].cat.supply += count;
|
||||
});
|
||||
}
|
||||
|
||||
export function checkWinner(host: Entity<BoopState>): WinnerType {
|
||||
for (const player of ['white', 'black'] as PlayerType[]) {
|
||||
const parts = host.value.parts.filter(p => p.value.player === player && p.value.pieceType === 'cat');
|
||||
const positions = parts.map(p => p.value.position);
|
||||
const board = getBoardRegion(host);
|
||||
const partsMap = board.partsMap.value;
|
||||
|
||||
for (const player of ['white', 'black'] as PlayerType[]) {
|
||||
const positions: number[][] = [];
|
||||
for (const key in partsMap) {
|
||||
const part = partsMap[key] as Entity<BoopPart>;
|
||||
if (part.value.player === player && part.value.pieceType === 'cat') {
|
||||
positions.push(part.value.position);
|
||||
}
|
||||
}
|
||||
if (hasWinningLine(positions)) return player;
|
||||
}
|
||||
|
||||
const totalParts = host.value.parts.length;
|
||||
const whiteParts = host.value.parts.filter(p => p.value.player === 'white').length;
|
||||
const blackParts = host.value.parts.filter(p => p.value.player === 'black').length;
|
||||
const state = host.value;
|
||||
const whiteTotal = MAX_PIECES_PER_PLAYER - state.players.white.kitten.supply + state.players.white.cat.supply;
|
||||
const blackTotal = MAX_PIECES_PER_PLAYER - state.players.black.kitten.supply + state.players.black.cat.supply;
|
||||
|
||||
if (whiteParts >= MAX_PIECES_PER_PLAYER && blackParts >= MAX_PIECES_PER_PLAYER) {
|
||||
if (whiteTotal >= MAX_PIECES_PER_PLAYER && blackTotal >= MAX_PIECES_PER_PLAYER) {
|
||||
return 'draw';
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user