Skip to content

Instantly share code, notes, and snippets.

@algrant
Last active June 21, 2017 06:20
Show Gist options
  • Save algrant/895e0511feadafec1b6f51f8b069fe6d to your computer and use it in GitHub Desktop.
Save algrant/895e0511feadafec1b6f51f8b069fe6d to your computer and use it in GitHub Desktop.
tic-tac-time

GameCore

GameCoreState: startingPlayer: 0 players: - pieces: - played turn direction location

Actions toggleStartingPlayer() placePiece(Player, {time, dir, loc}) turnPiece(Player, PieceId, Dir) movePiece(Player, PeiceId, Loc) switchPieceLoc(Player, Piece1Id, Piece2Id) switchPieceTime(Player, Piece1Id, Piece2Id)

GamePlay

GamePlayState: players: - name id currentGame: gameStatus: [waiting_both, waiting_player_1, waiting_player_2, game_over],

turns: 
  - 
    player1: gameCoreAction
    player2: gameCoreAction
  - 
    player1: gameCoreAction
    player2: gameCoreAction

nextTurn:
  - 
    player1: [gameCoreAction, null],
    player2: [gameCoreAction, null],

gameCoreState: GameCoreState,

Actions

submitTurn undo startNewGame

const { Map, List } = require('immutable');
const { createStore } = require('redux');
const { combineReducers } = require('redux-immutable');
// Constants
const TOGGLE_STARTING_PLAYER = 'gamecore/toggleStartingPlayer';
const PLACE_PIECE = 'gamecore/placePiece';
const TURN_PIECE = 'gamecore/turnPiece';
const MOVE_PIECE = 'gamecore/movePiece';
const SWITCH_PIECE_TURN = 'gamecore/switchPieceTime';
const SWITCH_PIECE_LOCATION = 'gamecore/switchPiecePlace'
// Actions
const toggleStartingPlayer = () => ({type: TOGGLE_STARTING_PLAYER})
const placePiece = (playerId, pieceData) => ({type: PLACE_PIECE, payload: {playerId, pieceData}});
const turnPiece = (playerId, pieceId, direction) => ({type: TURN_PIECE, payload: {playerId, direction}});
const movePiece = (playerId, pieceId, location) => ({type: MOVE_PIECE, payload: {playerId, location}});
const switchPieceTurn = (playerId, piece1Id, piece2Id) => ({type: SWITCH_PIECE_TURN, payload: {playerId, piece1Id, piece2Id}});
const switchPieceLocation = (playerId, piece1Id, piece2Id) => ({type: SWITCH_PIECE_LOCATION, payload: {playerId, piece1Id, piece2Id}});
// Initial State
const pieceState = Map({
played: false,
turn: null,
location: null,
direction: null,
})
const playerState = Map({
pieces: List([
pieceState,
pieceState,
pieceState,
])
})
const gameState = Map({
startingPlayer: 0,
players: List([
playerState,
playerState,
])
})
// Game State Reducer
// Assumes good inputs! no error checking.
const gameStateReducer = (state = gameState, action) => {
switch (action.type) {
case TOGGLE_STARTING_PLAYER:
return state.set('startingPlayer', !state.get('startingPlayer'))
case PLACE_PIECE:{
const pieces = state.getIn(['players', action.payload.playerId.toString(), 'pieces']).toJS();
const firstEmpty = pieces.map((_, index)=>index).filter( index => !pieces[index].played);
const newPiece = Map(action.payload.pieceData).set('played', true);
return state.setIn(['players', action.payload.playerId.toString(), 'pieces', firstEmpty[0].toString()], newPiece);
}
case TURN_PIECE:{
const {playerId, pieceId, direction} = action.payload;
return state.setIn(['players', playerId.toString(), 'pieces', pieceId.toString(), 'direction'], direction);
}
case MOVE_PIECE:{
const {playerId, pieceId, location} = action.payload;
return state.setIn(['players', playerId.toString(), 'pieces', pieceId.toString(), 'location'], location);
}
case SWITCH_PIECE_TURN:{
const {playerId, piece1Id, piece2Id} = action.payload;
return state.updateIn(['players', playerId.toString(), 'pieces'], pieces => {
const p1_turn = pieces.getIn([piece1Id.toString(), 'turn']);
const p2_turn = pieces.getIn([piece2Id.toString(), 'turn']);
return pieces.setIn([piece1Id.toString(), 'turn'], p2_turn).setIn([piece2Id.toString(), 'turn'], p1_turn);
});
}
case SWITCH_PIECE_LOCATION:{
const {playerId, piece1Id, piece2Id} = action.payload;
return state.updateIn(['players', playerId.toString(), 'pieces'], pieces => {
const p1_loc = pieces.getIn([piece1Id.toString(), 'location']);
const p2_loc = pieces.getIn([piece2Id.toString(), 'location']);
return pieces.setIn([piece1Id.toString(), 'location'], p2_loc).setIn([piece2Id.toString(), 'location'], p1_loc);
});}
default:
return state
}
}
const pieceToString = (piece) => {
if (!piece.played) return '\tUnplayed';
return `\t${piece.turn},\t\t[${piece.location.join(', ')}],\t\t${piece.direction}`
}
const displayGameState = (immutableState) => {
const state = immutableState.toJS();
console.log(`startingPlayer: ${state.startingPlayer + 1}`)
console.log('p1');
state.players[0].pieces.map(piece => console.log(pieceToString(piece)));
console.log('p2');
state.players[1].pieces.map(piece => console.log(pieceToString(piece)));
}
const gameStore = createStore(gameStateReducer);
// some tests...
gameStore.dispatch(placePiece(0, {turn:0, location:[0,0], direction: 'N'}));
gameStore.dispatch(placePiece(0, {turn:1, location:[0,0], direction: 'N'}));
gameStore.dispatch(placePiece(1, {turn:2, location:[0,0], direction: 'N'}));
gameStore.dispatch(placePiece(1, {turn:3, location:[0,0], direction: 'N'}));
gameStore.dispatch(toggleStartingPlayer());
gameStore.dispatch(toggleStartingPlayer());
gameStore.dispatch(toggleStartingPlayer());
displayGameState(gameStore.getState());
gameStore.dispatch(switchPieceTurn(1, 0, 1));
displayGameState(gameStore.getState());
const { Map, List } = require('immutable');
const { createStore } = require('redux');
const { combineReducers } = require('redux-immutable');
// Constants
const PLAY_TURN = 'PLAY_TURN';
// Actions
const playTurn = ({playerId, location, direction}) => ({type: PLAY_TURN, payload: {playerId, location, direction}});
// Initial State
// because there's only 6 pieces it seems more sensible to simply hold their positions, rather than the empty board.
// keeping history to view pieces as they are placed.
const simState = Map({ history:List([]), board: List([])});
// Helper Function
const movePiece = (immutableLocation, direction) => {
const iL = immutableLocation;
switch (direction) {
case 'N': {
return iL.set(0, iL.get(0)-1);
}
case 'S': {
return iL.set(0, iL.get(0)+1);
}
case 'E': {
return iL.set(1, iL.get(1)-1);
}
case 'W': {
return iL.set(1, iL.get(1)+1);
}
default: {
console.log(`fucked up... direciton ${direction} is not in ['N', 'S', 'E', 'W']`);
return iL;
}
}
}
// Reducer
const simStateReducer = (state = simState, action) => {
switch (action.type) {
case PLAY_TURN:
const { playerId, location, direction } = action.payload;
const filledSpaces = state.get('board').map(turn => turn.get('location'));
let immutableLocation = List(location);
while (filledSpaces.indexOf(immutableLocation) !== -1) {
immutableLocation = movePiece(immutableLocation, direction);
}
return state.update('history', (h) => h.push(state.get('board'))).update('board', (b) => b.push(Map({playerId, direction: direction, location: immutableLocation})));
default:
return state
}
}
// Quick Tests...
const simStore = createStore(simStateReducer);
const displaySimBoard = (board) => {
let emptyBoard = Array(13).fill('.').map((_, r)=>Array(13).fill('.').map((_, c) => {
if ([5,6,7].indexOf(r) !== -1 && [5,6,7].indexOf(c) !== -1 ) return '_';
if ([5,6,7].indexOf(r) === -1 && [5,6,7].indexOf(c) === -1 ) return ' ';
return '.'}));
board.forEach(turn => {
const {playerId, location: l} = turn.toJS();
emptyBoard[l[0]+5][l[1]+5] = playerId;
})
emptyBoard.forEach(row=> {
console.log(row.join(' '));
})
console.log('----');
}
simStore.dispatch(playTurn({playerId:1, location:[0,0], direction: 'N'}));
simStore.dispatch(playTurn({playerId:2, location:[0,0], direction: 'S'}));
simStore.dispatch(playTurn({playerId:1, location:[0,0], direction: 'N'}));
simStore.dispatch(playTurn({playerId:2, location:[0,0], direction: 'S'}));
simStore.dispatch(playTurn({playerId:1, location:[0,0], direction: 'N'}));
simStore.dispatch(playTurn({playerId:2, location:[0,0], direction: 'S'}));
simStore.getState().get('history').forEach(board => {
displaySimBoard(board);
});
displaySimBoard(simStore.getState().get('board'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment