Skip to content

Commit

Permalink
feat: Support move limits in setActivePlayers (#452)
Browse files Browse the repository at this point in the history
* feat: Add `ctx._activePlayersMoveLimit`

Enables passing a `moveLimit` option to `setActivePlayers` similar in 
API to `setActivePlayers` itself

* feat: Track moves by active players in `ctx._activePlayersNumMoves`

* feat: Remove `ctx._activePlayersOnce`

* refactor: Replace uses of `once: true` with `moveLimit: 1`

* feat: Remove players from `activePlayers` when they reach move limit

* test: Add tests for active player move limits

* feat: Restore move limits and counts with `revert: true`

* test: Add test for `revert` restoring move limits & counts

* fix: Remove stray code from copy/paste

* test: Add test for `value` syntax in `moveLimit`

* refactor: Don’t set `_activePlayersMoveLimit` if `activePlayers` is null

* refactor: Flatten unnecessarily nested logic

* refactor: Simplify variable name in `ProcessMove`

* feat: Set `_activePlayersMoveLimit` to null when `activePlayers` empties

* style: Make active players field ordering consistent

* refactor: Use `const` for variable which isn’t changed
  • Loading branch information
delucis authored and nicolodavis committed Sep 15, 2019
1 parent 7833734 commit ca61bf6
Show file tree
Hide file tree
Showing 4 changed files with 370 additions and 55 deletions.
4 changes: 2 additions & 2 deletions examples/react-web/src/turnorder/example-others-once.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import React from 'react';
const code = `{
moves: {
play(G, ctx) {
ctx.events.setActivePlayers({ others: 'discard', once: true });
ctx.events.setActivePlayers({ others: 'discard', moveLimit: 1 });
return G;
},
},
Expand Down Expand Up @@ -46,7 +46,7 @@ export default {

moves: {
play(G, ctx) {
ctx.events.setActivePlayers({ others: 'discard', once: true });
ctx.events.setActivePlayers({ others: 'discard', moveLimit: 1 });
return G;
},
},
Expand Down
43 changes: 35 additions & 8 deletions src/core/flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -683,34 +683,60 @@ export function Flow({ moves, phases, endIf, turn, events, plugins }) {
let conf = GetPhase(state.ctx);

let { ctx } = state;
let { activePlayers, _activePlayersOnce, _prevActivePlayers } = ctx;
let {
activePlayers,
_activePlayersMoveLimit,
_activePlayersNumMoves,
_prevActivePlayers,
} = ctx;

if (_activePlayersOnce) {
const playerID = action.playerID;
const { playerID } = action;

if (activePlayers) _activePlayersNumMoves[playerID]++;

if (
_activePlayersMoveLimit &&
_activePlayersNumMoves[playerID] >= _activePlayersMoveLimit[playerID]
) {
activePlayers = Object.keys(activePlayers)
.filter(id => id !== playerID)
.reduce((obj, key) => {
obj[key] = activePlayers[key];
return obj;
}, {});
_activePlayersMoveLimit = Object.keys(_activePlayersMoveLimit)
.filter(id => id !== playerID)
.reduce((obj, key) => {
obj[key] = _activePlayersMoveLimit[key];
return obj;
}, {});
}

if (activePlayers && Object.keys(activePlayers).length == 0) {
if (ctx._nextActivePlayers) {
ctx = SetActivePlayers(ctx, ctx._nextActivePlayers);
({ activePlayers, _activePlayersOnce, _prevActivePlayers } = ctx);
({
activePlayers,
_activePlayersMoveLimit,
_activePlayersNumMoves,
_prevActivePlayers,
} = ctx);
} else if (_prevActivePlayers.length > 0) {
const lastIndex = _prevActivePlayers.length - 1;
activePlayers = _prevActivePlayers[lastIndex];
({
activePlayers,
_activePlayersMoveLimit,
_activePlayersNumMoves,
} = _prevActivePlayers[lastIndex]);
_prevActivePlayers = _prevActivePlayers.slice(0, lastIndex);
} else {
activePlayers = null;
_activePlayersOnce = false;
_activePlayersMoveLimit = null;
}
}

let numMoves = state.ctx.numMoves;
if (action.playerID == state.ctx.currentPlayer) {
if (playerID == state.ctx.currentPlayer) {
numMoves++;
}

Expand All @@ -719,7 +745,8 @@ export function Flow({ moves, phases, endIf, turn, events, plugins }) {
ctx: {
...ctx,
activePlayers,
_activePlayersOnce,
_activePlayersMoveLimit,
_activePlayersNumMoves,
_prevActivePlayers,
numMoves,
},
Expand Down
56 changes: 47 additions & 9 deletions src/core/turn-order.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,16 @@ export function SetActivePlayers(ctx, arg) {
const _nextActivePlayers = arg.next || null;

if (arg.revert) {
_prevActivePlayers = _prevActivePlayers.concat(ctx.activePlayers);
_prevActivePlayers = _prevActivePlayers.concat({
activePlayers: ctx.activePlayers,
_activePlayersMoveLimit: ctx._activePlayersMoveLimit,
_activePlayersNumMoves: ctx._activePlayersNumMoves,
});
} else {
_prevActivePlayers = [];
}

let activePlayers = {};
let _activePlayersOnce = false;

if (arg.value) {
activePlayers = arg.value;
Expand All @@ -76,18 +79,53 @@ export function SetActivePlayers(ctx, arg) {
}
}

if (arg.once) {
_activePlayersOnce = true;
}

if (Object.keys(activePlayers).length == 0) {
activePlayers = null;
}

let _activePlayersMoveLimit = null;

if (activePlayers && arg.moveLimit) {
if (typeof arg.moveLimit === 'number') {
_activePlayersMoveLimit = {};
for (const id in activePlayers) {
_activePlayersMoveLimit[id] = arg.moveLimit;
}
} else {
_activePlayersMoveLimit = {};

if (arg.moveLimit.value) {
_activePlayersMoveLimit = arg.moveLimit.value;
}

if (
arg.moveLimit.currentPlayer !== undefined &&
activePlayers[ctx.currentPlayer]
) {
_activePlayersMoveLimit[ctx.currentPlayer] =
arg.moveLimit.currentPlayer;
}

if (arg.moveLimit.others !== undefined) {
for (const id in activePlayers) {
if (id !== ctx.currentPlayer) {
_activePlayersMoveLimit[id] = arg.moveLimit.others;
}
}
}
}
}

let _activePlayersNumMoves = {};
for (const id in activePlayers) {
_activePlayersNumMoves[id] = 0;
}

return {
...ctx,
activePlayers,
_activePlayersOnce,
_activePlayersMoveLimit,
_activePlayersNumMoves,
_prevActivePlayers,
_nextActivePlayers,
};
Expand Down Expand Up @@ -291,7 +329,7 @@ export const ActivePlayers = {
* This is typically used in a phase where you want to elicit a response
* from every player in the game.
*/
ALL_ONCE: { all: Stage.NULL, once: true },
ALL_ONCE: { all: Stage.NULL, moveLimit: 1 },

/**
* OTHERS
Expand All @@ -308,5 +346,5 @@ export const ActivePlayers = {
* This is typically used in a phase where you want to elicit a response
* from every *other* player in the game.
*/
OTHERS_ONCE: { others: Stage.NULL, once: true },
OTHERS_ONCE: { others: Stage.NULL, moveLimit: 1 },
};
Loading

0 comments on commit ca61bf6

Please sign in to comment.