Skip to content

Commit

Permalink
move InitializeGame and ContextEnhancer into separate files
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolodavis committed Sep 10, 2019
1 parent 17f7bce commit 6dc3856
Show file tree
Hide file tree
Showing 16 changed files with 182 additions and 178 deletions.
7 changes: 2 additions & 5 deletions packages/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@
*/

import { Game } from '../src/core/game.js';
import {
InitializeGame,
CreateGameReducer,
INVALID_MOVE,
} from '../src/core/reducer.js';
import { InitializeGame } from '../src/core/initialize.js';
import { CreateGameReducer, INVALID_MOVE } from '../src/core/reducer.js';
import { Flow, FlowWithPhases } from '../src/core/flow.js';
import { Pass, TurnOrder } from '../src/core/turn-order.js';
import { PlayerView } from '../src/core/player-view.js';
Expand Down
2 changes: 1 addition & 1 deletion src/ai/bot.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* https://opensource.org/licenses/MIT.
*/

import { InitializeGame } from '../core/reducer';
import { InitializeGame } from '../core/initialize';
import { MAKE_MOVE, GAME_EVENT } from '../core/action-types';
import { makeMove } from '../core/action-creators';
import { Simulate, Bot, RandomBot, MCTSBot } from './bot';
Expand Down
3 changes: 2 additions & 1 deletion src/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import { Game } from '../core/game';
import { error } from '../core/logger';
import { SocketIO } from './transport/socketio';
import { Local, LocalMaster } from './transport/local';
import { InitializeGame, CreateGameReducer } from '../core/reducer';
import { CreateGameReducer } from '../core/reducer';
import { InitializeGame } from '../core/initialize';

// The Game Master object (if using a local one).
let localMaster_ = null;
Expand Down
3 changes: 2 additions & 1 deletion src/client/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
*/

import { createStore } from 'redux';
import { InitializeGame, CreateGameReducer } from '../core/reducer';
import { CreateGameReducer } from '../core/reducer';
import { InitializeGame } from '../core/initialize';
import { Client, createMoveDispatchers } from './client';
import { Game } from '../core/game';
import { Local } from './transport/local';
Expand Down
3 changes: 2 additions & 1 deletion src/client/log/log.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import React from 'react';
import { Client } from '../client';
import { makeMove, automaticGameEvent } from '../../core/action-creators';
import { GameLog } from './log';
import { InitializeGame, CreateGameReducer } from '../../core/reducer';
import { CreateGameReducer } from '../../core/reducer';
import { InitializeGame } from '../../core/initialize';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Expand Down
3 changes: 2 additions & 1 deletion src/client/transport/local.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
import { createStore } from 'redux';
import { Local, LocalMaster } from './local';
import { makeMove, gameEvent } from '../../core/action-creators';
import { InitializeGame, CreateGameReducer } from '../../core/reducer';
import { CreateGameReducer } from '../../core/reducer';
import { InitializeGame } from '../../core/initialize';

