refactor: prompt def udpate
This commit is contained in:
parent
bf20e53c6b
commit
20f722818d
|
|
@ -1 +1,2 @@
|
||||||
!node_modules
|
!node_modules
|
||||||
|
!debug
|
||||||
15
QWEN.md
15
QWEN.md
|
|
@ -99,14 +99,20 @@ async function start(game: IGameContext<GameState>) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
需要等待玩家交互时,使用`await game.prompt(schema, validator, player)`。
|
需要等待玩家交互时,使用`await game.prompt(promptDef, validator, player)`。
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
import {createPromptDef} from "boardgame-core";
|
||||||
|
|
||||||
|
export const prompts = {
|
||||||
|
play: createPromptDef<[PlayerType, number, number]>('play <player> <row:number> <col:number>'),
|
||||||
|
}
|
||||||
|
|
||||||
async function turn(game: IGameContext<GameState>, currentPlayer: PlayerType) {
|
async function turn(game: IGameContext<GameState>, currentPlayer: PlayerType) {
|
||||||
const {player, row, col} = await game.prompt(
|
const {player, row, col} = await game.prompt(
|
||||||
'play <player:string> <row:number> <col:number>',
|
prompts.play,
|
||||||
(player, row, col) => {
|
(player, row, col) => {
|
||||||
if(player !== currentPlayer)
|
if (player !== currentPlayer)
|
||||||
throw `Wrong player!`
|
throw `Wrong player!`
|
||||||
return {player, row, col};
|
return {player, row, col};
|
||||||
}
|
}
|
||||||
|
|
@ -138,7 +144,8 @@ export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
|
||||||
readonly activePromptPlayer: ReadonlySignal<string | null>;
|
readonly activePromptPlayer: ReadonlySignal<string | null>;
|
||||||
|
|
||||||
// 玩家响应activePrompt的输入,若报错则返回string,否则返回null
|
// 玩家响应activePrompt的输入,若报错则返回string,否则返回null
|
||||||
onInput(input: string): string | null {}
|
// promptDef应当从game module中导出
|
||||||
|
tryAnswerPrompt<TArgs extends any[]>(promptDef: Promptdef<TArgs>,...args: TArgs): string | null {}
|
||||||
|
|
||||||
// 添加中断,context.produceAsync会等待所有中断结束之后再继续
|
// 添加中断,context.produceAsync会等待所有中断结束之后再继续
|
||||||
addInterruption(promise: Promise<void>): void {}
|
addInterruption(promise: Promise<void>): void {}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
WinnerType,
|
WinnerType,
|
||||||
WIN_LENGTH,
|
WIN_LENGTH,
|
||||||
MAX_PIECES_PER_PLAYER,
|
MAX_PIECES_PER_PLAYER,
|
||||||
BoopGame,
|
BoopGame, prompts,
|
||||||
} from "./data";
|
} from "./data";
|
||||||
import {createGameCommandRegistry, Command, moveToRegion} from "boardgame-core";
|
import {createGameCommandRegistry, Command, moveToRegion} from "boardgame-core";
|
||||||
import {
|
import {
|
||||||
|
|
@ -184,8 +184,8 @@ async function handleCheckFullBoard(game: BoopGame, turnPlayer: PlayerType){
|
||||||
}
|
}
|
||||||
|
|
||||||
const partId = await game.prompt(
|
const partId = await game.prompt(
|
||||||
'play <player> <row:number> <col:number> [type:string]',
|
prompts.graduate,
|
||||||
(player: PlayerType, row: number, col: number, type?: PieceType) => {
|
(player, row, col) => {
|
||||||
if (player !== turnPlayer) {
|
if (player !== turnPlayer) {
|
||||||
throw `无效的玩家: ${player},期望的是 ${turnPlayer}。`;
|
throw `无效的玩家: ${player},期望的是 ${turnPlayer}。`;
|
||||||
}
|
}
|
||||||
|
|
@ -213,8 +213,8 @@ const checkFullBoard = registry.register('check-full-board', handleCheckFullBoar
|
||||||
|
|
||||||
async function handleTurn(game: BoopGame, turnPlayer: PlayerType) {
|
async function handleTurn(game: BoopGame, turnPlayer: PlayerType) {
|
||||||
const {row, col, type} = await game.prompt(
|
const {row, col, type} = await game.prompt(
|
||||||
'play <player> <row:number> <col:number> [type:string]',
|
prompts.play,
|
||||||
(player: PlayerType, row: number, col: number, type?: PieceType) => {
|
(player, row, col, type?) => {
|
||||||
const pieceType = type === 'cat' ? 'cat' : 'kitten';
|
const pieceType = type === 'cat' ? 'cat' : 'kitten';
|
||||||
|
|
||||||
if (player !== turnPlayer) {
|
if (player !== turnPlayer) {
|
||||||
|
|
@ -246,13 +246,4 @@ async function handleTurn(game: BoopGame, turnPlayer: PlayerType) {
|
||||||
await handleCheckFullBoard(game, turnPlayer);
|
await handleCheckFullBoard(game, turnPlayer);
|
||||||
return { winner: null };
|
return { winner: null };
|
||||||
}
|
}
|
||||||
const turn = registry.register('turn <player>', handleTurn);
|
const turn = registry.register('turn <player>', 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}`;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import parts from './parts.csv';
|
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 {createPartsFromTable} from "boardgame-core";
|
||||||
import {Part} from "boardgame-core";
|
import {Part} from "boardgame-core";
|
||||||
import {IGameContext} 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 RegionType = 'white' | 'black' | 'board' | '';
|
||||||
export type BoopPartMeta = { player: PlayerType; type: PieceType };
|
export type BoopPartMeta = { player: PlayerType; type: PieceType };
|
||||||
export type BoopPart = Part<BoopPartMeta>;
|
export type BoopPart = Part<BoopPartMeta>;
|
||||||
|
export const prompts = {
|
||||||
|
play: createPromptDef<[PlayerType, number, number, PieceType?]>('play <player> <row:number> <col:number> [type:string]'),
|
||||||
|
graduate: createPromptDef<[PlayerType, number, number]>('graduate <player> <row:number> <col:number>'),
|
||||||
|
}
|
||||||
|
|
||||||
export function createInitialState() {
|
export function createInitialState() {
|
||||||
const pieces = createPartsFromTable(
|
const pieces = createPartsFromTable(
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,7 @@ export class GameScene extends GameHostScene<BoopState> {
|
||||||
|
|
||||||
private handleCellClick(row: number, col: number): void {
|
private handleCellClick(row: number, col: number): void {
|
||||||
const selectedType = this.pieceTypeSelector.getSelectedType();
|
const selectedType = this.pieceTypeSelector.getSelectedType();
|
||||||
const cmd = prompts.play(this.state.currentPlayer, row, col, selectedType);
|
const error = this.gameHost.tryAnswerPrompt(prompts.play, this.state.currentPlayer, row, col, selectedType);
|
||||||
const error = this.gameHost.onInput(cmd);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
this.errorOverlay.show(error);
|
this.errorOverlay.show(error);
|
||||||
}
|
}
|
||||||
|
|
@ -82,8 +81,7 @@ export class GameScene extends GameHostScene<BoopState> {
|
||||||
|
|
||||||
private handlePieceClick(row: number, col: number): void {
|
private handlePieceClick(row: number, col: number): void {
|
||||||
// 棋盘满时,点击棋子触发升级
|
// 棋盘满时,点击棋子触发升级
|
||||||
const cmd = prompts.play(this.state.currentPlayer, row, col);
|
const error = this.gameHost.tryAnswerPrompt(prompts.graduate, this.state.currentPlayer, row, col);
|
||||||
const error = this.gameHost.onInput(cmd);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
this.errorOverlay.show(error);
|
this.errorOverlay.show(error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import {
|
import {
|
||||||
createGameCommandRegistry, Part, createRegion,
|
createGameCommandRegistry, Part, createRegion,
|
||||||
IGameContext, createRegionAxis, GameModule
|
IGameContext, createRegionAxis, GameModule,
|
||||||
|
createPromptDef
|
||||||
} from 'boardgame-core';
|
} from 'boardgame-core';
|
||||||
|
|
||||||
const BOARD_SIZE = 3;
|
const BOARD_SIZE = 3;
|
||||||
|
|
@ -21,6 +22,9 @@ export type WinnerType = PlayerType | 'draw' | null;
|
||||||
export type TicTacToePart = Part<{ player: PlayerType }>;
|
export type TicTacToePart = Part<{ player: PlayerType }>;
|
||||||
export type TicTacToeState = ReturnType<typeof createInitialState>;
|
export type TicTacToeState = ReturnType<typeof createInitialState>;
|
||||||
export type TicTacToeGame = IGameContext<TicTacToeState>;
|
export type TicTacToeGame = IGameContext<TicTacToeState>;
|
||||||
|
export const prompts = {
|
||||||
|
play: createPromptDef<[PlayerType, number, number]>('play <player> <row:number> <col:number>'),
|
||||||
|
}
|
||||||
|
|
||||||
export function createInitialState() {
|
export function createInitialState() {
|
||||||
return {
|
return {
|
||||||
|
|
@ -57,8 +61,8 @@ export async function start(game: TicTacToeGame) {
|
||||||
|
|
||||||
async function handleTurn(game: TicTacToeGame, turnPlayer: PlayerType, turnNumber: number) {
|
async function handleTurn(game: TicTacToeGame, turnPlayer: PlayerType, turnNumber: number) {
|
||||||
const {player, row, col} = await game.prompt(
|
const {player, row, col} = await game.prompt(
|
||||||
'play <player> <row:number> <col:number>',
|
prompts.play,
|
||||||
(player: PlayerType, row: number, col: number) => {
|
(player, row, col) => {
|
||||||
if (player !== turnPlayer) {
|
if (player !== turnPlayer) {
|
||||||
throw `Invalid player: ${player}. Expected ${turnPlayer}.`;
|
throw `Invalid player: ${player}. Expected ${turnPlayer}.`;
|
||||||
} else if (!isValidMove(row, col)) {
|
} else if (!isValidMove(row, col)) {
|
||||||
|
|
@ -130,10 +134,4 @@ export const gameModule: GameModule<TicTacToeState> = {
|
||||||
registry,
|
registry,
|
||||||
createInitialState,
|
createInitialState,
|
||||||
start
|
start
|
||||||
};
|
|
||||||
|
|
||||||
export const prompts = {
|
|
||||||
play: (player: PlayerType, row: number, col: number) => {
|
|
||||||
return `play ${player} ${row} ${col}`;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
@ -61,8 +61,7 @@ export class GameScene extends GameHostScene<TicTacToeState> {
|
||||||
if (this.state.winner) return;
|
if (this.state.winner) return;
|
||||||
if (this.isCellOccupied(row, col)) return;
|
if (this.isCellOccupied(row, col)) return;
|
||||||
|
|
||||||
const cmd = prompts.play(this.state.currentPlayer, row, col);
|
const error = this.gameHost.tryAnswerPrompt(prompts.play, this.state.currentPlayer, row, col);
|
||||||
const error = this.gameHost.onInput(cmd);
|
|
||||||
if (error) {
|
if (error) {
|
||||||
console.warn('Invalid move:', error);
|
console.warn('Invalid move:', error);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue