Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions src/components/Card/Card.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@
justify-content: center;
container-type: inline-size;
}

.CardHighlight {
-webkit-animation: glow 1s ease-in-out infinite alternate;
-moz-animation: glow 1s ease-in-out infinite alternate;
animation: glow 1s ease-in-out infinite alternate;
}

.CardDim {
opacity: 0.7;
}

.CardContent {
text-align: center;
overflow-wrap: break-word;
Expand All @@ -40,3 +51,14 @@
transform: translateX(0);
}
}

@keyframes glow {
from {
box-shadow: 0 0 2px #fff, 0 0 4px #fff, 0 0 6px #84b893, 0 0 8px #84b893, 0 0 10px #84b893, 0 0 12px #84b893,
0 0 14px #84b893;
}
to {
box-shadow: 0 0 2px #fff, 0 0 4px #fff, 0 0 6px #1e5e31, 0 0 8px #1e5e31, 0 0 10px #1e5e31, 0 0 12px #1e5e31,
0 0 14px #1e5e31;
}
}
15 changes: 12 additions & 3 deletions src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ import {

import styles from "./Card.module.scss";

export interface CardProps extends CardObject {}
export type CardEffect = "highlight" | "dim" | "none";
export interface CardProps extends CardObject {
effect: CardEffect;
}

function Card({ rank, suit, facing }: CardProps) {
function Card({ rank, suit, facing, effect }: CardProps) {
const suitData = CardSuitMetadataMap[suit];
const rankData = CardRankMetadataMap[rank];

Expand All @@ -20,9 +23,15 @@ function Card({ rank, suit, facing }: CardProps) {
content = ["?"];
}

const cardClasses = [
styles.Card,
effect === "dim" && styles.CardDim,
effect === "highlight" && styles.CardHighlight,
].join(" ");

return (
<div className={styles.CardWrapper}>
<div className={styles.Card} style={{ backgroundColor: color }}>
<div className={cardClasses} style={{ backgroundColor: color }}>
<div className={styles.CardContent}>{content}</div>
</div>
</div>
Expand Down
18 changes: 13 additions & 5 deletions src/components/CardRow/CardRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,35 @@ import { CardObject } from "../Card";

import styles from "./CardRow.module.scss";
import React from "react";
import { CardEffect } from "../Card/Card";

export interface CardRowProps {
cardOwner: Participant;
cards: CardObject[];
effect: CardEffect;
children?: React.ReactNode;
}

const CardRow = (props: CardRowProps) => {
const CardRow = ({ cardOwner, cards, effect, children }: CardRowProps) => {
return (
<div className={styles.CardRow}>
<div className={styles.CardOwner}>
<span>{props.cardOwner} Cards</span>
<span>{cardOwner} Cards</span>
{/*
Pretty hacky, but the settings icon is passed
into this row as a child element
*/}
{props.children}
{children}
</div>
<div className={styles.Cards}>
{props.cards.map(({ facing, rank, suit }, i) => (
<Card facing={facing} rank={rank} suit={suit} key={i}></Card>
{cards.map(({ facing, rank, suit }, i) => (
<Card
facing={facing}
rank={rank}
suit={suit}
key={i}
effect={effect}
/>
))}
</div>
</div>
Expand Down
20 changes: 17 additions & 3 deletions src/components/Table/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import { useState } from "react";
import CardRow from "../CardRow";
import InfoHud from "../InfoHud";
import YesNoPopUp from "../YesNoPopUp";
import { useGame } from ".";
import { Participant, useGame } from ".";
import { ScoreBoardRow } from "../ScoreBoard";
import { useGameSettingsStore } from "../../stores/gameSettingsStore";

import styles from "./Table.module.scss";
import SettingsButton from "../SettingsButton";
import { CardEffect } from "../Card/Card";

const Table = ({ hide = false }: { hide?: boolean }) => {
const game = useGame();
Expand Down Expand Up @@ -93,14 +94,27 @@ const Table = ({ hide = false }: { hide?: boolean }) => {
];
}

function getCardEffect(cardOwner: Participant): CardEffect {
if (game.winner === "none") return "none";
return cardOwner === game.winner ? "highlight" : "dim";
}

return (
<div className={styles.Table} style={{ display: hide ? "none" : "" }}>
{showHitWarning && getHitWarning()}
{showStickWarning && getStickWarning()}
<CardRow cardOwner={"Dealer"} cards={game.dealer.cards}>
<CardRow
cardOwner={"Dealer"}
cards={game.dealer.cards}
effect={getCardEffect("Dealer")}
>
<SettingsButton />
</CardRow>
<CardRow cardOwner={"Player"} cards={game.player.cards} />
<CardRow
cardOwner={"Player"}
cards={game.player.cards}
effect={getCardEffect("Player")}
/>
<InfoHud
gameState={game.state}
outcome={game.outcome}
Expand Down
18 changes: 17 additions & 1 deletion src/components/Table/hooks/useGame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,19 @@ export type GameState =
| "GameOver";

export type Participant = "Player" | "Dealer";
export type Winner = Participant | "none";
export type WinType =
| "opponent-bust"
| "five-card-trick"
| "high-score"
| "most-cards"
| "high-card"
| "draw";

export function useGame() {
const [state, setState] = useState<GameState>("WaitingForStart");
const [outcome, setOutcome] = useState<string | null>(null);
const [winner, setWinner] = useState<Winner>("none");

const deck = useDeck();
const player = useCardPile();
Expand Down Expand Up @@ -68,7 +77,7 @@ export function useGame() {
let timeout: NodeJS.Timeout | undefined;

if (dealer.bust) {
setResult("Dealer bust, dealer wins!", "Player");
setResult("Dealer bust, player wins!", "Player");
} else if (dealer.fiveCardTrick) {
setResult("Dealer wins with a five card trick!", "Dealer");
}
Expand Down Expand Up @@ -133,6 +142,7 @@ export function useGame() {
*/
function setup() {
setOutcome(null);
setWinner("none");
deck.init();

player.setCards([]);
Expand Down Expand Up @@ -196,6 +206,7 @@ export function useGame() {
function setResult(outcomeText: string, winner?: Participant | null): void {
setState("GameOver");
setOutcome(outcomeText);
setWinner(winner ?? "none");

winner && stats.updateWinnerStats(winner);
}
Expand Down Expand Up @@ -223,6 +234,11 @@ export function useGame() {
* Statistics about the games played during this session.
*/
stats,

/**
* The participant who won the round, if any.
*/
winner,
setup,
startDealerRound,
getParticipantScore,
Expand Down
16 changes: 8 additions & 8 deletions src/utilities/deckUtilities.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe("deckUtilities", () => {
cards: [
{
card: { facing: "Up", rank: "Ace", suit: "Club" },
rankRelativeValueUsed: Math.min(
rankGlobalValueUsed: Math.min(
...CardRankMetadataMap["Ace"].relativeValues
),
rankValueUsed: Math.min(...CardRankMetadataMap["Ace"].values),
Expand All @@ -22,7 +22,7 @@ describe("deckUtilities", () => {
cards: [
{
card: { facing: "Up", rank: "Ace", suit: "Diamond" },
rankRelativeValueUsed: Math.min(
rankGlobalValueUsed: Math.min(
...CardRankMetadataMap["Ace"].relativeValues
),
rankValueUsed: Math.min(...CardRankMetadataMap["Ace"].values),
Expand Down Expand Up @@ -51,7 +51,7 @@ describe("deckUtilities", () => {
it("Should return Dealer when dealer has more cards than player", () => {
dealerHand.cards.push({
card: { facing: "Up", rank: "Eight", suit: "Diamond" },
rankRelativeValueUsed: 8,
rankGlobalValueUsed: 8,
rankValueUsed: 8,
});
dealerHand.score = playerHand.score;
Expand All @@ -63,7 +63,7 @@ describe("deckUtilities", () => {
it("Should return Player when player has more cards than player", () => {
playerHand.cards.push({
card: { facing: "Up", rank: "Eight", suit: "Diamond" },
rankRelativeValueUsed: 8,
rankGlobalValueUsed: 8,
rankValueUsed: 8,
});
playerHand.score = dealerHand.score;
Expand All @@ -77,12 +77,12 @@ describe("deckUtilities", () => {
it("Should return Dealer when dealers high card is greater than players", () => {
dealerHand.cards.push({
card: { facing: "Up", rank: "Eight", suit: "Diamond" },
rankRelativeValueUsed: 8,
rankGlobalValueUsed: 8,
rankValueUsed: 8,
});
playerHand.cards.push({
card: { facing: "Up", rank: "Seven", suit: "Diamond" },
rankRelativeValueUsed: 7,
rankGlobalValueUsed: 7,
rankValueUsed: 7,
});
dealerHand.score = playerHand.score;
Expand All @@ -94,12 +94,12 @@ describe("deckUtilities", () => {
it("Should return Player when player has more cards than player", () => {
dealerHand.cards.push({
card: { facing: "Up", rank: "Seven", suit: "Diamond" },
rankRelativeValueUsed: 7,
rankGlobalValueUsed: 7,
rankValueUsed: 7,
});
playerHand.cards.push({
card: { facing: "Up", rank: "Eight", suit: "Diamond" },
rankRelativeValueUsed: 8,
rankGlobalValueUsed: 8,
rankValueUsed: 8,
});
playerHand.score = dealerHand.score;
Expand Down
14 changes: 6 additions & 8 deletions src/utilities/deckUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export const generateDeck = (
export interface CardValue {
card: CardObject;
rankValueUsed: number;
rankRelativeValueUsed: number;
rankGlobalValueUsed: number;
}
export interface BestHand {
score: number;
Expand All @@ -125,12 +125,12 @@ export const calculateBestHand = (cards: CardObject[]): BestHand => {
}

const cardValue = Math.max(...CardRankMetadataMap[card.rank].values);
const cardRelativeValue = Math.max(
const cardGlobalValue = Math.max(
...CardRankMetadataMap[card.rank].relativeValues
);
bestHand.cards.push({
card,
rankRelativeValueUsed: cardRelativeValue,
rankGlobalValueUsed: cardGlobalValue,
rankValueUsed: cardValue,
});
bestHand.score += cardValue;
Expand Down Expand Up @@ -197,17 +197,15 @@ export const determineWinner = (
};

const getHighestCardValue = (cards: CardValue[]) => {
return cards.sort((a, b) => b.rankValueUsed - a.rankValueUsed)[0];
return cards.sort((a, b) => b.rankGlobalValueUsed - a.rankGlobalValueUsed)[0];
};

const getHighCardWinner = (
playerCards: CardValue[],
dealerCards: CardValue[]
): GameResult | null => {
const playerHighCard = getHighestCardValue(playerCards).rankValueUsed;
console.log("playerHighCard", playerHighCard);
const dealerHighCard = getHighestCardValue(dealerCards).rankValueUsed;
console.log("dealerHighCard", dealerHighCard);
const playerHighCard = getHighestCardValue(playerCards).rankGlobalValueUsed;
const dealerHighCard = getHighestCardValue(dealerCards).rankGlobalValueUsed;

const winner = getPlayerWithHighestValue(playerHighCard, dealerHighCard);
if (!winner) return null;
Expand Down