describe('LocalMaster', () => {
const game = {};
Expand Down
3 changes: 2 additions & 1 deletion src/client/transport/socketio.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
import { createStore } from 'redux';
import { SocketIO } from './socketio';
import { makeMove } from '../../core/action-creators';
import { InitializeGame, CreateGameReducer } from '../../core/reducer';
import { CreateGameReducer } from '../../core/reducer';
import { InitializeGame } from '../../core/initialize';
import * as Actions from '../../core/action-types';

class MockSocket {
Expand Down
84 changes: 84 additions & 0 deletions src/core/context-enhancer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { Random } from './random';
import { Events } from './events';

/**
* Context API to allow writing custom logs in games.
*/
export class GameLoggerCtxAPI {
constructor() {
this._payload = undefined;
}

_api() {
return {
setPayload: payload => {
this._payload = payload;
},
};
}

attach(ctx) {
return { ...ctx, log: this._api() };
}

update(state) {
if (this._payload === undefined) {
return state;
}

// attach the payload to the last log event
let deltalog = state.deltalog;
deltalog[deltalog.length - 1] = {
...deltalog[deltalog.length - 1],
payload: this._payload,
};
this._payload = undefined;

return { ...state, deltalog };
}

static detach(ctx) {
const { log, ...ctxWithoutLog } = ctx; // eslint-disable-line no-unused-vars
return ctxWithoutLog;
}
}

/**
* This class is used to attach/detach various utility objects
* onto a ctx, without having to manually attach/detach them
* all separately.
*/
export class ContextEnhancer {
constructor(ctx, game, player) {
this.random = new Random(ctx);
this.events = new Events(game.flow, player);
this.log = new GameLoggerCtxAPI();
}

attachToContext(ctx) {
let ctxWithAPI = this.random.attach(ctx);
ctxWithAPI = this.events.attach(ctxWithAPI);
ctxWithAPI = this.log.attach(ctxWithAPI);
return ctxWithAPI;
}

static detachAllFromContext(ctx) {
let ctxWithoutAPI = Random.detach(ctx);
ctxWithoutAPI = Events.detach(ctxWithoutAPI);
ctxWithoutAPI = GameLoggerCtxAPI.detach(ctxWithoutAPI);
return ctxWithoutAPI;
}

_update(state, updateEvents) {
let newState = updateEvents ? this.events.update(state) : state;
newState = this.random.update(newState);
newState = this.log.update(newState);
return newState;
}

updateAndDetach(state, updateEvents) {
const newState = this._update(state, updateEvents);
newState.ctx = ContextEnhancer.detachAllFromContext(newState.ctx);
return newState;
}
}
2 changes: 1 addition & 1 deletion src/core/flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from './turn-order';
import * as plugin from '../plugins/main';
import { automaticGameEvent } from './action-creators';
import { ContextEnhancer } from './reducer';
import { ContextEnhancer } from './context-enhancer';
import * as logging from './logger';

/**
Expand Down
74 changes: 74 additions & 0 deletions src/core/initialize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { parse, stringify } from 'flatted';
import { Random } from './random';
import { Game } from './game';
import * as plugins from '../plugins/main';
import { ContextEnhancer } from './context-enhancer';

/**
* InitializeGame
*
* Creates the initial game state.
*
* @param {...object} game - Return value of Game().
* @param {...object} numPlayers - The number of players.
* @param {...object} multiplayer - Set to true if we are in a multiplayer client.
*/
export function InitializeGame({ game, numPlayers, setupData }) {
game = Game(game);

if (!numPlayers) {
numPlayers = 2;
}

let ctx = game.flow.ctx(numPlayers);

let seed = game.seed;
if (seed === undefined) {
seed = Random.seed();
}
ctx._random = { seed };

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

// Augment ctx with the enhancers (TODO: move these into plugins).
const apiCtx = new ContextEnhancer(ctx, game, ctx.currentPlayer);
let ctxWithAPI = apiCtx.attachToContext(ctx);

let initialG = game.setup(ctxWithAPI, setupData);

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

const initial = {
// User managed state.
G: initialG,
// Framework managed state.
ctx: ctx,
// List of {G, ctx} pairs that can be undone.
_undo: [],
// List of {G, ctx} pairs that can be redone.
_redo: [],
// A monotonically non-decreasing ID to ensure that
// state updates are only allowed from clients that
// are at the same version that the server.
_stateID: 0,
// A snapshot of this object so that actions can be
// replayed over it to view old snapshots.
// TODO: This will no longer be necessary once the
// log stops replaying actions (but reads the actual
// game states instead).
_initial: {},
};

let state = game.flow.init({ G: initial.G, ctx: ctxWithAPI });

initial.G = state.G;
initial._undo = state._undo;
state = apiCtx.updateAndDetach(state, true);
initial.ctx = state.ctx;
const deepCopy = obj => parse(stringify(obj));
initial._initial = deepCopy(initial);

return initial;
}
3 changes: 2 additions & 1 deletion src/core/random.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

import { Random } from './random';
import { makeMove } from './action-creators';
import { InitializeGame, CreateGameReducer } from './reducer';
import { CreateGameReducer } from './reducer';
import { InitializeGame } from './initialize';

function Init(seed) {
const ctx = { _random: { seed } };
Expand Down
Loading

0 comments on commit 6dc3856

Please sign in to comment.