Skip to content

Commit

Permalink
Merge pull request #86 from daithihearn/doubles-leaderboard
Browse files Browse the repository at this point in the history
Fixing Doubles Leaderboard
  • Loading branch information
daithihearn authored Jan 18, 2023
2 parents ae99299 + 0a41d84 commit e5998e5
Show file tree
Hide file tree
Showing 2 changed files with 136 additions and 90 deletions.
102 changes: 67 additions & 35 deletions src/caches/GameSlice.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
import { createSelector, createSlice, PayloadAction } from "@reduxjs/toolkit"

import { GameState, GameStatus } from "../model/Game"
import { Player } from "../model/Player"
Expand Down Expand Up @@ -31,39 +31,71 @@ export const gameSlice = createSlice({
export const { updateGame, updatePlayers, resetGame } = gameSlice.actions

export const getGame = (state: RootState) => state.game
export const getGamePlayers = (state: RootState) => state.game.players
export const getRound = (state: RootState) => state.game.round
export const getCards = (state: RootState) => state.game.cards
export const getSuit = (state: RootState) => state.game.round?.suit
export const getGameId = (state: RootState) => state.game.id
export const getHasGame = (state: RootState) =>
state.game.status === GameStatus.ACTIVE ||
state.game.status === GameStatus.NONE
export const getGameStatus = (state: RootState) => state.game.status
export const isGameActive = (state: RootState) =>
state.game.status === GameStatus.ACTIVE
export const getIsRoundCalling = (state: RootState) =>
state.game.round?.status === RoundStatus.CALLING
export const getIsRoundCalled = (state: RootState) =>
state.game.round?.status === RoundStatus.CALLED
export const getIsRoundBuying = (state: RootState) =>
state.game.round?.status === RoundStatus.BUYING
export const getIsRoundPlaying = (state: RootState) =>
state.game.round?.status === RoundStatus.PLAYING
export const isDoublesGame = (state: RootState) =>
state.game.players.length === 6
export const getCanBuyCards = (state: RootState) =>
state.game.isMyGo &&
state.game.iamGoer &&
state.game.round &&
state.game.round.status === RoundStatus.BUYING
export const getGamePlayers = createSelector(getGame, game => game.players)
export const getMe = createSelector(getGame, game => game.me)

export const getIsInBunker = (state: RootState) =>
state.game.isMyGo &&
state.game.round?.status === RoundStatus.CALLING &&
state.game.me &&
state.game.me?.score < -30
export const getRound = createSelector(getGame, game => game.round)
export const getCards = createSelector(getGame, game => game.cards)
export const getSuit = createSelector(getRound, round => round?.suit)
export const getGameId = createSelector(getGame, game => game.id)

export const getIsMyGo = (state: RootState) => state.game.isMyGo
export const getIamGoer = (state: RootState) => state.game.iamGoer
export const getIamSpectator = (state: RootState) => state.game.iamSpectator
export const getGameStatus = createSelector(getGame, game => game.status)

export const getHasGame = createSelector(
getGameStatus,
status => status === GameStatus.ACTIVE || status === GameStatus.NONE,
)
export const isGameActive = createSelector(
getGameStatus,
status => status === GameStatus.ACTIVE,
)

export const isGameFinished = createSelector(
getGameStatus,
status => status === GameStatus.FINISHED,
)

export const getRoundStatus = createSelector(getRound, round => round?.status)
export const getIsRoundCalling = createSelector(
getRoundStatus,
status => status === RoundStatus.CALLING,
)
export const getIsRoundCalled = createSelector(
getRoundStatus,
status => status === RoundStatus.CALLED,
)
export const getIsRoundBuying = createSelector(
getRoundStatus,
status => status === RoundStatus.BUYING,
)
export const getIsRoundPlaying = createSelector(
getRoundStatus,
status => status === RoundStatus.PLAYING,
)

export const isDoublesGame = createSelector(
getGamePlayers,
players => players.length === 6,
)

export const getIsMyGo = createSelector(getGame, game => game.isMyGo)
export const getIamGoer = createSelector(getGame, game => game.iamGoer)
export const getIamSpectator = createSelector(
getGame,
game => game.iamSpectator,
)

export const getCanBuyCards = createSelector(
getIsMyGo,
getIamGoer,
getIsRoundBuying,
(isMyGo, iamGoer, isRoundBuying) => isMyGo && iamGoer && isRoundBuying,
)

export const getIsInBunker = createSelector(
getIsMyGo,
getIsRoundCalling,
getMe,
(isMyGo, isRoundCalling, me) =>
isMyGo && isRoundCalling && me && me?.score < -30,
)
124 changes: 69 additions & 55 deletions src/components/Leaderboard/DoublesLeaderboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,98 +2,123 @@ import React, { useCallback, useMemo } from "react"
import DataTable, { TableColumn } from "react-data-table-component"
import TrophyImage from "../../assets/icons/trophy.png"
import { useAppSelector } from "../../caches/hooks"
import { getGame } from "../../caches/GameSlice"
import {
getGame,
getGamePlayers,
getRound,
isGameFinished,
} from "../../caches/GameSlice"
import { getPlayerProfiles } from "../../caches/PlayerProfilesSlice"
import { GameStatus } from "../../model/Game"
import { compareScore, compareTeamIds } from "../../utils/PlayerUtils"
import { Player, Team } from "../../model/Player"
import { Player } from "../../model/Player"
import { customStyles } from "../Tables/CustomStyles"

interface LeaderBoardPlayer {
cardsBought?: number
name: string
picture: string
previousCard?: string
}

interface DoublesLeaderboardItem {
teamId: string
score: number
rings: number
player1: LeaderBoardPlayer
player2: LeaderBoardPlayer
winner: boolean
}

const DoublesLeaderboard = () => {
const game = useAppSelector(getGame)
const round = useAppSelector(getRound)
const players = useAppSelector(getGamePlayers)
const playerProfiles = useAppSelector(getPlayerProfiles)
const gameOver = useAppSelector(isGameFinished)

const previousHand = useMemo(() => {
if (game.round)
return game.round.completedHands[
game.round.completedHands.length - 1
]
}, [game])

const gameOver = useMemo(() => game.status === GameStatus.FINISHED, [game])
if (round) return round.completedHands[round.completedHands.length - 1]
}, [round])

const getProfile = useCallback(
(player: Player) =>
playerProfiles.find(p => p.id === player.id, [playerProfiles]),
[playerProfiles],
)

const teams = useMemo<Team[]>(() => {
const ps = game.players.sort(compareTeamIds)
const mapToLeaderboard = useCallback(
(player: Player): LeaderBoardPlayer => {
const profile = getProfile(player)
if (!profile) throw Error("No profile for player")
const previousCard = previousHand?.playedCards.find(
c => c.playerId === player.id,
)
return {
cardsBought: player.cardsBought,
name: profile.name,
picture: profile.picture,
previousCard: previousCard?.card,
}
},
[previousHand],
)

const leaderboardData = useMemo<DoublesLeaderboardItem[]>(() => {
const ps = [...players].sort(compareTeamIds)

if (!ps) {
return []
}
const teams: Team[] = [
const items: DoublesLeaderboardItem[] = [
{
id: ps[0].teamId,
teamId: ps[0].teamId,
score: ps[0].score,
rings: ps[0].rings,
player1: ps[0],
player2: ps[1],
player1: mapToLeaderboard(ps[0]),
player2: mapToLeaderboard(ps[1]),
winner: ps[0].winner,
},
{
id: ps[2].teamId,
teamId: ps[2].teamId,
score: ps[2].score,
rings: ps[2].rings,
player1: ps[2],
player2: ps[3],
player1: mapToLeaderboard(ps[2]),
player2: mapToLeaderboard(ps[3]),
winner: ps[2].winner,
},
{
id: ps[4].teamId,
teamId: ps[4].teamId,
score: ps[4].score,
rings: ps[4].rings,
player1: ps[4],
player2: ps[5],
player1: mapToLeaderboard(ps[4]),
player2: mapToLeaderboard(ps[5]),
winner: ps[4].winner,
},
]

return teams.sort(compareScore)
}, [])
return items.sort(compareScore)
}, [players])

const columns: TableColumn<Team>[] = [
const columns: TableColumn<DoublesLeaderboardItem>[] = [
{
name: "Player 1",
cell: row => (
<>
<div>
<img
alt="Image Preview"
src={getProfile(row.player1)!.picture}
src={row.player1.picture}
className="avatar"
/>

{!gameOver && !!previousHand ? (
{!gameOver && !!row.player1.previousCard ? (
<div>
{previousHand ? (
<img
alt={
previousHand.playedCards.find(
p =>
p.playerId ===
row.player1.id,
)?.card
}
alt={row.player1.previousCard}
src={
"/cards/thumbnails/" +
previousHand.playedCards.find(
p =>
p.playerId ===
row.player1.id,
)?.card +
row.player1.previousCard +
".png"
}
className="thumbnail_size_small cardNotSelected"
Expand All @@ -119,24 +144,18 @@ const DoublesLeaderboard = () => {
<div>
<img
alt="Image Preview"
src={getProfile(row.player2)!.picture}
src={row.player2.picture}
className="avatar"
/>

{!gameOver && previousHand ? (
<div>
{previousHand ? (
<img
alt={
previousHand.playedCards.find(
p => p.playerId === row.player2.id,
)?.card
}
alt={row.player2.previousCard}
src={
"/cards/thumbnails/" +
previousHand.playedCards.find(
p => p.playerId === row.player1.id,
)?.card +
row.player2.previousCard +
".png"
}
className="thumbnail_size_small cardNotSelected"
Expand Down Expand Up @@ -180,12 +199,7 @@ const DoublesLeaderboard = () => {
},
]

if (
!game ||
!game.status ||
!playerProfiles ||
playerProfiles.length === 0
) {
if (!playerProfiles || playerProfiles.length === 0) {
return null
}

Expand All @@ -194,7 +208,7 @@ const DoublesLeaderboard = () => {
<DataTable
noHeader
theme="solarized"
data={teams}
data={leaderboardData}
columns={columns}
highlightOnHover
customStyles={customStyles}
Expand Down

0 comments on commit e5998e5

Please sign in to comment.