Skip to content

Instantly share code, notes, and snippets.

@atoko
Created October 17, 2019 23:24
Show Gist options
  • Save atoko/8ac1e7036f7846bb0d084db0138dad3e to your computer and use it in GitHub Desktop.
Save atoko/8ac1e7036f7846bb0d084db0138dad3e to your computer and use it in GitHub Desktop.
import {combineReducers} from 'redux';
import battleEngine, {BOT_IDENTIFIER} from './briscaEngine';
import * as actions from './briscaActions';
const defaultState = () => {
return {
deck: [],
rounds: [],
tableSize: 0,
tableOwner: null,
life: null,
players: {},
table: [],
turnSequence: []
};
}
let PlayerRecord = () => ({
id: null,
next: null,
hand: [],
points: 0,
});
let playerState = (state = PlayerRecord(), action) => {
let {points, card, player_id} = action;
switch (action.type) {
case "JOIN_GAME":
return {
...state,
id: player_id
};
}
if ((state.id) !== player_id) {
return state;
}
switch (action.type) {
case "DRAW_CARD":
let hand = [...state.hand, card];
return {
...state,
hand
};
case "PLAY_CARD":
return {
...state,
hand: state.hand.filter((cardInHand) => cardInHand !== card)
};
case "ADD_POINTS":
return {
...state,
points: state.points + points
};
default:
return state;
}
}
let newGame = (state = defaultState(), action) => {
let {players, rounds} = state;
const {deck, tableSize = state.tableSize} = action;
if (Object.keys(players).length > 0) {
let newSequence = [ getWinner(state).id, getWinner(state).next ];
state = {
...state,
players: [],
rounds: [...rounds, getWinner(state)],
table: [],
turnSequence: []
};
newSequence.forEach((id) => {
state = joinGame(state, actions.joinGame(id));
});
}
return {
...state,
deck,
life: deck.slice(-1).pop(),
tableSize
};
}
let joinGame = (state = defaultState(), action) => {
const {player_id} = action;
let {players, playerSequence, turnSequence, tableSize, tableOwner} = state;
if (Object.keys(players).length >= tableSize) {
return state;
}
players = {
...players,
[player_id]: playerState(players[player_id], action)
};
if (tableOwner == null) {
tableOwner = player_id;
}
turnSequence = [...turnSequence, player_id];
let playerCount = Object.keys(players).length;
let newPlayerMap = {};
Object.keys(players).map((key) => {
let player = players[key];
let index = turnSequence.indexOf(key);
let next = (index + 1 >= playerCount) ?
tableOwner :
turnSequence[index + 1];
newPlayerMap[key] = {...player, next};
});
players = {...newPlayerMap};
return {
...state,
players,
tableOwner,
turnSequence
}
}
const drawAction = (player_id, card) => ({
type: "DRAW_CARD",
player_id,
card
});
let dealCards = (state = defaultState(), action) => {
if (state.deck.length < state.tableSize) {
return state;
}
const {deck, players} = state.turnSequence.slice(state.tableSize * -1).reduce(
({deck, players}, player_id) => {
let card = deck.slice(0, 1).pop();
let newPlayerMap = {};
Object.keys(players).map((key) => {
let player = players[key];
newPlayerMap[key] = playerState(player, drawAction(player_id, card))
});
players = {...newPlayerMap};
return {deck: deck.slice(1), players};
}, {...state});
return {
...state,
deck,
players
}
}
const startGameTransition = (state = defaultState(), action) => {
let {players, tableSize} = state;
if (Object.keys(players).length < tableSize) {
return state;
}
for (var i = 0; i < 3; i++) {
state = dealCards(state, action);
}
return {
...state
};
}
const playCard = (state = defaultState(), action) => {
const {player_id, card} = action;
let {table, players} = state;
let nextPlayer = nextToPlay(state);
if (card !== 0 && !card) {
return state;
}
if (players[nextPlayer].hand.indexOf(card) === -1) {
return state;
}
if (nextPlayer !== player_id) {
return state;
}
let newPlayerMap = {};
Object.keys(players).map((key) => {
let player = players[key];
newPlayerMap[key] = playerState(player, action);
});
players = {...newPlayerMap};
table = [...table, {player_id, card}];
return {
...state,
players,
table
}
}
const getWinCardFromState = ({life} = defaultState()) => (winCard, nextCard, tableCards) => {
return battleEngine.determineWinner(life, winCard, nextCard);
};
const getPointsFromState = () => (points, card) => {
return battleEngine.determinePointValue(card) + points;
}
const afterPlayTransition = ({...state, deck, engine, life, table, players, turnSequence} = defaultState(), action) => {
if (table.length === turnSequence.length) {
let winCard = table.slice(state.tableSize * -1)
.map((tablePlay) => tablePlay.card)
.reduce(getWinCardFromState(state));
let winIndex = table.map((tablePlay) => tablePlay.card).indexOf(winCard);
let nextPlayer = turnSequence[winIndex];
//TODO
//Traverse until nextRound.length == tableSize
let nextRound = [players[nextPlayer].id, players[nextPlayer].next];
turnSequence = turnSequence.concat(nextRound);
let pointsAction = {
type: "ADD_POINTS",
points: table
.slice(state.tableSize * -1)
.map((tablePlay) => tablePlay.card)
.reduce(getPointsFromState(state), 0),
player_id: nextPlayer
}
let newPlayerMap = {};
Object.keys(players).map((key) => {
let player = players[key];
newPlayerMap[key] = playerState(player, pointsAction)
});
players = {...newPlayerMap};
return dealCards({...state, players, turnSequence}, action);
}
return {
...state
};
}
export default (state = defaultState(), action) => {
switch (action.type) {
case actions.NEW_GAME:
return newGame(state, action);
case actions.JOIN_GAME:
state = joinGame(state, action);
return startGameTransition(state, action);
case actions.PLAY_CARD:
state = playCard(state, action);
state = afterPlayTransition(state, action);
return state;
case actions.NEXT_ROUND:
state = newGame(state, action);
return startGameTransition(state, action);
default:
return state;
}
}
//Selectors
export const playersArray = (state, data = []) => {
return Object.keys(state.players).map((playerId) => {
let player = state.players[playerId];
let preferences = data.filter((pd) => pd && pd.member_id == playerId);
if (preferences.length == 1) {
player.preferences = preferences[0].public_data;
}
return player
});
}
export const playerAlreadyJoined = (state, playerId) => {
return Object.keys(state.players).indexOf(playerId) !== -1;
}
export const playerTableFull = (state) => {
return Object.keys(state.players).length >= state.tableSize;
}
export const nextToPlay = (state) => {
return state.turnSequence[state.table.length];
}
export const cardsLeft = (state) => {
return state.deck.length;
}
export const handCardsLeft = (state) => {
return playersArray(state).reduce((total, player) => { return total + player.hand.length}, 0)
}
export const tableOwner = (state) => {
if (Object.keys(state.players).length < 1) {
return null;
}
return state.tableOwner;
}
export const currentPlay = (state) => {
if (state.table.length % state.tableSize == 0) {
return [];
}
let currentPlay = state.table.slice(0, state.tableSize);
let restOfSequence = state.table.slice(state.tableSize);
while (restOfSequence.length > 0) {
currentPlay = restOfSequence.slice(0, state.tableSize);
restOfSequence = restOfSequence.slice(state.tableSize);
}
return currentPlay;
}
export const lastPlay = (state) => {
if (state.table.length < state.tableSize) {
return [];
}
let lastPlay = state.table.slice(0, state.tableSize);
let restOfSequence = state.table.slice(state.tableSize);
while (restOfSequence.length >= state.tableSize) {
lastPlay = restOfSequence.slice(0, state.tableSize);
restOfSequence = restOfSequence.slice(state.tableSize);
}
return lastPlay;
}
export const getLifeCard = (state) => {
return state.life;
}
export const isPlayerBot = ({id}) => {
return id.startsWith(BOT_IDENTIFIER)
}
export const isGameEnded = (state) => {
return cardsLeft(state) === 0 && handCardsLeft(state) === 0;
}
export const getPlayer = (state, playerId) => {
return state.players[playerId];
}
export const getPlayerHand = (state, playerId) => {
return state.players[playerId].hand;
}
export const getWinner = (state) => {
return playersArray(state).reduce((winner, player) => {
if (player.points > winner.points) {
return player;
}
return winner;
})
}
export const getRounds = (state) => {
return state.rounds;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment