Created
October 17, 2019 23:24
-
-
Save atoko/8ac1e7036f7846bb0d084db0138dad3e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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