Skip to content

Commit

Permalink
implement card drawing + some other fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
naueramant committed May 22, 2024
1 parent 46db8e9 commit ca977fb
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 67 deletions.
80 changes: 47 additions & 33 deletions src/stores/game.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import create from "zustand";
import { create } from "zustand";
import { persist } from "zustand/middleware";
import * as GameAPI from "../api/endpoints/game";
import { Card, CardSuits, CardValues } from "../models/card";
import { Card, CardValues } from "../models/card";
import { Chug } from "../models/chug";
import { Player } from "../models/player";
import { GenerateShuffleIndices } from "../utilities/deck";
import { mapToRemote } from "./game.mapper";
import {
GenerateDeck,
GenerateShuffleIndices,
GetCardN,
} from "../utilities/deck";
import useGamesPlayed from "./gamesPlayed";
import useSettings from "./settings";
/*
Expand All @@ -25,13 +28,13 @@ interface GameState {
numberOfRounds: number;

gameStartTimestamp: number;
gameEndTimestamp: number;
turnStartTimestamp: number;

draws: Card[];

players: Player[];

chugs: Chug[];
draws: Card[];
}

interface GameActions {
Expand Down Expand Up @@ -60,11 +63,12 @@ const initialState: GameState = {
numberOfRounds: 13,

gameStartTimestamp: 0,
gameEndTimestamp: 0,
turnStartTimestamp: 0,

players: [],
chugs: [],

chugs: [],
draws: [],
};

Expand Down Expand Up @@ -92,13 +96,15 @@ const useGame = create<GameState & GameActions>()(

// Set up game state

let id = undefined;
let id;
let token;
let shuffleIndices;
let gameStartTimestamp = Date.now();
let turnStartTimestamp = Date.now();
let shuffleIndices = GenerateShuffleIndices(players.length);
let token = undefined;

if (!options.offline) {
if (options.offline) {
shuffleIndices = GenerateShuffleIndices(players.length);
} else {
const playerTokens = players.map((player) => player.token as string);

const resp = await GameAPI.postStart(playerTokens, true);
Expand All @@ -109,6 +115,8 @@ const useGame = create<GameState & GameActions>()(
shuffleIndices = resp.shuffle_indices;
}

const deck = GenerateDeck(shuffleIndices, players.length);

set({
id: id,
offline: options.offline,
Expand All @@ -129,31 +137,37 @@ const useGame = create<GameState & GameActions>()(
Draw: () => {
console.debug("[Game]", "Drawing card");

const suit = CardSuits[Math.floor(Math.random() * 4)];
const value = CardValues[Math.floor(Math.random() * 13)];
const state = useGame.getState();

const deck = GenerateDeck(state.shuffleIndices, state.players.length);

if (deck.length === 0) {
throw new Error("Cannot draw from an empty deck!");
}

const card = GetCardN(
state.shuffleIndices,
state.players.length,
state.draws.length,
);

const draws = [...state.draws, card];
const turnStartTimestamp = Date.now();

const done =
draws.length === (CardValues.length - 1) * state.players.length;

const card = {
suit: suit,
value: value,
const update: Partial<GameState> = {
draws: draws,
turnStartTimestamp: turnStartTimestamp,
};

set((state) => {
const updates = {
turnStartTimestamp: Date.now(),
draws: [...state.draws, card],
};

if (!state.offline) {
GameAPI.postUpdate(
mapToRemote({
...state,
...updates,
}),
);
}

return updates;
});
if (done) {
useGamesPlayed.getState().incrementCompleted();
update.gameEndTimestamp = Date.now();
}

set(update);

return card;
},
Expand Down
2 changes: 1 addition & 1 deletion src/stores/gamesPlayed.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import create from "zustand";
import { create } from "zustand";
import { persist } from "zustand/middleware";

interface ComputerGamesCountState {
Expand Down
26 changes: 13 additions & 13 deletions src/stores/metrics.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import create from "zustand";
import { Card } from "../models/card";
import { GenerateDeck } from "../utilities/deck";
import { create } from "zustand";
import useGame from "./game";

interface PlayerMetrics {
Expand Down Expand Up @@ -72,16 +70,18 @@ const MetricsStore = create<MetricsState & MetricsActions>()((set, get) => ({
const draws = game.draws;

/*
Calculate game metrics
*/
Calculate game metrics
*/

