Skip to content

Commit 0758c7e

Browse files
committed
cascade endPhase
Subsequent phases are also automatically ended if `endPhaseIf` returns true when a single `endPhase` is triggered (either manually or through `endPhaseIf`).
1 parent a6aab98 commit 0758c7e

2 files changed

Lines changed: 34 additions & 5 deletions

File tree

src/core/flow.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,12 +239,12 @@ export function FlowWithPhases({
239239
* The next phase is chosen in a round-robin fashion, with the
240240
* option to override that by passing nextPhase.
241241
*/
242-
function endPhaseEvent(state, nextPhase) {
242+
function endPhaseEvent(state, nextPhase, cascadeDepth) {
243243
let G = state.G;
244244
let ctx = state.ctx;
245245

246246
// Run any cleanup code for the phase that is about to end.
247-
const conf = phaseMap[ctx.phase];
247+
let conf = phaseMap[ctx.phase];
248248
G = conf.onPhaseEnd(G, ctx);
249249

250250
const gameover = conf.endGameIf(G, ctx);
@@ -263,7 +263,21 @@ export function FlowWithPhases({
263263
}
264264

265265
// Run any setup code for the new phase.
266-
return startPhase({ ...state, G, ctx }, phaseMap[ctx.phase]);
266+
state = startPhase({ ...state, G, ctx }, phaseMap[ctx.phase]);
267+
268+
// End the new phase automatically if necessary.
269+
// In order to avoid infinite loops, this is called
270+
// a finite number of times.
271+
if (!cascadeDepth) cascadeDepth = 0;
272+
if (cascadeDepth < phases.length - 1) {
273+
conf = phaseMap[state.ctx.phase];
274+
const end = conf.endPhaseIf(state.G, state.ctx);
275+
if (end) {
276+
state = endPhaseEvent(state, end, cascadeDepth + 1);
277+
}
278+
}
279+
280+
return state;
267281
}
268282

269283
/**

src/core/flow.test.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,10 @@ test('onPhaseBegin / onPhaseEnd', () => {
207207

208208
test('endPhaseIf', () => {
209209
const flow = FlowWithPhases({
210-
phases: [{ name: 'A', endPhaseIf: G => G.end }, { name: 'B' }],
210+
phases: [{ name: 'A', endPhaseIf: () => true }, { name: 'B' }],
211211
});
212212

213-
let state = { G: { end: true }, ctx: flow.ctx(2) };
213+
const state = { ctx: flow.ctx(2) };
214214

215215
{
216216
const t = flow.processGameEvent(state, { type: 'endPhase' });
@@ -226,6 +226,21 @@ test('endPhaseIf', () => {
226226
const t = flow.processMove(state, { type: 'move' });
227227
expect(t.ctx.phase).toBe('B');
228228
}
229+
230+
{
231+
const endPhaseIf = () => true;
232+
const flow = FlowWithPhases({
233+
phases: [
234+
{ name: 'A', endPhaseIf },
235+
{ name: 'B', endPhaseIf },
236+
{ name: 'C', endPhaseIf },
237+
],
238+
});
239+
240+
const state = { ctx: flow.ctx(2) };
241+
const t = flow.processGameEvent(state, { type: 'endPhase' });
242+
expect(t.ctx.phase).toBe('A');
243+
}
229244
});
230245

231246
test('endGameIf', () => {

0 commit comments

Comments
 (0)