From 129c58fb08e12f6b9fb7ab4baa336c796c1695bd Mon Sep 17 00:00:00 2001 From: hypercross Date: Mon, 6 Apr 2026 10:10:58 +0800 Subject: [PATCH] refactor: update samples --- src/samples/boop/commands.ts | 58 ++++++++++++------ src/samples/tic-tac-toe.ts | 86 ++++++++++++++------------- src/utils/command/command-registry.ts | 11 +++- 3 files changed, 95 insertions(+), 60 deletions(-) diff --git a/src/samples/boop/commands.ts b/src/samples/boop/commands.ts index 9b3e3c6..e1f828f 100644 --- a/src/samples/boop/commands.ts +++ b/src/samples/boop/commands.ts @@ -23,7 +23,7 @@ export const registry = createGameCommandRegistry(); /** * 放置棋子到棋盘 */ -async function place(game: BoopGame, row: number, col: number, player: PlayerType, type: PieceType) { +async function handlePlace(game: BoopGame, row: number, col: number, player: PlayerType, type: PieceType) { const value = game.value; // 从玩家supply中找到对应类型的棋子 const part = findPartInRegion(game, player, type); @@ -42,12 +42,15 @@ async function place(game: BoopGame, row: number, col: number, player: PlayerTyp return { row, col, player, type, partId }; } -const placeCommand = registry.asCommand( 'place ', place); +const place = registry.register({ + schema: 'place ', + run: handlePlace +}); /** * 执行boop - 推动周围棋子 */ -async function boop(game: BoopGame, row: number, col: number, type: PieceType) { +async function handleBoop(game: BoopGame, row: number, col: number, type: PieceType) { const booped: string[] = []; await game.produceAsync(state => { @@ -85,12 +88,15 @@ async function boop(game: BoopGame, row: number, col: number, type: PieceType) { return { booped }; } -const boopCommand = registry.asCommand('boop ', boop); +const boop = registry.register({ + schema: 'boop ', + run: handleBoop +}); /** * 检查是否有玩家获胜(三个猫连线) */ -async function checkWin(game: BoopGame): Promise { +async function handleCheckWin(game: BoopGame): Promise { for(const line of getLineCandidates()){ let whites = 0; let blacks = 0; @@ -109,12 +115,15 @@ async function checkWin(game: BoopGame): Promise { } return null; } -const checkWinCommand = registry.asCommand('check-win', checkWin); +const checkWin = registry.register({ + schema: 'check-win', + run: handleCheckWin +}); /** * 检查并执行小猫升级(三个小猫连线变成猫) */ -async function checkGraduates(game: BoopGame){ +async function handleCheckGraduates(game: BoopGame){ const toUpgrade = new Set(); for(const line of getLineCandidates()){ let whites = 0; @@ -145,12 +154,15 @@ async function checkGraduates(game: BoopGame){ } }); } -const checkGraduatesCommand = registry.asCommand('check-graduates', checkGraduates); +const checkGraduates = registry.register({ + schema: 'check-graduates', + run: handleCheckGraduates +}); -async function setup(game: BoopGame) { +async function handleStart(game: BoopGame) { while (true) { const currentPlayer = game.value.currentPlayer; - const turnOutput = await turnCommand(game, currentPlayer); + const turnOutput = await turn(game, currentPlayer); await game.produceAsync(state => { state.winner = turnOutput.winner; @@ -163,9 +175,12 @@ async function setup(game: BoopGame) { return game.value; } -registry.asCommand('setup', setup); +const start = registry.register({ + schema: 'start', + run: handleStart +}); -async function checkFullBoard(game: BoopGame, turnPlayer: PlayerType){ +async function handleCheckFullBoard(game: BoopGame, turnPlayer: PlayerType){ // 检查8-piece规则: 如果玩家所有8个棋子都在棋盘上且没有获胜,强制升级一个小猫 const playerPieces = Object.values(game.value.pieces).filter( p => p.player === turnPlayer && p.regionId === 'board' @@ -201,8 +216,12 @@ async function checkFullBoard(game: BoopGame, turnPlayer: PlayerType){ moveToRegion(cat || part, null, state.regions[turnPlayer]); }); } +const checkFullBoard = registry.register({ + schema: 'check-full-board ', + run: handleCheckFullBoard +}); -async function turn(game: BoopGame, turnPlayer: PlayerType) { +async function handleTurn(game: BoopGame, turnPlayer: PlayerType) { const {row, col, type} = await game.prompt( 'play [type:string]', (command) => { @@ -229,13 +248,16 @@ async function turn(game: BoopGame, turnPlayer: PlayerType) { ); const pieceType = type === 'cat' ? 'cat' : 'kitten'; - await placeCommand(game, row, col, turnPlayer, pieceType); - await boopCommand(game, row, col, pieceType); - const winner = await checkWinCommand(game); + await place(game, row, col, turnPlayer, pieceType); + await boop(game, row, col, pieceType); + const winner = await checkWin(game); if(winner) return { winner: winner }; - await checkGraduatesCommand(game); + await checkGraduates(game); await checkFullBoard(game, turnPlayer); return { winner: null }; } -const turnCommand = registry.asCommand('turn ', turn); \ No newline at end of file +const turn = registry.register({ + schema: 'turn ', + run: handleTurn +}); \ No newline at end of file diff --git a/src/samples/tic-tac-toe.ts b/src/samples/tic-tac-toe.ts index 094492b..25867a2 100644 --- a/src/samples/tic-tac-toe.ts +++ b/src/samples/tic-tac-toe.ts @@ -36,54 +36,58 @@ export type TicTacToeState = ReturnType; export type TicTacToeGame = IGameContext; export const registry = createGameCommandRegistry(); -async function start(game: TicTacToeGame) { - while (true) { - const currentPlayer = game.value.currentPlayer; - const turnNumber = game.value.turn + 1; - const turnOutput = await turnCommand(game, currentPlayer, turnNumber); +registry.register({ + schema: 'start', + async run(game: TicTacToeGame) { + while (true) { + const currentPlayer = game.value.currentPlayer; + const turnNumber = game.value.turn + 1; + const turnOutput = await turn(game, currentPlayer, turnNumber); - game.produce(state => { - state.winner = turnOutput.winner; - if (!state.winner) { - state.currentPlayer = state.currentPlayer === 'X' ? 'O' : 'X'; - state.turn = turnNumber; - } - }); - if (game.value.winner) break; + game.produce(state => { + state.winner = turnOutput.winner; + if (!state.winner) { + state.currentPlayer = state.currentPlayer === 'X' ? 'O' : 'X'; + state.turn = turnNumber; + } + }); + if (game.value.winner) break; + } + + return game.value; } +}); - return game.value; -} -registry.asCommand('start', start); +const turn = registry.register({ + schema: 'turn ', + async run(game: TicTacToeGame, turnPlayer: PlayerType, turnNumber: number) { + const {player, row, col} = await game.prompt( + 'play ', + (command) => { + const [player, row, col] = command.params as [PlayerType, number, number]; -async function turn(game: TicTacToeGame, turnPlayer: PlayerType, turnNumber: number) { - const {player, row, col} = await game.prompt( - 'play ', - (command) => { - const [player, row, col] = command.params as [PlayerType, number, number]; + if (player !== turnPlayer) { + throw `Invalid player: ${player}. Expected ${turnPlayer}.`; + } else if (!isValidMove(row, col)) { + throw `Invalid position: (${row}, ${col}). Must be between 0 and ${BOARD_SIZE - 1}.`; + } else if (isCellOccupied(game, row, col)) { + throw `Cell (${row}, ${col}) is already occupied.`; + } else { + return { player, row, col }; + } + }, + game.value.currentPlayer + ); - if (player !== turnPlayer) { - throw `Invalid player: ${player}. Expected ${turnPlayer}.`; - } else if (!isValidMove(row, col)) { - throw `Invalid position: (${row}, ${col}). Must be between 0 and ${BOARD_SIZE - 1}.`; - } else if (isCellOccupied(game, row, col)) { - throw `Cell (${row}, ${col}) is already occupied.`; - } else { - return { player, row, col }; - } - }, - game.value.currentPlayer - ); + placePiece(game, row, col, turnPlayer); - placePiece(game, row, col, turnPlayer); + const winner = checkWinner(game); + if (winner) return { winner }; + if (turnNumber >= MAX_TURNS) return { winner: 'draw' as WinnerType }; - const winner = checkWinner(game); - if (winner) return { winner }; - if (turnNumber >= MAX_TURNS) return { winner: 'draw' as WinnerType }; - - return { winner: null }; -} -const turnCommand = registry.asCommand('turn ', turn); + return { winner: null }; + } +}); function isValidMove(row: number, col: number): boolean { return !isNaN(row) && !isNaN(col) && row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE; diff --git a/src/utils/command/command-registry.ts b/src/utils/command/command-registry.ts index 1375f86..4f8a774 100644 --- a/src/utils/command/command-registry.ts +++ b/src/utils/command/command-registry.ts @@ -18,7 +18,16 @@ type CanRunParsed = { } export class CommandRegistry extends Map>{ - register>({schema,run}: CommandDef) { + register>(...args: [schema: CommandSchema | string, run: TFunc] | [CommandDef]){ + let schema: CommandSchema | string; + let run: TFunc; + if(args.length === 1){ + schema = args[0].schema; + run = args[0].run; + }else{ + schema = args[0]; + run = args[1]; + } const parsedSchema = typeof schema === 'string' ? parseCommandSchema(schema) : schema; registerCommand(this, { schema: parsedSchema,