From dae9e841ca910137ee77b2666dbc0fbb16172f06 Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Fri, 18 Apr 2025 15:04:28 +0800 Subject: [PATCH] feat: add run command --- packages/game/src/Quest.ts | 21 ++++++++++++- packages/game/src/Session.ts | 18 ++++++++++-- packages/game/test/session.test.ts | 47 ++++++++++++++++++++++++++---- 3 files changed, 77 insertions(+), 9 deletions(-) diff --git a/packages/game/src/Quest.ts b/packages/game/src/Quest.ts index 0a352b8..e7a3e5d 100644 --- a/packages/game/src/Quest.ts +++ b/packages/game/src/Quest.ts @@ -1,11 +1,16 @@ +/* eslint-disable no-await-in-loop */ import { IQuest, IStage } from './schema' import { Stage } from './Stage' +import { ICommand, IFileExistenceChecker } from './types' export class Quest { private stages: Stage[] private quest: IQuest - constructor(quest: IQuest) { + constructor( + quest: IQuest, + private checker: IFileExistenceChecker + ) { this.quest = quest this.stages = quest.stages.map((stage: IStage) => new Stage(stage)) } @@ -13,4 +18,18 @@ export class Quest { getActiveStages(completed: string[]) { return this.stages.filter((stage) => stage.active(completed)) } + + async findSatisfiedStage( + command: ICommand, + completed: string[] + ): Promise { + const stages = this.getActiveStages(completed) + for (const stage of stages) { + const satisfies = await stage.satisfies(command, this.checker) + if (satisfies) { + return stage.id + } + } + return null + } } diff --git a/packages/game/src/Session.ts b/packages/game/src/Session.ts index 4664100..9750c48 100644 --- a/packages/game/src/Session.ts +++ b/packages/game/src/Session.ts @@ -1,14 +1,18 @@ import { Quest } from './Quest' import { IQuest } from './schema' -import { ISession } from './types' +import { ICommand, ISession, IFileExistenceChecker } from './types' export class Session implements ISession { private completed: string[] = [] private quest: Quest - constructor({ completedStages }: ISession, quest: IQuest) { + constructor( + { completedStages }: ISession, + quest: IQuest, + checker: IFileExistenceChecker + ) { this.completed = completedStages - this.quest = new Quest(quest) + this.quest = new Quest(quest, checker) } get completedStages() { @@ -22,4 +26,12 @@ export class Session implements ISession { getActiveStages(): string[] { return this.quest.getActiveStages(this.completed).map((stage) => stage.id) } + + async runCommand(command: ICommand) { + const stageId = await this.quest.findSatisfiedStage(command, this.completed) + if (stageId) { + this.complete(stageId) + } + return stageId + } } diff --git a/packages/game/test/session.test.ts b/packages/game/test/session.test.ts index 73dfee2..5de1353 100644 --- a/packages/game/test/session.test.ts +++ b/packages/game/test/session.test.ts @@ -1,6 +1,7 @@ import { expect, describe, it } from '@jest/globals' import { IQuest } from '../src/schema' import { Session } from '../src/Session' +import { MockFileChecker } from './asyncCondition.test' const quest: IQuest = { id: 'quest1', @@ -12,25 +13,33 @@ const quest: IQuest = { { id: 'stage1', requirements: [], - condition: {}, + condition: { + command: 'echo start', + }, response: { type: 'narrative', content: 'Narrative 1' }, }, { id: 'stage2', requirements: ['stage1'], - condition: {}, + condition: { + command: 'ls', + }, response: { type: 'narrative', content: 'Narrative 2' }, }, { id: 'stage3', requirements: ['stage1'], - condition: {}, + condition: { + command: 'mkdir hello', + }, response: { type: 'narrative', content: 'Narrative 3' }, }, { id: 'stage4', requirements: ['stage2', 'stage3'], - condition: {}, + condition: { + command: 'echo finish', + }, response: { type: 'narrative', content: 'Narrative 4' }, }, ], @@ -42,7 +51,8 @@ describe('Session', () => { { completedStages: [], }, - quest + quest, + new MockFileChecker() ) expect(session.getActiveStages()).toEqual(['stage1']) @@ -55,4 +65,31 @@ describe('Session', () => { session.complete('stage3') expect(session.getActiveStages()).toEqual(['stage4']) }) + + it('should run command', async () => { + const session = new Session( + { + completedStages: [], + }, + quest, + new MockFileChecker() + ) + expect(await session.runCommand({ command: 'hi' })).toBeNull() + expect(await session.runCommand({ command: 'echo start' })).toEqual( + 'stage1' + ) + + expect(await session.runCommand({ command: 'echo start' })).toBeNull() + expect(await session.runCommand({ command: 'ls' })).toEqual('stage2') + + expect(await session.runCommand({ command: 'echo finish' })).toBeNull() + + expect(await session.runCommand({ command: 'mkdir hello' })).toEqual( + 'stage3' + ) + + expect(await session.runCommand({ command: 'echo finish' })).toEqual( + 'stage4' + ) + }) })