feat: refactor stage to multiple route design

This commit is contained in:
wancat committed 2023-08-30 18:05:11 +08:00
1 parent 52c6c6ab93
commit e16b328892
6 files changed
+50 -31

No files matched your search

+10 -8
View File
@@ -8,7 +8,7 @@ stages:
- id: helloworld - id: helloworld
condition: condition:
command: command:
- echo Hello World! - echo Hello World
responses: responses:
- type: narrative - type: narrative
content: content:
@@ -22,12 +22,13 @@ stages:
- 由於長久以來依賴於薩加,世人已失去了「指令」的力量,即將走向衰敗和滅亡的命運。 - 由於長久以來依賴於薩加,世人已失去了「指令」的力量,即將走向衰敗和滅亡的命運。
- 你的任務,就是找回被世人遺忘的指令,奪回 Linux 之根,成為 Linux 之王。 - 你的任務,就是找回被世人遺忘的指令,奪回 Linux 之根,成為 Linux 之王。
- 首先,你必須要學會如何使用指令。 - 首先,你必須要學會如何使用指令。
- 一個指令是由一個指令名稱和一些參數所組成的,而指令名稱和參數之間是以空白字元分隔。 - 你要學習的第一個指令,是「發現」的指令:`ls`。ls 可以用來查看一個目錄中有哪些檔案。
- 例如,你可以輸入 `ls` 來查看目前的目錄下有哪些檔案。 - 現在,請你輸入 `ls` 來查看目前的目錄下有哪些檔案。
hints: hints:
- 使用 `ls` 指令來查看目前的目錄下有哪些檔案。 - 使用 `ls` 指令來查看目前的目錄下有哪些檔案。
next: ls
- id: ls - id: ls
requirements:
- helloworld
condition: condition:
command: command:
- ls - ls
@@ -47,8 +48,9 @@ stages:
hints: hints:
- 使用 `cat [檔案名稱]` 指令來查看檔案內容。 - 使用 `cat [檔案名稱]` 指令來查看檔案內容。
- 使用 `Tab` 鍵來取得指令提示。 - 使用 `Tab` 鍵來取得指令提示。
next: cat
- id: cat - id: cat
requirements:
- ls
condition: condition:
command: command:
- cat forgotten_scroll.txt - cat forgotten_scroll.txt
@@ -58,8 +60,9 @@ stages:
content: content:
- 你找到的是一個被遺忘的卷軸,上面寫著解除封印的咒語。 - 你找到的是一個被遺忘的卷軸,上面寫著解除封印的咒語。
- 使用你已經知道的 `echo` 指令來詠唱咒語。 - 使用你已經知道的 `echo` 指令來詠唱咒語。
next: echo - id: END
- id: echo requirements:
- cat
condition: condition:
command: command:
- echo Unix, rise and guide me! - echo Unix, rise and guide me!
@@ -72,4 +75,3 @@ stages:
content: content:
- 恭喜您,我的指令官,您已成功解除了封印。 - 恭喜您,我的指令官,您已成功解除了封印。
- 請跟著在接下了關卡,一步步取回 Linux 之根吧! - 請跟著在接下了關卡,一步步取回 Linux 之根吧!
next: END
@@ -36,7 +36,6 @@ export async function newCommand(req, res) {
} }
session.lastActivityAt = new Date() session.lastActivityAt = new Date()
await session.save()
const c = new Command({ const c = new Command({
session, session,
@@ -54,4 +53,5 @@ export async function newCommand(req, res) {
console.log(response) console.log(response)
res.status(201).json(response) res.status(201).json(response)
await session.save()
} }
+31 -19
View File
@@ -50,20 +50,15 @@ export default class CommandHandler {
const graph = new FileGraph(this.session.graph) const graph = new FileGraph(this.session.graph)
graph.discover(this.additionalData.discover) graph.discover(this.additionalData.discover)
this.session.graph = graph this.session.graph = graph
await this.session.save()
} }
async run() { getStages() {
const quest = await Quest.findById(this.session.quest) return this.quest.stages.filter((s) =>
const stage = quest.stages.find((s) => s.id === this.session.progress) s.requirements.every((r) => this.session.completed.includes(r))
if (!stage) { )
console.error('stage not found', this.session.progress)
return {}
} }
this.handleEvent() matchStage(stage) {
this.handleCommand()
const commandMatch = checkMatch( const commandMatch = checkMatch(
stage.condition.command, stage.condition.command,
this.commandInput.command this.commandInput.command
@@ -79,22 +74,39 @@ export default class CommandHandler {
if (!commandMatch || !outputMatch || !errorMatch) return {} if (!commandMatch || !outputMatch || !errorMatch) return {}
this.session.completion.push(this.session.progress) this.session.completed.push(stage.id)
this.session.hints.push(...stage.hints) this.session.hints.push(...stage.hints)
if (stage.id === 'END') {
this.session.progress = stage.next
await this.session.save()
if (stage.next === 'END') {
this.session.status = 'finished' this.session.status = 'finished'
this.session.finishedAt = new Date() this.session.finishedAt = new Date()
await this.session.save()
} }
return { return {
responses: stage.responses, responses: stage.responses,
hints: stage.hints, hints: stage.hints,
end: stage.next === 'END', }
}
async run() {
this.quest = await Quest.findById(this.session.quest)
const stages = this.getStages()
if (stages.length === 0) {
console.error('stage not found', this.session.progress)
return {}
}
console.log('stages', stages)
this.handleEvent()
this.handleCommand()
const response = stages.reduce(
(r, s) => ({ ...r, ...this.matchStage(s) }),
{}
)
return {
end: this.session.status === 'finished',
...response,
} }
} }
} }
+6
View File
@@ -15,6 +15,12 @@ const stageSchema = new Schema({
type: String, type: String,
required: true, required: true,
}, },
requirements: [
{
type: String,
required: true,
},
],
condition: { condition: {
command: { command: {
type: [String], type: [String],
+1 -2
View File
@@ -39,8 +39,7 @@ const Session = model(
default: Date.now, default: Date.now,
required: true, required: true,
}, },
progress: String, completed: [String],
completion: [String],
hints: [String], hints: [String],
graph: { graph: {
type: nodeSchema, type: nodeSchema,
+1 -1
View File
@@ -392,7 +392,7 @@ components:
type: string type: string
description: current stage id description: current stage id
example: helloworld example: helloworld
completion: completed:
type: array type: array
description: list of completed stage ids description: list of completed stage ids
items: items: