refactor: update api

This commit is contained in:
2026-04-06 10:39:10 +08:00
parent 129c58fb08
commit e673f60657
4 changed files with 45 additions and 47 deletions
+12 -8
View File
@@ -4,14 +4,13 @@ import type {
CommandRegistry,
PromptEvent,
CommandRunnerContextExport,
CommandResult
} from '@/utils/command';
import type { MutableSignal } from '@/utils/mutable-signal';
import {createGameContext, IGameContext} from './game';
import {createGameCommandRegistry, createGameContext, IGameContext} from './game';
export type GameHostStatus = 'created' | 'running' | 'disposed';
export class GameHost<TState extends Record<string, unknown>> {
export class GameHost<TState extends Record<string, unknown>, TResult=unknown> {
readonly context: IGameContext<TState>;
readonly status: ReadonlySignal<GameHostStatus>;
readonly activePromptSchema: ReadonlySignal<CommandSchema | null>;
@@ -19,6 +18,7 @@ export class GameHost<TState extends Record<string, unknown>> {
private _state: MutableSignal<TState>;
private _commands: CommandRunnerContextExport<IGameContext<TState>>;
private _start: (ctx: IGameContext<TState>) => Promise<TResult>;
private _status: Signal<GameHostStatus>;
private _activePromptSchema: Signal<CommandSchema | null>;
private _activePromptPlayer: Signal<string | null>;
@@ -29,12 +29,14 @@ export class GameHost<TState extends Record<string, unknown>> {
constructor(
registry: CommandRegistry<IGameContext<TState>>,
createInitialState: () => TState,
start: (ctx: IGameContext<TState>) => Promise<TResult>
) {
this._createInitialState = createInitialState;
this._eventListeners = new Map();
const initialState = createInitialState();
this.context = createGameContext(registry, initialState);
this._start = start;
this._status = new Signal<GameHostStatus>('created');
this.status = this._status;
@@ -94,7 +96,7 @@ export class GameHost<TState extends Record<string, unknown>> {
this._state.clearInterruptions();
}
start(startCommand: string): Promise<CommandResult<unknown>> {
start(): Promise<TResult> {
if (this._isDisposed) {
throw new Error('GameHost is disposed');
}
@@ -104,7 +106,7 @@ export class GameHost<TState extends Record<string, unknown>> {
const initialState = this._createInitialState();
this._state.value = initialState as any;
const promise = this._commands.run(startCommand);
const promise = this._start(this.context);
this._status.value = 'running';
this._emitEvent('start');
@@ -147,16 +149,18 @@ export class GameHost<TState extends Record<string, unknown>> {
}
}
export type GameModule<TState extends Record<string, unknown>> = {
registry: CommandRegistry<IGameContext<TState>>;
export type GameModule<TState extends Record<string, unknown>, TResult=unknown> = {
registry?: CommandRegistry<IGameContext<TState>>;
createInitialState: () => TState;
start: (ctx: IGameContext<TState>) => Promise<TResult>;
}
export function createGameHost<TState extends Record<string, unknown>>(
gameModule: GameModule<TState>
): GameHost<TState> {
return new GameHost(
gameModule.registry,
gameModule.registry || createGameCommandRegistry(),
gameModule.createInitialState,
gameModule.start
);
}
+1 -5
View File
@@ -159,7 +159,7 @@ const checkGraduates = registry.register({
run: handleCheckGraduates
});
async function handleStart(game: BoopGame) {
export async function start(game: BoopGame) {
while (true) {
const currentPlayer = game.value.currentPlayer;
const turnOutput = await turn(game, currentPlayer);
@@ -175,10 +175,6 @@ async function handleStart(game: BoopGame) {
return game.value;
}
const start = registry.register({
schema: 'start',
run: handleStart
});
async function handleCheckFullBoard(game: BoopGame, turnPlayer: PlayerType){
// 检查8-piece规则: 如果玩家所有8个棋子都在棋盘上且没有获胜,强制升级一个小猫
+16 -19
View File
@@ -36,27 +36,24 @@ export type TicTacToeState = ReturnType<typeof createInitialState>;
export type TicTacToeGame = IGameContext<TicTacToeState>;
export const registry = createGameCommandRegistry<TicTacToeState>();
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);
export async function start(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;
}
return game.value;
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;
}
const turn = registry.register({
schema: 'turn <player> <turnNumber:number>',