const numberOfCards = game.players.length * game.numberOfRounds;

const numberOfCardsDrawn = draws.length;
const numberOfCardsRemaining = numberOfCards - numberOfCardsDrawn;

const currentRound =
Math.floor(numberOfCardsDrawn / game.players.length) + 1;
const currentRound = Math.min(
Math.floor(numberOfCardsDrawn / game.players.length) + 1,
13,
);
const roundsRemaining = game.numberOfRounds - currentRound;

const numberOfPlayers = game.players.length;
Expand All @@ -90,8 +90,8 @@ const MetricsStore = create<MetricsState & MetricsActions>()((set, get) => ({
const done = numberOfCardsDrawn === numberOfCards;

/*
Calculate player metrics
*/
Calculate player metrics
*/

const currentPlayerMetrics = get().players;
const currentPlayerIndex = draws.length % game.players.length;
Expand Down Expand Up @@ -141,8 +141,8 @@ const MetricsStore = create<MetricsState & MetricsActions>()((set, get) => ({
}));

/*
Update the metrics store state
*/
Update the metrics store state
*/

set({
players: playerMetrics,
Expand Down Expand Up @@ -192,8 +192,8 @@ const useGameMetrics = () => {

export {
MetricsStore,
usePlayerMetricsByIndex,
useGameMetrics,
usePlayerMetrics,
usePlayerMetricsByIndex,
};
export type { PlayerMetrics, GameMetrics, MetricsState, MetricsActions };
export type { GameMetrics, MetricsActions, MetricsState, PlayerMetrics };
2 changes: 1 addition & 1 deletion src/stores/settings.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import create from "zustand";
import { create } from "zustand";
import { persist } from "zustand/middleware";

type ThemeMode = "light" | "dark";
Expand Down
14 changes: 12 additions & 2 deletions src/utilities/deck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const GenerateDeck = (
shuffleIndices: number[],
numberOfPlayers: number,
): Card[] => {
if (shuffleIndices.length !== numberOfPlayers * CardValues.length) {
if (shuffleIndices.length !== numberOfPlayers * CardValues.length - 1) {
throw new Error("Number of players and shuffle indices mismatch!");
}

Expand Down Expand Up @@ -39,4 +39,14 @@ const GenerateShuffleIndices = (numberOfPlayers: number): number[] => {
return shuffleIndices;
};

export { GenerateDeck, GenerateShuffleIndices };
const GetCardN = (
shuffleIndices: number[],
numberOfPlayers: number,
n: number,
): Card => {
const deck = GenerateDeck(shuffleIndices, numberOfPlayers);

return deck[n];
};

export { GenerateDeck, GenerateShuffleIndices, GetCardN };
1 change: 1 addition & 0 deletions src/views/Game/components/CardInventory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const CardInventoryCard: FunctionComponent<CardInventoryCardProps> = (
flexShrink: 0,
textAlign: "center",
position: "relative",
userSelect: "none",

...(props.value <= 0 && {
opacity: 0.5,
Expand Down
8 changes: 4 additions & 4 deletions src/views/Game/components/DNFDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import {
useTheme,
} from "@mui/material";
import { FunctionComponent } from "react";
import useGame from "../../../stores/game";
import { useSounds } from "../../../hooks/sounds";
import useGame from "../../../stores/game";
interface DNFDialogProps extends DialogProps {}

const DNFDialog: FunctionComponent<DNFDialogProps> = (props) => {
Expand All @@ -28,8 +28,8 @@ const DNFDialog: FunctionComponent<DNFDialogProps> = (props) => {

return (
<Dialog {...props}>
<DialogTitle textAlign="center">
<Typography variant="h4">Did not finish?</Typography>
<DialogTitle textAlign="center" variant="h4">
Did not finish?
</DialogTitle>

<DialogContent
Expand All @@ -53,7 +53,7 @@ const DNFDialog: FunctionComponent<DNFDialogProps> = (props) => {
{players.map((player, index) => {
return (
<Box
key={player.id}
key={index}
sx={{
display: "flex",
flexDirection: "column",
Expand Down
5 changes: 2 additions & 3 deletions src/views/Game/components/GameOverDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
DialogProps,
DialogTitle,
Stack,
Typography,
} from "@mui/material";
import { FunctionComponent } from "react";
import useGame from "../../../stores/game";
Expand All @@ -20,8 +19,8 @@ const GameOverDialog: FunctionComponent<GameOverDialogProps> = (props) => {

return (
<Dialog {...props}>
<DialogTitle textAlign="center">
<Typography variant="h4">Game Over</Typography>
<DialogTitle textAlign="center" variant="h4">
Game Over
</DialogTitle>

<DialogContent
Expand Down
15 changes: 9 additions & 6 deletions src/views/Game/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const Header: FunctionComponent = () => {

const game = useGame((state) => ({
gameStartTimestamp: state.gameStartTimestamp,
gameEndTimestamp: state.gameEndTimestamp,
turnStartTimestamp: state.turnStartTimestamp,
numberOfRounds: state.numberOfRounds,
ExitGame: state.Exit,
Expand Down Expand Up @@ -56,15 +57,16 @@ const Header: FunctionComponent = () => {
const [elapsedTurnTime, setElapsedTurnTime] = useState(0);

const updateTimes = () => {
setElapsedGameTime(Date.now() - game.gameStartTimestamp);
setElapsedTurnTime(Date.now() - game.turnStartTimestamp);
};

useEffect(() => {
if (gameMetrics.done) {
// TODO
setElapsedGameTime(game.gameEndTimestamp - game.gameStartTimestamp);
setElapsedTurnTime(0);
} else {
setElapsedGameTime(Date.now() - game.gameStartTimestamp);
setElapsedTurnTime(Date.now() - game.turnStartTimestamp);
}
};

useEffect(() => {
updateTimes();

const interval = setInterval(updateTimes, 1);
Expand All @@ -84,6 +86,7 @@ const Header: FunctionComponent = () => {
paddingRight: 2,
flexShrink: 0,
display: "flex",
userSelect: "none",
}}
>
<Box
Expand Down
9 changes: 5 additions & 4 deletions src/views/Game/components/PlayerItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ import {
} from "@mui/material";
import { FunctionComponent, memo, useCallback } from "react";
import Bottle from "../../../components/Bottle";
import Bubbles from "../../../components/Bubbles";
import { Crown, Jester } from "../../../components/Hats";
import { Player } from "../../../models/player";
import useGame from "../../../stores/game";
import { usePlayerMetricsByIndex } from "../../../stores/metrics";
import useSettings from "../../../stores/settings";
import { toBase14 } from "../../../utilities/base14";
import { secondsToHHMMSS } from "../../../utilities/time";
import { usePlayerMetricsByIndex } from "../../../stores/metrics";
import Bubbles from "../../../components/Bubbles";
import useGame from "../../../stores/game";
import { Crown, Jester } from "../../../components/Hats";

interface PlayerItemProps {
player: Player;
Expand Down Expand Up @@ -88,6 +88,7 @@ const PlayerItem: FunctionComponent<PlayerItemProps> = (props) => {
display: "flex",
backgroundColor: color(),
color: "white",
userSelect: "none",
}}
onClick={() => settings.SetSimpleCardsMode(!settings.simpleCardsMode)}
>
Expand Down
1 change: 1 addition & 0 deletions src/views/Game/components/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const GameTable: FunctionComponent<GameTableProps> = () => {
<TableContainer
sx={{
flex: 1,
userSelect: "none",
}}
>
<Table
Expand Down

0 comments on commit ca977fb

Please sign in to comment.