Skip to content

Commit d75fe44

Browse files
committed
move undoableMoves into boolean inside long form move syntax
1 parent 8924e84 commit d75fe44

3 files changed

Lines changed: 30 additions & 69 deletions

File tree

src/core/flow.js

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,6 @@ import * as logging from './logger';
4848
* Predicate to determine whether a
4949
* particular move is allowed at
5050
* this time.
51-
*
52-
* @param {...object} canUndoMove - (G, ctx, moveName) => boolean
53-
* Predicate to determine whether a
54-
* particular move is undoable at this
55-
* time.
5651
*/
5752
export function Flow({
5853
ctx,
@@ -183,9 +178,6 @@ export function Flow({
183178
*
184179
* @param {...object} setActionPlayers - Set to true to enable the `setActionPlayers` event.
185180
*
186-
* @param {...object} undoableMoves - List of moves that are undoable,
187-
* (default: null, i.e. all moves are undoable).
188-
*
189181
* @param {...object} optimisticUpdate - (G, ctx, move) => boolean
190182
* Control whether a move should
191183
* be executed optimistically on
@@ -225,9 +217,6 @@ export function Flow({
225217
*
226218
* // A phase-specific turn structure.
227219
* turn: { ... },
228-
*
229-
* // List of moves that are undoable.
230-
* undoableMoves: ['moveA', ...],
231220
* }
232221
*/
233222
export function FlowWithPhases({
@@ -240,8 +229,8 @@ export function FlowWithPhases({
240229
endPhase,
241230
endGame,
242231
setActionPlayers,
243-
undoableMoves,
244232
optimisticUpdate,
233+
getMove,
245234
game,
246235
}) {
247236
// Attach defaults.
@@ -267,7 +256,6 @@ export function FlowWithPhases({
267256
if (!endGameIf) endGameIf = () => undefined;
268257
if (!onMove) onMove = G => G;
269258
if (!turn) turn = {};
270-
if (undoableMoves === undefined) undoableMoves = null;
271259

272260
const phaseMap = game.phases || phases || {};
273261

@@ -309,10 +297,6 @@ export function FlowWithPhases({
309297
}
310298
conf.onMove = plugins.FnWrap(conf.onMove, game);
311299

312-
if (conf.undoableMoves === undefined) {
313-
conf.undoableMoves = undoableMoves;
314-
}
315-
316300
if (conf.turn === undefined) {
317301
conf.turn = turn;
318302
}
@@ -663,9 +647,17 @@ export function FlowWithPhases({
663647
};
664648

665649
const canUndoMove = (G, ctx, moveName) => {
666-
const conf = phaseMap[ctx.phase];
667-
if (!conf.undoableMoves) return true;
668-
return conf.undoableMoves.includes(moveName);
650+
const move = getMove(moveName);
651+
652+
if (move.undoable === false) {
653+
return false;
654+
}
655+
656+
if (move.undoable instanceof Function) {
657+
return move.undoable(G, ctx);
658+
}
659+
660+
return true;
669661
};
670662

671663
const events = {

src/core/flow.test.js

Lines changed: 14 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -587,22 +587,27 @@ describe('endTurn / endPhase args', () => {
587587
});
588588
});
589589

590-
test('undo / redo restricted by undoableMoves', () => {
590+
test('undoable moves', () => {
591591
const game = Game({
592592
moves: {
593-
A: () => ({ A: true }),
594-
B: () => ({ B: true }),
593+
A: {
594+
impl: () => ({ A: true }),
595+
undoable: (G, ctx) => {
596+
return ctx.phase == 'A';
597+
},
598+
},
599+
B: {
600+
impl: () => ({ B: true }),
601+
undoable: false,
602+
},
595603
C: () => ({ C: true }),
596604
},
597605

598606
flow: {
599-
undoableMoves: ['A', 'B'],
600607
startingPhase: 'A',
601608
phases: {
602-
A: { undoableMoves: ['A'] },
603-
B: { undoableMoves: ['B'] },
604-
C: {},
605-
D: { undoableMoves: null },
609+
A: {},
610+
B: {},
606611
},
607612
},
608613
});
@@ -622,7 +627,7 @@ test('undo / redo restricted by undoableMoves', () => {
622627
state = reducer(state, makeMove('C'));
623628
expect(state.G).toEqual({ C: true });
624629
state = reducer(state, undo());
625-
expect(state.G).toEqual({ C: true });
630+
expect(state.G).toEqual({ B: true });
626631

627632
state.G = {};
628633
state = reducer(state, gameEvent('endPhase', { next: 'B' }));
@@ -636,47 +641,11 @@ test('undo / redo restricted by undoableMoves', () => {
636641
state = reducer(state, makeMove('B'));
637642
expect(state.G).toEqual({ B: true });
638643
state = reducer(state, undo());
639-
expect(state.G).toEqual({ A: true });
640-
state = reducer(state, makeMove('C'));
641-
expect(state.G).toEqual({ C: true });
642-
state = reducer(state, undo());
643-
expect(state.G).toEqual({ C: true });
644-
645-
state.G = {};
646-
state = reducer(state, gameEvent('endPhase', { next: 'C' }));
647-
state = reducer(state, gameEvent('endTurn'));
648-
expect(state.ctx.phase).toBe('C');
649-
650-
state = reducer(state, makeMove('A'));
651-
expect(state.G).toEqual({ A: true });
652-
state = reducer(state, undo());
653-
expect(state.G).toEqual({});
654-
state = reducer(state, makeMove('B'));
655644
expect(state.G).toEqual({ B: true });
656-
state = reducer(state, undo());
657-
expect(state.G).toEqual({});
658645
state = reducer(state, makeMove('C'));
659646
expect(state.G).toEqual({ C: true });
660647
state = reducer(state, undo());
661-
expect(state.G).toEqual({ C: true });
662-
663-
state.G = {};
664-
state = reducer(state, gameEvent('endPhase', { next: 'D' }));
665-
state = reducer(state, gameEvent('endTurn'));
666-
expect(state.ctx.phase).toBe('D');
667-
668-
state = reducer(state, makeMove('A'));
669-
expect(state.G).toEqual({ A: true });
670-
state = reducer(state, undo());
671-
expect(state.G).toEqual({});
672-
state = reducer(state, makeMove('B'));
673648
expect(state.G).toEqual({ B: true });
674-
state = reducer(state, undo());
675-
expect(state.G).toEqual({});
676-
state = reducer(state, makeMove('C'));
677-
expect(state.G).toEqual({ C: true });
678-
state = reducer(state, undo());
679-
expect(state.G).toEqual({});
680649
});
681650

682651
test('endTurn is not called twice in one move', () => {

src/core/game.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,6 @@ function Game(game) {
9898
if (game.playerView === undefined) game.playerView = G => G;
9999
if (game.plugins === undefined) game.plugins = [];
100100

101-
if (!game.flow || game.flow.processGameEvent === undefined) {
102-
game.flow = FlowWithPhases({ game, ...game.flow });
103-
}
104-
105101
const getMove = name => {
106102
if (name in game.moves) {
107103
return game.moves[name];
@@ -114,6 +110,10 @@ function Game(game) {
114110
return null;
115111
};
116112

113+
if (!game.flow || game.flow.processGameEvent === undefined) {
114+
game.flow = FlowWithPhases({ game, getMove, ...game.flow });
115+
}
116+
117117
return {
118118
...game,
119119

0 commit comments

Comments
 (0)