diff --git a/QWEN.md b/QWEN.md index ceeda0d..b1272e6 100644 --- a/QWEN.md +++ b/QWEN.md @@ -17,113 +17,6 @@ `boardgame-core`的内容可以在`framework/node_modules/boardgame-core`找到。 这个文件夹被.gitignore忽略,查看时需要绕开这一限制。 -## 编写GameModule - -游戏逻辑以GameModule的形式定义: - -```typescript -import {createGameCommandRegistry, IGameContext} from "boardgame-core"; - -// 创建mutative游戏初始状态 -export function createInitialState(): GameState { - //... -} - -// 运行游戏 -export async function start(game: IGameContext) { - // ... -} - -// 可选 -export const registry = createGameCommandRegistry(); -``` - -使用以下步骤创建GameModule: - -### 1. 定义状态 - -通常使用一个`regions: Record`和一个`parts: Record>`来记录桌游物件的摆放。 - -```typescript -import {Region} from "boardgame-core"; - -type GameState = { - regions: { - white: Region, - black: Region, - board: Region, - }, - pieces: Record>, - currentPlayer: PlayerType, - winner: WinnerType, -}; -``` - -游戏的部件可以从`csv`加载。详情见`boop-game/node_modules/inline-schema/`。 -``` -/// parts.csv -type, player, count -string, string, number -cat, white, 8 -cat, black, 8 - -/// parts.csv.d.ts -type PartsTable = { - type: string; - player: string; - count: number; - }[]; - -declare const data: PartsTable; -export default data; -``` - -### 2. 定义流程 - -使用`async function start(game: IGameContext)`作为入口。 - -使用`game.value`读取游戏当前状态 -```typescript -async function gameEnd(game: IGameContext) { - return game.value.winner; -} -``` - -需要修改状态时,使用`game.produce`或`game.produceAsync`。 - -```typescript -async function start(game: IGameContext) { - await game.produceAsync(state => { - state.currentPlayer = 'white'; - }); -} -``` - -需要等待玩家交互时,使用`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( - prompts.play, - (player, row, col) => { - if (player !== currentPlayer) - throw `Wrong player!` - return {player, row, col}; - } - ) -} -``` - -### 3. 编写测试 - -使用`vitest`编写测试,测试应当使用`GameHost`来模拟游戏环境。 - ## 编写Phaser App 使用`framework/src/ui/PhaserBridge`来创建Phaser App。 @@ -136,6 +29,9 @@ async function turn(game: IGameContext, currentPlayer: PlayerType) { export class GameHost, TResult=unknown> { // 获取游戏状态的只读快照 get state(): TState{} + // 获取随机数 + get rng(): ReadonlyRNG{} + // 运行状态 readonly status: ReadonlySignal; @@ -151,7 +47,7 @@ export class GameHost, TResult=unknown> { addInterruption(promise: Promise): void {} // 开始或者重新开始游戏 - start(): Promise{} + start(seed?: number): Promise{} // 销毁 dispose(): void {} diff --git a/docs/GameModule.md b/docs/GameModule.md new file mode 100644 index 0000000..61ca864 --- /dev/null +++ b/docs/GameModule.md @@ -0,0 +1,107 @@ +## 编写GameModule + +游戏逻辑以GameModule的形式定义: + +```typescript +import {createGameCommandRegistry, IGameContext} from "boardgame-core"; + +// 创建mutative游戏初始状态 +export function createInitialState(): GameState { + //... +} + +// 运行游戏 +export async function start(game: IGameContext) { + // ... +} + +// 可选 +export const registry = createGameCommandRegistry(); +``` + +使用以下步骤创建GameModule: + +### 1. 定义状态 + +通常使用一个`regions: Record`和一个`parts: Record>`来记录桌游物件的摆放。 + +```typescript +import {Region} from "boardgame-core"; + +type GameState = { + regions: { + white: Region, + black: Region, + board: Region, + }, + pieces: Record>, + currentPlayer: PlayerType, + winner: WinnerType, +}; +``` + +游戏的部件可以从`csv`加载。详情见`boop-game/node_modules/inline-schema/`。 +``` +/// parts.csv +type, player, count +string, string, number +cat, white, 8 +cat, black, 8 + +/// parts.csv.d.ts +type PartsTable = { + type: string; + player: string; + count: number; + }[]; + +declare const data: PartsTable; +export default data; +``` + +### 2. 定义流程 + +使用`async function start(game: IGameContext)`作为入口。 + +使用`game.value`读取游戏当前状态 +```typescript +async function gameEnd(game: IGameContext) { + return game.value.winner; +} +``` + +需要修改状态时,使用`game.produce`或`game.produceAsync`。 + +```typescript +async function start(game: IGameContext) { + await game.produceAsync(state => { + state.currentPlayer = 'white'; + }); +} +``` + +需要等待玩家交互时,使用`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( + prompts.play, + (player, row, col) => { + if (player !== currentPlayer) + throw `Wrong player!` + return {player, row, col}; + } + ) +} +``` + +### 3. 编写测试 + +使用`vitest`编写测试,测试应当使用`GameHost`来模拟游戏环境。 +