はじめに
前回は、バトル開始から1ターン終了までを普通の関数呼び出しで動かしました。
今回は、その処理を Section の階層に組み替えます。実行結果は前回のままです。
今回のポイント
- 処理の順番を、関数の中の呼び出しではなく、親 Section が子を前から並べる形にした
- 行動リストは
BattleStateに入れず、ターンの中だけで作るActionBufferに置いた。攻撃は Section を作ったときではなく、実行するときにその配列を読む - ログと最終HPは Step 1 から変えていない
ディレクトリ
増えたファイルは section.ts だけです。battle.ts と turn.ts は、処理を直接呼ぶ役から、Section を並べる役に変わっています。
Before
src/
├── main.ts
└── battle/
├── types.ts
├── battle.ts 登場と runTurn を直接呼ぶ
├── turn.ts 選択・順序・攻撃を直接呼ぶ
└── actions.ts 行動の処理
After
src/
├── main.ts
└── battle/
├── types.ts
├── section.ts 追加。Section と SectionRunner
├── battle.ts Battle が子 Section を並べる
├── turn.ts Turn が ActionBuffer と子 Section を並べる
└── actions.ts リーフ Section から従来の処理を呼ぶ
シーケンス
呼び出しの間に SectionRunner が入り、turn.ts が actions.ts の関数を直接呼ぶ形ではなくなっています。
Before
After
コード
export type Section = {
name: string;
run: (state: BattleState, runner: SectionRunner) => BattleState;
};
export function createSectionRunner(trace?: string[]): SectionRunner {
const runner: SectionRunner = {
run(section, state) {
trace?.push(section.name);
const result = section.run(state, runner);
if (result !== state) {
throw new Error(`${section.name} が別の BattleState を返しました`);
}
return result;
},
runAll(sections, state) {
for (const section of sections) {
runner.run(section, state);
}
return state;
},
};
return runner;
}
export function createBattleSection(): Section {
return {
name: "Battle",
run(state, runner) {
return runner.runAll(
[
createBattleStartSection(),
createAppearPokemonSection("ガブリアス", createGarchomp),
createAppearPokemonSection("カバルドン", createHippowdon),
createTurnSection(),
],
state,
);
},
};
}
export function createTurnSection(): Section {
return {
name: "Turn",
run(state, runner) {
const buffer: ActionBuffer = { actions: [] };
return runner.runAll(
[
createTurnStartSection(),
createSelectActionsSection(buffer),
createDecideActionOrderSection(buffer),
createExecuteActionsSection(buffer),
createTurnEndSection(),
],
state,
);
},
};
}
export function createExecuteActionsSection(buffer: ActionBuffer): Section {
return {
name: "ExecuteActions",
run(state, runner) {
const sections = buffer.actions.map((action) => createExecuteActionSection(action));
return runner.runAll(sections, state);
},
};
}