diff --git a/.qwenignore b/.qwenignore index 22fb128..322e2e2 100644 --- a/.qwenignore +++ b/.qwenignore @@ -1 +1,2 @@ -!node_modules \ No newline at end of file +!node_modules +!debug \ No newline at end of file diff --git a/QWEN.md b/QWEN.md index 797d208..ceeda0d 100644 --- a/QWEN.md +++ b/QWEN.md @@ -99,14 +99,20 @@ async function start(game: IGameContext) { } ``` -需要等待玩家交互时,使用`await game.prompt(schema, validator, player)`。 +需要等待玩家交互时,使用`await game.prompt(promptDef, validator, player)`。 ```typescript +import {createPromptDef} from "boardgame-core"; + +export const prompts = { + play: createPromptDef<[PlayerType, number, number]>('play '), +} + async function turn(game: IGameContext, currentPlayer: PlayerType) { const {player, row, col} = await game.prompt( - 'play ', + prompts.play, (player, row, col) => { - if(player !== currentPlayer) + if (player !== currentPlayer) throw `Wrong player!` return {player, row, col}; } @@ -138,7 +144,8 @@ export class GameHost, TResult=unknown> { readonly activePromptPlayer: ReadonlySignal; // 玩家响应activePrompt的输入,若报错则返回string,否则返回null - onInput(input: string): string | null {} + // promptDef应当从game module中导出 + tryAnswerPrompt(promptDef: Promptdef,...args: TArgs): string | null {} // 添加中断,context.produceAsync会等待所有中断结束之后再继续 addInterruption(promise: Promise): void {} diff --git a/packages/boop-game/src/game/commands.ts b/packages/boop-game/src/game/commands.ts index 15750f0..aaccb69 100644 --- a/packages/boop-game/src/game/commands.ts +++ b/packages/boop-game/src/game/commands.ts @@ -7,7 +7,7 @@ WinnerType, WIN_LENGTH, MAX_PIECES_PER_PLAYER, - BoopGame, + BoopGame, prompts, } from "./data"; import {createGameCommandRegistry, Command, moveToRegion} from "boardgame-core"; import { @@ -184,8 +184,8 @@ async function handleCheckFullBoard(game: BoopGame, turnPlayer: PlayerType){ } const partId = await game.prompt( - 'play [type:string]', - (player: PlayerType, row: number, col: number, type?: PieceType) => { + prompts.graduate, + (player, row, col) => { if (player !== turnPlayer) { throw `无效的玩家: ${player},期望的是 ${turnPlayer}。`; } @@ -213,8 +213,8 @@ const checkFullBoard = registry.register('check-full-board', handleCheckFullBoar async function handleTurn(game: BoopGame, turnPlayer: PlayerType) { const {row, col, type} = await game.prompt( - 'play [type:string]', - (player: PlayerType, row: number, col: number, type?: PieceType) => { + prompts.play, + (player, row, col, type?) => { const pieceType = type === 'cat' ? 'cat' : 'kitten'; if (player !== turnPlayer) { @@ -246,13 +246,4 @@ async function handleTurn(game: BoopGame, turnPlayer: PlayerType) { await handleCheckFullBoard(game, turnPlayer); return { winner: null }; } -const turn = registry.register('turn ', handleTurn); - -export const prompts = { - play: (player: PlayerType, row: number, col: number, type?: PieceType) => { - if (type) { - return `play ${player} ${row} ${col} ${type}`; - } - return `play ${player} ${row} ${col}`; - }, -}; \ No newline at end of file +const turn = registry.register('turn ', handleTurn); \ No newline at end of file diff --git a/packages/boop-game/src/game/data.ts b/packages/boop-game/src/game/data.ts index a957e28..737e971 100644 --- a/packages/boop-game/src/game/data.ts +++ b/packages/boop-game/src/game/data.ts @@ -1,5 +1,5 @@ import parts from './parts.csv'; -import {createRegion, moveToRegion, Region} from "boardgame-core"; +import {createRegion, moveToRegion, Region, createPromptDef} from "boardgame-core"; import {createPartsFromTable} from "boardgame-core"; import {Part} from "boardgame-core"; import {IGameContext} from "boardgame-core"; @@ -14,6 +14,10 @@ export type WinnerType = PlayerType | 'draw' | null; export type RegionType = 'white' | 'black' | 'board' | ''; export type BoopPartMeta = { player: PlayerType; type: PieceType }; export type BoopPart = Part; +export const prompts = { + play: createPromptDef<[PlayerType, number, number, PieceType?]>('play [type:string]'), + graduate: createPromptDef<[PlayerType, number, number]>('graduate '), +} export function createInitialState() { const pieces = createPartsFromTable( diff --git a/packages/boop-game/src/scenes/GameScene.ts b/packages/boop-game/src/scenes/GameScene.ts index c0fc3f9..341a292 100644 --- a/packages/boop-game/src/scenes/GameScene.ts +++ b/packages/boop-game/src/scenes/GameScene.ts @@ -73,8 +73,7 @@ export class GameScene extends GameHostScene { private handleCellClick(row: number, col: number): void { const selectedType = this.pieceTypeSelector.getSelectedType(); - const cmd = prompts.play(this.state.currentPlayer, row, col, selectedType); - const error = this.gameHost.onInput(cmd); + const error = this.gameHost.tryAnswerPrompt(prompts.play, this.state.currentPlayer, row, col, selectedType); if (error) { this.errorOverlay.show(error); } @@ -82,8 +81,7 @@ export class GameScene extends GameHostScene { private handlePieceClick(row: number, col: number): void { // 棋盘满时,点击棋子触发升级 - const cmd = prompts.play(this.state.currentPlayer, row, col); - const error = this.gameHost.onInput(cmd); + const error = this.gameHost.tryAnswerPrompt(prompts.graduate, this.state.currentPlayer, row, col); if (error) { this.errorOverlay.show(error); } diff --git a/packages/sample-game/src/game/tic-tac-toe.ts b/packages/sample-game/src/game/tic-tac-toe.ts index f0a289d..b7a4bb2 100644 --- a/packages/sample-game/src/game/tic-tac-toe.ts +++ b/packages/sample-game/src/game/tic-tac-toe.ts @@ -1,6 +1,7 @@ import { createGameCommandRegistry, Part, createRegion, - IGameContext, createRegionAxis, GameModule + IGameContext, createRegionAxis, GameModule, + createPromptDef } from 'boardgame-core'; const BOARD_SIZE = 3; @@ -21,6 +22,9 @@ export type WinnerType = PlayerType | 'draw' | null; export type TicTacToePart = Part<{ player: PlayerType }>; export type TicTacToeState = ReturnType; export type TicTacToeGame = IGameContext; +export const prompts = { + play: createPromptDef<[PlayerType, number, number]>('play '), +} export function createInitialState() { return { @@ -57,8 +61,8 @@ export async function start(game: TicTacToeGame) { async function handleTurn(game: TicTacToeGame, turnPlayer: PlayerType, turnNumber: number) { const {player, row, col} = await game.prompt( - 'play ', - (player: PlayerType, row: number, col: number) => { + prompts.play, + (player, row, col) => { if (player !== turnPlayer) { throw `Invalid player: ${player}. Expected ${turnPlayer}.`; } else if (!isValidMove(row, col)) { @@ -130,10 +134,4 @@ export const gameModule: GameModule = { registry, createInitialState, start -}; - -export const prompts = { - play: (player: PlayerType, row: number, col: number) => { - return `play ${player} ${row} ${col}`; - }, }; \ No newline at end of file diff --git a/packages/sample-game/src/scenes/GameScene.ts b/packages/sample-game/src/scenes/GameScene.ts index a1f2020..39cb614 100644 --- a/packages/sample-game/src/scenes/GameScene.ts +++ b/packages/sample-game/src/scenes/GameScene.ts @@ -61,8 +61,7 @@ export class GameScene extends GameHostScene { if (this.state.winner) return; if (this.isCellOccupied(row, col)) return; - const cmd = prompts.play(this.state.currentPlayer, row, col); - const error = this.gameHost.onInput(cmd); + const error = this.gameHost.tryAnswerPrompt(prompts.play, this.state.currentPlayer, row, col); if (error) { console.warn('Invalid move:', error); }