From 94e021974f63020df15741c0a2f87a9d63ea897d Mon Sep 17 00:00:00 2001 From: hyper Date: Thu, 2 Apr 2026 19:56:34 +0800 Subject: [PATCH] refactor: choose a kitten to graduate --- src/samples/boop/index.ts | 54 ++++++++++++++++++++++++++++++++------- src/samples/boop/rules.md | 6 ++--- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/src/samples/boop/index.ts b/src/samples/boop/index.ts index 0e79873..f8f1b37 100644 --- a/src/samples/boop/index.ts +++ b/src/samples/boop/index.ts @@ -125,6 +125,36 @@ registration.add('turn ', async function(cmd) { processGraduation(this.context, turnPlayer, graduatedLines); } + if (countPiecesOnBoard(this.context, turnPlayer) >= MAX_PIECES_PER_PLAYER) { + const board = getBoardRegion(this.context); + const partsMap = board.partsMap.value; + const availableKittens: Entity[] = []; + for (const key in partsMap) { + const part = partsMap[key] as Entity; + if (part.value.player === turnPlayer && part.value.pieceType === 'kitten') { + availableKittens.push(part); + } + } + + if (availableKittens.length > 0) { + const graduateCmd = await this.prompt( + 'graduate ', + (command) => { + const [row, col] = command.params as [number, number]; + const posKey = `${row},${col}`; + const part = availableKittens.find(p => `${p.value.position[0]},${p.value.position[1]}` === posKey); + if (!part) return `No kitten at (${row}, ${col}).`; + return null; + } + ); + const [row, col] = graduateCmd.params as [number, number]; + const part = availableKittens.find(p => p.value.position[0] === row && p.value.position[1] === col)!; + removePieceFromBoard(this.context, part); + const playerEntity = getPlayer(this.context, turnPlayer); + incrementSupply(playerEntity, 'cat', 1); + } + } + const winner = checkWinner(this.context); if (winner) return { winner }; @@ -218,9 +248,13 @@ export function applyBoops(host: Entity, placedRow: number, placedCol export function removePieceFromBoard(host: Entity, part: Entity) { const board = getBoardRegion(host); + const playerEntity = getPlayer(host, part.value.player); board.produce(draft => { draft.children = draft.children.filter(p => p.id !== part.id); }); + playerEntity.produce(p => { + p[part.value.pieceType].placed--; + }); } const DIRECTIONS: [number, number][] = [ @@ -323,6 +357,17 @@ export function processGraduation(host: Entity, player: PlayerType, l incrementSupply(playerEntity, 'cat', count); } +export function countPiecesOnBoard(host: Entity, player: PlayerType): number { + const board = getBoardRegion(host); + const partsMap = board.partsMap.value; + let count = 0; + for (const key in partsMap) { + const part = partsMap[key] as Entity; + if (part.value.player === player) count++; + } + return count; +} + export function checkWinner(host: Entity): WinnerType { const board = getBoardRegion(host); const partsMap = board.partsMap.value; @@ -338,14 +383,5 @@ export function checkWinner(host: Entity): WinnerType { if (hasWinningLine(positions)) return player; } - const whitePlayer = getPlayer(host, 'white'); - const blackPlayer = getPlayer(host, 'black'); - const whiteTotal = MAX_PIECES_PER_PLAYER - whitePlayer.value.kitten.supply + whitePlayer.value.cat.supply; - const blackTotal = MAX_PIECES_PER_PLAYER - blackPlayer.value.kitten.supply + blackPlayer.value.cat.supply; - - if (whiteTotal >= MAX_PIECES_PER_PLAYER && blackTotal >= MAX_PIECES_PER_PLAYER) { - return 'draw'; - } - return null; } diff --git a/src/samples/boop/rules.md b/src/samples/boop/rules.md index b95c8dd..c8292b3 100644 --- a/src/samples/boop/rules.md +++ b/src/samples/boop/rules.md @@ -30,7 +30,7 @@ On your turn, perform the following steps: ### 1. Placing Pieces -Place one Kitten from your supply onto any empty space on the bed. +Place one piece (Kitten or Cat) from your supply onto any empty space on the bed. ### 2. The "Boop" Mechanic @@ -51,9 +51,9 @@ Placing a piece causes a **"boop."** Every piece (yours or your opponent's) in t To win, you need Cats. You obtain Cats by lining up Kittens: 1. **Three in a Row:** If you line up three of your Kittens in a row (horizontally, vertically, or diagonally), they "graduate." -2. **The Process:** Remove the three Kittens from the board and return them to the box. Replace them in your personal supply with three **Cats**. +2. **The Process:** Remove the three Kittens from the board and return them to the box. Add three **Cats** to your personal supply. 3. **Multiple Rows:** If placing a piece creates multiple rows of three, you graduate all pieces involved in those rows. -4. **The 8-Piece Rule:** If a player has all 8 of their pieces on the board (a mix of Kittens and Cats) and no one has three-in-a-row, the player must graduate one of their Kittens on the board into a Cat to free up a piece. +4. **The 8-Piece Rule:** If a player has all 8 of their pieces on the board (a mix of Kittens and Cats) and no one has three-in-a-row, the player must choose one of their Kittens on the board to graduate into a Cat to free up a piece. ## How to Win