refactor: update samples

This commit is contained in:
hypercross 2026-04-06 10:10:58 +08:00
parent 70b1ac1e43
commit 129c58fb08
3 changed files with 95 additions and 60 deletions

View File

@ -23,7 +23,7 @@ export const registry = createGameCommandRegistry<BoopState>();
/** /**
* *
*/ */
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; const value = game.value;
// 从玩家supply中找到对应类型的棋子 // 从玩家supply中找到对应类型的棋子
const part = findPartInRegion(game, player, type); 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 }; return { row, col, player, type, partId };
} }
const placeCommand = registry.asCommand( 'place <row:number> <col:number> <player> <type>', place); const place = registry.register({
schema: 'place <row:number> <col:number> <player> <type>',
run: handlePlace
});
/** /**
* boop - * 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[] = []; const booped: string[] = [];
await game.produceAsync(state => { await game.produceAsync(state => {
@ -85,12 +88,15 @@ async function boop(game: BoopGame, row: number, col: number, type: PieceType) {
return { booped }; return { booped };
} }
const boopCommand = registry.asCommand('boop <row:number> <col:number> <type>', boop); const boop = registry.register({
schema: 'boop <row:number> <col:number> <type>',
run: handleBoop
});
/** /**
* (线) * (线)
*/ */
async function checkWin(game: BoopGame): Promise<WinnerType | null> { async function handleCheckWin(game: BoopGame): Promise<WinnerType | null> {
for(const line of getLineCandidates()){ for(const line of getLineCandidates()){
let whites = 0; let whites = 0;
let blacks = 0; let blacks = 0;
@ -109,12 +115,15 @@ async function checkWin(game: BoopGame): Promise<WinnerType | null> {
} }
return null; 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<string>(); const toUpgrade = new Set<string>();
for(const line of getLineCandidates()){ for(const line of getLineCandidates()){
let whites = 0; 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) { while (true) {
const currentPlayer = game.value.currentPlayer; const currentPlayer = game.value.currentPlayer;
const turnOutput = await turnCommand(game, currentPlayer); const turnOutput = await turn(game, currentPlayer);
await game.produceAsync(state => { await game.produceAsync(state => {
state.winner = turnOutput.winner; state.winner = turnOutput.winner;
@ -163,9 +175,12 @@ async function setup(game: BoopGame) {
return game.value; 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个棋子都在棋盘上且没有获胜,强制升级一个小猫 // 检查8-piece规则: 如果玩家所有8个棋子都在棋盘上且没有获胜,强制升级一个小猫
const playerPieces = Object.values(game.value.pieces).filter( const playerPieces = Object.values(game.value.pieces).filter(
p => p.player === turnPlayer && p.regionId === 'board' 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]); moveToRegion(cat || part, null, state.regions[turnPlayer]);
}); });
} }
const checkFullBoard = registry.register({
schema: 'check-full-board <player:string>',
run: handleCheckFullBoard
});
async function turn(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]', 'play <player> <row:number> <col:number> [type:string]',
(command) => { (command) => {
@ -229,13 +248,16 @@ async function turn(game: BoopGame, turnPlayer: PlayerType) {
); );
const pieceType = type === 'cat' ? 'cat' : 'kitten'; const pieceType = type === 'cat' ? 'cat' : 'kitten';
await placeCommand(game, row, col, turnPlayer, pieceType); await place(game, row, col, turnPlayer, pieceType);
await boopCommand(game, row, col, pieceType); await boop(game, row, col, pieceType);
const winner = await checkWinCommand(game); const winner = await checkWin(game);
if(winner) return { winner: winner }; if(winner) return { winner: winner };
await checkGraduatesCommand(game); await checkGraduates(game);
await checkFullBoard(game, turnPlayer); await checkFullBoard(game, turnPlayer);
return { winner: null }; return { winner: null };
} }
const turnCommand = registry.asCommand('turn <player>', turn); const turn = registry.register({
schema: 'turn <player:string>',
run: handleTurn
});

View File

@ -36,11 +36,13 @@ export type TicTacToeState = ReturnType<typeof createInitialState>;
export type TicTacToeGame = IGameContext<TicTacToeState>; export type TicTacToeGame = IGameContext<TicTacToeState>;
export const registry = createGameCommandRegistry<TicTacToeState>(); export const registry = createGameCommandRegistry<TicTacToeState>();
async function start(game: TicTacToeGame) { registry.register({
schema: 'start',
async run(game: TicTacToeGame) {
while (true) { while (true) {
const currentPlayer = game.value.currentPlayer; const currentPlayer = game.value.currentPlayer;
const turnNumber = game.value.turn + 1; const turnNumber = game.value.turn + 1;
const turnOutput = await turnCommand(game, currentPlayer, turnNumber); const turnOutput = await turn(game, currentPlayer, turnNumber);
game.produce(state => { game.produce(state => {
state.winner = turnOutput.winner; state.winner = turnOutput.winner;
@ -54,9 +56,11 @@ async function start(game: TicTacToeGame) {
return game.value; return game.value;
} }
registry.asCommand('start', start); });
async function turn(game: TicTacToeGame, turnPlayer: PlayerType, turnNumber: number) { const turn = registry.register({
schema: 'turn <player> <turnNumber:number>',
async run(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>', 'play <player> <row:number> <col:number>',
(command) => { (command) => {
@ -83,7 +87,7 @@ async function turn(game: TicTacToeGame, turnPlayer: PlayerType, turnNumber: num
return { winner: null }; return { winner: null };
} }
const turnCommand = registry.asCommand('turn <player:string> <turnNumber:int>', turn); });
function isValidMove(row: number, col: number): boolean { function isValidMove(row: number, col: number): boolean {
return !isNaN(row) && !isNaN(col) && row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE; return !isNaN(row) && !isNaN(col) && row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE;

View File

@ -18,7 +18,16 @@ type CanRunParsed = {
} }
export class CommandRegistry<TContext> extends Map<string, CommandRunner<TContext>>{ export class CommandRegistry<TContext> extends Map<string, CommandRunner<TContext>>{
register<TFunc extends CommandFunction<TContext>>({schema,run}: CommandDef<TContext, TFunc>) { register<TFunc extends CommandFunction<TContext>>(...args: [schema: CommandSchema | string, run: TFunc] | [CommandDef<TContext, TFunc>]){
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; const parsedSchema = typeof schema === 'string' ? parseCommandSchema(schema) : schema;
registerCommand(this, { registerCommand(this, {
schema: parsedSchema, schema: parsedSchema,