Skip to content

Commit

Permalink
add plugin.onPhaseBegin
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolodavis committed Jan 9, 2019
1 parent a4f115a commit 7188222
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 58 deletions.
20 changes: 12 additions & 8 deletions src/core/flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
UpdateTurnOrderState,
TurnOrder,
} from './turn-order';
import { FnWrap } from '../plugins/main';
import * as plugins from '../plugins/main';
import { automaticGameEvent } from './action-creators';
import { ContextEnhancer } from './reducer';
import * as logging from './logger';
Expand Down Expand Up @@ -317,11 +317,11 @@ export function FlowWithPhases({
if (conf.onPhaseBegin === undefined) {
conf.onPhaseBegin = G => G;
}
conf.onPhaseBegin = FnWrap(conf.onPhaseBegin, game);
conf.onPhaseBegin = plugins.FnWrap(conf.onPhaseBegin, game);
if (conf.onPhaseEnd === undefined) {
conf.onPhaseEnd = G => G;
}
conf.onPhaseEnd = FnWrap(conf.onPhaseEnd, game);
conf.onPhaseEnd = plugins.FnWrap(conf.onPhaseEnd, game);
if (conf.movesPerTurn === undefined) {
conf.movesPerTurn = movesPerTurn;
}
Expand All @@ -334,15 +334,15 @@ export function FlowWithPhases({
if (conf.onTurnBegin === undefined) {
conf.onTurnBegin = onTurnBegin;
}
conf.onTurnBegin = FnWrap(conf.onTurnBegin, game);
conf.onTurnBegin = plugins.FnWrap(conf.onTurnBegin, game);
if (conf.onTurnEnd === undefined) {
conf.onTurnEnd = onTurnEnd;
}
conf.onTurnEnd = FnWrap(conf.onTurnEnd, game);
conf.onTurnEnd = plugins.FnWrap(conf.onTurnEnd, game);
if (conf.onMove === undefined) {
conf.onMove = onMove;
}
conf.onMove = FnWrap(conf.onMove, game);
conf.onMove = plugins.FnWrap(conf.onMove, game);
if (conf.turnOrder === undefined) {
conf.turnOrder = turnOrder;
}
Expand Down Expand Up @@ -375,8 +375,12 @@ export function FlowWithPhases({

// Helper to perform start-of-phase initialization.
const startPhase = function(state, config) {
const G = config.onPhaseBegin(state.G, state.ctx);
const ctx = InitTurnOrderState(state.G, state.ctx, config.turnOrder);
let G = config.onPhaseBegin(state.G, state.ctx);
let ctx = InitTurnOrderState(state.G, state.ctx, config.turnOrder);

// Allow plugins to modify G and ctx at the beginning of a phase.
G = plugins.G.onPhaseBegin(G, ctx, game);
ctx = plugins.ctx.onPhaseBegin(ctx, game);

// Reset stats.
ctx.stats = {
Expand Down
4 changes: 2 additions & 2 deletions src/core/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export function CreateGameReducer({
ctx._random = { seed };

// Pass ctx through all the plugins that want to modify it.
ctx = plugins.SetupCtx(ctx, game);
ctx = plugins.ctx.setup(ctx, game);

// Augment ctx with the enhancers (TODO: move these into plugins).
const apiCtx = new ContextEnhancer(ctx, game, ctx.currentPlayer);
Expand All @@ -137,7 +137,7 @@ export function CreateGameReducer({
let initialG = game.setup(ctxWithAPI, setupData);

// Pass G through all the plugins that want to modify it.
initialG = plugins.SetupG(initialG, ctxWithAPI, game);
initialG = plugins.G.setup(initialG, ctxWithAPI, game);

const initial = {
// User managed state.
Expand Down
113 changes: 75 additions & 38 deletions src/plugins/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,46 +13,13 @@ import PluginImmer from './plugin-immer';
*/
const DEFAULT_PLUGINS = [PluginImmer];

/**
* Applies the provided plugins to ctx during game setup.
*
* @param {object} ctx - The ctx object.
* @param {object} game - The game object.
*/
export const SetupCtx = (ctx, game) => {
[...DEFAULT_PLUGINS, ...game.plugins]
.filter(plugin => plugin.ctx !== undefined)
.filter(plugin => plugin.ctx.setup !== undefined)
.forEach(plugin => {
ctx = plugin.ctx.setup(ctx, game);
});
return ctx;
};

/**
* Applies the provided plugins to G.
*
* @param {object} G - The G object.
* @param {object} ctx - The ctx object.
* @param {object} game - The game object.
*/
export const SetupG = (G, ctx, game) => {
[...DEFAULT_PLUGINS, ...game.plugins]
.filter(plugin => plugin.G !== undefined)
.filter(plugin => plugin.G.setup !== undefined)
.forEach(plugin => {
G = plugin.G.setup(G, ctx, game);
});
return G;
};

/**
* Applies the provided plugins to ctx before processing a move / event.
*
* @param {object} ctx - The ctx object.
* @param {object} game - The game object.
*/
export const CtxPreMove = (ctx, game) => {
const CtxPreMove = (ctx, game) => {
[...DEFAULT_PLUGINS, ...game.plugins]
.filter(plugin => plugin.ctx !== undefined)
.filter(plugin => plugin.ctx.preMove !== undefined)
Expand All @@ -68,7 +35,7 @@ export const CtxPreMove = (ctx, game) => {
* @param {object} ctx - The ctx object.
* @param {object} game - The game object.
*/
export const CtxPostMove = (ctx, game) => {
const CtxPostMove = (ctx, game) => {
[...DEFAULT_PLUGINS, ...game.plugins]
.filter(plugin => plugin.ctx !== undefined)
.filter(plugin => plugin.ctx.postMove !== undefined)
Expand All @@ -84,7 +51,7 @@ export const CtxPostMove = (ctx, game) => {
* @param {object} G - The G object.
* @param {object} game - The game object.
*/
export const GPreMove = (G, game) => {
const GPreMove = (G, game) => {
[...DEFAULT_PLUGINS, ...game.plugins]
.filter(plugin => plugin.G !== undefined)
.filter(plugin => plugin.G.preMove !== undefined)
Expand All @@ -100,7 +67,7 @@ export const GPreMove = (G, game) => {
* @param {object} G - The G object.
* @param {object} game - The game object.
*/
export const GPostMove = (G, game) => {
const GPostMove = (G, game) => {
[...DEFAULT_PLUGINS, ...game.plugins]
.filter(plugin => plugin.G !== undefined)
.filter(plugin => plugin.G.postMove !== undefined)
Expand All @@ -127,7 +94,77 @@ export const FnWrap = (fn, game) => {
ctx = CtxPreMove(ctx, game);
G = g(G, ctx, ...args);
ctx = CtxPostMove(ctx, game);
ctx = GPostMove(G, game);
G = GPostMove(G, game);
return G;
};
};

export const G = {
/**
* Applies the provided plugins to G during game setup.
*
* @param {object} G - The G object.
* @param {object} ctx - The ctx object.
* @param {object} game - The game object.
*/
setup: (G, ctx, game) => {
[...DEFAULT_PLUGINS, ...game.plugins]
.filter(plugin => plugin.G !== undefined)
.filter(plugin => plugin.G.setup !== undefined)
.forEach(plugin => {
G = plugin.G.setup(G, ctx, game);
});
return G;
},

/**
* Applies the provided plugins to G during the beginning of the phase.
*
* @param {object} G - The G object.
* @param {object} ctx - The ctx object.
* @param {object} game - The game object.
*/
onPhaseBegin: (G, ctx, game) => {
[...DEFAULT_PLUGINS, ...game.plugins]
.filter(plugin => plugin.G !== undefined)
.filter(plugin => plugin.G.onPhaseBegin !== undefined)
.forEach(plugin => {
G = plugin.G.onPhaseBegin(G, ctx, game);
});
return G;
},
};

export const ctx = {
/**
* Applies the provided plugins to ctx during game setup.
*
* @param {object} ctx - The ctx object.
* @param {object} game - The game object.
*/
setup: (ctx, game) => {
[...DEFAULT_PLUGINS, ...game.plugins]
.filter(plugin => plugin.ctx !== undefined)
.filter(plugin => plugin.ctx.setup !== undefined)
.forEach(plugin => {
ctx = plugin.ctx.setup(ctx, game);
});
return ctx;
},

/**
* Applies the provided plugins to ctx during the beginning of the phase.
*
* @param {object} ctx - The ctx object.
* @param {object} game - The game object.
*/
onPhaseBegin: (ctx, game) => {
[...DEFAULT_PLUGINS, ...game.plugins]
.filter(plugin => plugin.ctx !== undefined)
.filter(plugin => plugin.ctx.onPhaseBegin !== undefined)
.forEach(plugin => {
ctx = plugin.ctx.onPhaseBegin(ctx, game);
});
return ctx;
},
};
35 changes: 25 additions & 10 deletions src/plugins/main.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ describe('plugins', () => {
return { ...G, fnWrap: true };
},
G: {
setup: G => ({ ...G, initG: true }),
preMove: G => ({ ...G, addToG: true }),
postMove: G => ({ ...G, removeFromG: true }),
setup: G => ({ ...G, setup: true }),
preMove: G => ({ ...G, preMove: true }),
postMove: G => ({ ...G, postMove: true }),
onPhaseBegin: G => ({ ...G, onPhaseBegin: true }),
},
ctx: {
setup: ctx => ({ ...ctx, initCtx: true }),
preMove: ctx => ({ ...ctx, addToCtx: true }),
postMove: ctx => ({ ...ctx, removeFromCtx: true }),
setup: ctx => ({ ...ctx, setup: true }),
preMove: ctx => ({ ...ctx, preMove: true }),
postMove: ctx => ({ ...ctx, postMove: true }),
onPhaseBegin: ctx => ({ ...ctx, onPhaseBegin: true }),
},
},
],
Expand All @@ -54,12 +56,18 @@ describe('plugins', () => {

test('setupG', () => {
const state = reducer(undefined, { type: 'init' });
expect(state.G).toMatchObject({ initG: true });
expect(state.G).toMatchObject({ setup: true });
});

test('setupCtx', () => {
const state = reducer(undefined, { type: 'init' });
expect(state.ctx).toMatchObject({ initCtx: true });
expect(state.ctx).toMatchObject({ setup: true });
});

test('onPhaseBegin', () => {
const state = reducer(undefined, { type: 'init' });
expect(state.G).toMatchObject({ onPhaseBegin: true });
expect(state.ctx).toMatchObject({ onPhaseBegin: true });
});

test('fnWrap', () => {
Expand All @@ -68,9 +76,16 @@ describe('plugins', () => {
expect(state.G).toMatchObject({ fnWrap: true });
});

test('addToG / addToCtx', () => {
test('preMove', () => {
let state = reducer(undefined, { type: 'init' });
state = reducer(state, makeMove('A'));
expect(state.G).toMatchObject({ preMove: true });
expect(state.G.ctx).toMatchObject({ preMove: true });
});

test('postMove', () => {
let state = reducer(undefined, { type: 'init' });
state = reducer(state, makeMove('A'));
expect(state.G).toMatchObject({ addToG: true, ctx: { addToCtx: true } });
expect(state.G).toMatchObject({ postMove: true });
});
});

0 comments on commit 7188222

Please sign in to comment.