Skip to content

Commit

Permalink
Set winning team for each hand and round, set next player to move
Browse files Browse the repository at this point in the history
- Add hands key to match model
- Set next player to move based on previous hand result (the winner player of the prev hand should start)
- Set played card as played
- Set round winner when ending
- At the end of each hand set hand winner and next hand initial player (to determine the ending of the hand)
  • Loading branch information
arielger committed Mar 19, 2019
1 parent 9749fa9 commit 814d847
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 42 deletions.
26 changes: 0 additions & 26 deletions server/src/data/cards.js

This file was deleted.

25 changes: 24 additions & 1 deletion server/src/database/models/match.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
const mongoose = require("mongoose");
const shortid = require("shortid");
const mongooseHidden = require("mongoose-hidden")();
const cards = require("../../data/cards");
const { cards } = require("../../utils/cards");

const cardValidator = {
validator: card => cards.includes(card),
message: props => `${props.value} is not a valid card`
};

const roundSchema = new mongoose.Schema({
winner: {
type: String,
enum: ["first", "second"]
},
hands: {
type: [
{
winnerTeam: {
type: String,
enum: ["first", "second", "tie"],
required: true
},
initialPlayerIndex: {
type: Number,
required: true
}
}
],
validate: {
validator: val => val.length <= 3,
message: props => `${props.value} length is greater than 3`
}
},
moves: [
{
user: {
Expand Down
78 changes: 63 additions & 15 deletions server/src/datasources/match.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ const { DataSource } = require("apollo-datasource");
const { pubsub, events } = require("../subscriptions");
const pickRandom = require("pick-random");

const cards = require("../data/cards");
const { cards, getHandTeamWinner } = require("../utils/cards");
const getRoundWinnerTeam = require("../utils/round");

const Match = mongoose.model("Match");

Expand Down Expand Up @@ -68,6 +69,11 @@ const getNewRoundUpdate = playersIds => {
playerId,
cards: []
})),
hands: [
{
initialPlayerIndex: 0
}
],
nextPlayer: R.head(playersIds)
}
};
Expand Down Expand Up @@ -277,15 +283,47 @@ class MatchAPI extends DataSource {
throw new Error(`The card with the id ${cardId} has already been played`);
}

const lastRoundIndex = match.rounds.length - 1;
const playerIndex = R.findIndex(({ data }) => data.equals(userId))(
match.players
);
const nextPlayerId = R.pipe(
R.inc,
R.modulo(R.__, match.playersCount),
nextPlayerIndex => match.players[nextPlayerIndex].data
)(playerIndex);
const currentRoundIndex = match.rounds.length - 1;
const currentRound = R.last(match.rounds);
const currentHandIndex = currentRound.hands.length - 1;
const currentHand = R.last(currentRound.hands);

const playersIds = R.map(player => player.data.toString(), match.players);
const playerIndex = R.findIndex(R.equals(userId))(playersIds);

const lastPlayerIndex =
currentHand.initialPlayerIndex - 1 < 0
? match.playersCount - 1
: currentHand.initialPlayerIndex - 1;
const lastPlayerId = playersIds[lastPlayerIndex];
const isLastPlayerOfHand = userId === lastPlayerId;
const { handWinnerTeam, handStarterPlayerIndex } =
isLastPlayerOfHand &&
getHandTeamWinner(
R.pipe(
R.map(R.path(["cards", currentHandIndex, "card"])),
R.map(R.when(R.isNil, R.always(selectedCard.card)))
)(currentRound.cardsPlayedByPlayer)
);

const nextPlayerIndex =
R.type(handStarterPlayerIndex) === "Number"
? handStarterPlayerIndex
: R.pipe(
R.inc,
R.modulo(R.__, match.playersCount)
)(playerIndex);

const nextPlayerId = match.players[nextPlayerIndex].data;

const handsWinnerTeam =
isLastPlayerOfHand &&
R.pipe(
R.map(R.prop("winnerTeam")),
R.filter(Boolean),
R.append(handWinnerTeam)
)(currentRound.hands);
const roundWinnerTeam = getRoundWinnerTeam(handsWinnerTeam);

const updatedMatch = R.pipe(
match => match.toObject(),
Expand All @@ -296,15 +334,25 @@ class MatchAPI extends DataSource {
await Match.findByIdAndUpdate(
matchId,
{
$set: {
[`rounds.${currentRoundIndex}.nextPlayer`]: nextPlayerId,
[`rounds.${currentRoundIndex}.cardsByPlayer.${playerIndex}.cards.${selectedCardIndex}.played`]: true,
[`rounds.${currentRoundIndex}.winner`]: roundWinnerTeam || null,
...(isLastPlayerOfHand
? {
[`rounds.${currentRoundIndex}.hands.${currentHandIndex}.winnerTeam`]: handWinnerTeam,
[`rounds.${currentRoundIndex}.hands.${currentHandIndex +
1}`]: {
initialPlayerIndex: nextPlayerIndex
}
}
: {})
},
$push: {
[`rounds.${lastRoundIndex}.cardsPlayedByPlayer.${playerIndex}.cards`]: {
[`rounds.${currentRoundIndex}.cardsPlayedByPlayer.${playerIndex}.cards`]: {
id: cardId,
card: selectedCard.card
}
},
$set: {
[`rounds.${lastRoundIndex}.nextPlayer`]: nextPlayerId,
[`rounds.${lastRoundIndex}.cardsByPlayer.${playerIndex}.cards.${selectedCardIndex}.played`]: true
}
},
{
Expand Down
64 changes: 64 additions & 0 deletions server/src/utils/cards.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
const R = require("ramda");

const getHandTeamWinner = handCards => {
const cardsScores = R.pipe(
R.map(card =>
R.pipe(
R.find(R.propEq("card", card)),
R.prop("score")
)(cards)
)
)(handCards);

const highestScoreIndex = cardsScores.reduce(
(highestScoreIndexes, currentScore, i, scores) => {
if (Math.max(...scores) === currentScore) {
return highestScoreIndexes.concat(i);
}
return highestScoreIndexes;
},
[]
);

const handWinnerTeam =
highestScoreIndex.length > 1
? "tie"
: highestScoreIndex[0] % 2 === 0
? "first"
: "second";

// Get index of first player with highest score
const nextPlayerIndex = handWinnerTeam !== "tie" && highestScoreIndex[0];

return { handWinnerTeam, handStarterPlayerIndex: nextPlayerIndex };
};

const createCardsOfAllSets = ({ number, score }) =>
["SWORD", "BASTO", "GOLD", "CUP"].map(set => ({
card: `${number}-${set}`,
score
}));

const cards = [
{ card: "1-SWORD", score: 14 },
{ card: "1-BASTO", score: 13 },
{ card: "7-SWORD", score: 12 },
{ card: "7-GOLD", score: 11 },
...createCardsOfAllSets({ number: 3, score: 10 }),
...createCardsOfAllSets({ number: 2, score: 9 }),
{ card: "1-GOLD", score: 8 },
{ card: "1-CUP", score: 8 },
...createCardsOfAllSets({ number: 12, score: 7 }),
...createCardsOfAllSets({ number: 11, score: 6 }),
...createCardsOfAllSets({ number: 10, score: 5 }),
{ card: "7-BASTO", score: 4 },
{ card: "7-CUP", score: 4 },
...createCardsOfAllSets({ number: 6, score: 3 }),
...createCardsOfAllSets({ number: 5, score: 2 }),
...createCardsOfAllSets({ number: 4, score: 1 })
];

module.exports = {
getHandTeamWinner,
cards
};
27 changes: 27 additions & 0 deletions server/src/utils/round.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
const R = require("ramda");

const isTeamWinner = (handsResults, team, isFirstTeam) =>
R.anyPass([
// If the team won 2 or more hands
R.pipe(
R.filter(R.equals(team)),
R.length,
winningRounds => winningRounds >= 2
),
// If there is one tie and won 1 hand
R.both(R.find(R.equals("tie")), R.find(R.equals(team))),
// If it's the first team and all hands are a tie
R.both(R.always(isFirstTeam), R.equals(["tie", "tie", "tie"]))
])(handsResults);

const getRoundWinnerTeam = handsResults => {
if (isTeamWinner(handsResults, "first", true)) {
return "first";
}
if (isTeamWinner(handsResults, "second")) {
return "second";
}
return false;
};

module.exports = getRoundWinnerTeam;

0 comments on commit 814d847

Please sign in to comment.