Skip to content

Commit

Permalink
Merge pull request #185 from daithihearn/cards-enum
Browse files Browse the repository at this point in the history
Cards enum
  • Loading branch information
daithihearn authored Sep 29, 2023
2 parents 61b34fe + fad7695 commit 11e0160
Show file tree
Hide file tree
Showing 5 changed files with 125 additions and 25 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: CI

on:
workflow_dispatch:
pull_request:
branches: ["main"]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: "16.19.x"

- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Run tests
run: yarn test
4 changes: 2 additions & 2 deletions src/caches/PlayCardSlice.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { createSlice, PayloadAction } from "@reduxjs/toolkit"
import { Card } from "model/Cards"
import { Card, CardName } from "model/Cards"
import { RootState } from "./caches"

export interface AutoPlayState {
card?: string
card?: CardName
}

const initialState: AutoPlayState = {}
Expand Down
10 changes: 6 additions & 4 deletions src/components/Game/Actions/PlayCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,12 @@ const PlayCard = () => {
)

const playCard = useCallback(
(card: string) =>
(card: CardName) => {
console.debug(`Playing card ${card}`)
dispatch(GameService.playCard(gameId!, card)).catch(e => {
console.error(parseError(e))
}),
})
},
[gameId],
)

Expand All @@ -111,10 +113,10 @@ const PlayCard = () => {
if (round?.suit && isMyGo) {
if (cardToPlay) playCard(cardToPlay)
else if (autoPlay === "worst" || bestCardLead(round)) {
const worstCard = getWorstCard(myCards, round.suit)
const worstCard = getWorstCard(myCards, round)
if (worstCard) playCard(worstCard.name)
} else if (autoPlay === "best") {
const bestCard = getBestCard(myCards, round.suit)
const bestCard = getBestCard(myCards, round)
if (bestCard) playCard(bestCard.name)
}
}
Expand Down
50 changes: 49 additions & 1 deletion src/utils/GameUtils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
import { compareCards } from "./GameUtils"
import { Suit } from "model/Suit"
import { compareCards, getBestCard, getWorstCard } from "./GameUtils"
import { Card, CardName, CARDS } from "model/Cards"
import { Round, RoundStatus } from "model/Round"

const ROUND: Round = {
suit: Suit.HEARTS,
currentHand: {
leadOut: CardName.TWO_CLUBS,
timestamp: "",
currentPlayerId: "",
playedCards: [],
},
timestamp: "",
number: 0,
dealerId: "",
status: RoundStatus.PLAYING,
dealerSeeingCall: false,
completedHands: [],
}

const HAND1: Card[] = [
CARDS[CardName.TWO_HEARTS],
Expand All @@ -17,6 +35,12 @@ const HAND2: Card[] = [
CARDS[CardName.THREE_DIAMONDS],
]

const HAND3: Card[] = [
CARDS[CardName.KING_SPADES],
CARDS[CardName.THREE_DIAMONDS],
CARDS[CardName.TWO_CLUBS],
]

describe("GameUtils", () => {
describe("compareCards", () => {
it("2 empty hands should return true", () => {
Expand All @@ -35,4 +59,28 @@ describe("GameUtils", () => {
expect(compareCards(HAND1, HAND1.reverse())).toBe(true)
})
})

describe("getBestCard", () => {
it("empty hand", () => {
expect(getBestCard([], ROUND)).toBe(undefined)
})
it("trump card", () => {
expect(getBestCard(HAND1, ROUND)).toBe(CARDS[CardName.FIVE_HEARTS])
})
it("follow cold card", () => {
expect(getBestCard(HAND3, ROUND)).toBe(CARDS[CardName.TWO_CLUBS])
})
})

describe("getWorstCard", () => {
it("empty hand", () => {
expect(getBestCard([], ROUND)).toBe(undefined)
})
it("trump card", () => {
expect(getWorstCard(HAND1, ROUND)).toBe(CARDS[CardName.TWO_HEARTS])
})
it("follow cold card", () => {
expect(getWorstCard(HAND3, ROUND)).toBe(CARDS[CardName.TWO_CLUBS])
})
})
})
61 changes: 43 additions & 18 deletions src/utils/GameUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,38 +169,63 @@ export const bestCardLead = (round: Round) => {
return round.currentHand.leadOut === trumpCards[0].name
}

export const getWorstCard = (cards: SelectableCard[], suit: Suit) => {
const myTrumpCards = cards.filter(
card => card.suit === suit || card.suit === Suit.WILD,
)
export const getWorstCard = (cards: Card[], round: Round) => {
if (cards.length === 0) return undefined

if (myTrumpCards.length > 0) {
// Sort ascending by value
myTrumpCards.sort((a, b) => a.value - b.value)
return myTrumpCards[0]
} else {
// Sort ascending by cold value
cards.sort((a, b) => a.coldValue - b.coldValue)
// Check if must follow suit
const leadOut = round.currentHand?.leadOut
let suitLead = leadOut ? CARDS[leadOut as CardName]?.suit : undefined

return cards[0]
if (suitLead === Suit.WILD) {
suitLead = round.suit
}

if (suitLead) {
const myCards = cards.filter(card => card.suit === suitLead)
if (myCards.length > 0) {
// Sort ascending by value
myCards.sort((a, b) => a.value - b.value)
return myCards[0]
}
}

// Sort ascending by value
cards.sort((a, b) => a.value - b.value)

return cards[0]
}

export const getBestCard = (cards: SelectableCard[], suit: Suit) => {
export const getBestCard = (cards: Card[], round: Round) => {
if (cards.length === 0) return undefined

// Check for trump cards
const myTrumpCards = cards.filter(
card => card.suit === suit || card.suit === Suit.WILD,
card => card.suit === round.suit || card.suit === Suit.WILD,
)

if (myTrumpCards.length > 0) {
// Sort descending by value
myTrumpCards.sort((a, b) => b.value - a.value)
return myTrumpCards[0]
} else {
// Sort descending by cold value
cards.sort((a, b) => b.coldValue - a.coldValue)
}

return cards[0]
// Check if have any cold cards
const leadOut = round.currentHand?.leadOut
const suitLead = leadOut ? CARDS[leadOut as CardName]?.suit : undefined

if (suitLead && suitLead !== Suit.WILD && suitLead !== round.suit) {
const myColdCards = cards.filter(card => card.suit === suitLead)
if (myColdCards.length > 0) {
// Sort descending by cold value
myColdCards.sort((a, b) => b.coldValue - a.coldValue)
return myColdCards[0]
}
}

// Sort descending by cold value
cards.sort((a, b) => b.coldValue - a.coldValue)

return cards[0]
}

export const pickBestCards = <T extends Card>(
Expand Down

0 comments on commit 11e0160

Please sign in to comment.