From 82a2cea46ba3b65033b2a01bd92ab689030e4506 Mon Sep 17 00:00:00 2001 From: Daithi Hearn Date: Sat, 8 Jul 2023 22:07:50 +0200 Subject: [PATCH 1/5] WIP: Auto play --- .../{AutoPlaySlice.ts => PlayCardSlice.ts} | 14 ++-- src/caches/caches.ts | 4 +- src/components/Game/Actions/PlayCard.tsx | 82 +++++++++++++++---- src/components/Game/AutoActionManager.tsx | 44 +--------- src/components/Game/MyCards.tsx | 10 +-- src/components/Game/WebsocketManager.tsx | 2 +- src/pages/Game/Game.tsx | 2 +- src/services/GameService.ts | 2 +- src/utils/GameUtils.ts | 32 ++++++-- 9 files changed, 105 insertions(+), 87 deletions(-) rename src/caches/{AutoPlaySlice.ts => PlayCardSlice.ts} (62%) diff --git a/src/caches/AutoPlaySlice.ts b/src/caches/PlayCardSlice.ts similarity index 62% rename from src/caches/AutoPlaySlice.ts rename to src/caches/PlayCardSlice.ts index 5f7a644..7509f28 100644 --- a/src/caches/AutoPlaySlice.ts +++ b/src/caches/PlayCardSlice.ts @@ -8,16 +8,16 @@ export interface AutoPlayState { const initialState: AutoPlayState = {} -export const autoPlaySlice = createSlice({ - name: "autoPlay", +export const playCardSlice = createSlice({ + name: "playCard", initialState: initialState, reducers: { - updateAutoPlay: (_, action: PayloadAction) => { + updateCardToPlay: (_, action: PayloadAction) => { return { card: action.payload.name, } }, - toggleAutoPlay: (state, action: PayloadAction) => { + togglePlayCard: (state, action: PayloadAction) => { if (state.card === action.payload.name) return initialState return { card: action.payload.name, @@ -27,7 +27,7 @@ export const autoPlaySlice = createSlice({ }, }) -export const { updateAutoPlay, toggleAutoPlay, clearAutoPlay } = - autoPlaySlice.actions +export const { updateCardToPlay, togglePlayCard, clearAutoPlay } = + playCardSlice.actions -export const getAutoPlayCard = (state: RootState) => state.autoPlay.card +export const getCardToPlay = (state: RootState) => state.playCard.card diff --git a/src/caches/caches.ts b/src/caches/caches.ts index 1601d24..0148bd8 100644 --- a/src/caches/caches.ts +++ b/src/caches/caches.ts @@ -11,7 +11,7 @@ import { myProfileSlice } from "./MyProfileSlice" import { gameSlice } from "./GameSlice" import { myGamesSlice } from "./MyGamesSlice" import { myCardsSlice } from "./MyCardsSlice" -import { autoPlaySlice } from "./AutoPlaySlice" +import { playCardSlice } from "./PlayCardSlice" import { playerProfilesSlice } from "./PlayerProfilesSlice" import { settingsSlice } from "./SettingsSlice" @@ -21,7 +21,7 @@ const combinedReducer = combineReducers({ myGames: myGamesSlice.reducer, playerProfiles: playerProfilesSlice.reducer, myCards: myCardsSlice.reducer, - autoPlay: autoPlaySlice.reducer, + playCard: playCardSlice.reducer, settings: settingsSlice.reducer, }) diff --git a/src/components/Game/Actions/PlayCard.tsx b/src/components/Game/Actions/PlayCard.tsx index c69ab15..05f2388 100644 --- a/src/components/Game/Actions/PlayCard.tsx +++ b/src/components/Game/Actions/PlayCard.tsx @@ -1,4 +1,4 @@ -import { useCallback, useMemo } from "react" +import { useCallback, useEffect, useMemo, useState } from "react" import GameService from "services/GameService" import { useAppDispatch, useAppSelector } from "caches/hooks" @@ -9,6 +9,8 @@ import { BLANK_CARD } from "model/Cards" import parseError from "utils/ErrorUtils" import { RoundStatus } from "model/Round" import { Button } from "@mui/material" +import { getCardToPlay, updateCardToPlay } from "caches/PlayCardSlice" +import { bestCardLead, getBestCard, getWorstCard } from "utils/GameUtils" const WaitingForYourTurn = () => ( + ) + } return ( - + <> + + + + ) } diff --git a/src/components/Game/AutoActionManager.tsx b/src/components/Game/AutoActionManager.tsx index 5021339..659b2df 100644 --- a/src/components/Game/AutoActionManager.tsx +++ b/src/components/Game/AutoActionManager.tsx @@ -2,39 +2,14 @@ import { useEffect } from "react" import GameService from "services/GameService" import { useAppDispatch, useAppSelector } from "caches/hooks" -import { - getCards, - getGameId, - getIsInBunker, - getIsMyGo, - getRound, -} from "caches/GameSlice" -import { RoundStatus } from "model/Round" -import { getAutoPlayCard } from "caches/AutoPlaySlice" -import { bestCardLead, getWorstCard } from "utils/GameUtils" -import { useSnackbar } from "notistack" -import parseError from "utils/ErrorUtils" +import { getGameId, getIsInBunker } from "caches/GameSlice" const AutoActionManager = () => { const dispatch = useAppDispatch() - const { enqueueSnackbar } = useSnackbar() const gameId = useAppSelector(getGameId) - const round = useAppSelector(getRound) - const cards = useAppSelector(getCards) - - const autoPlayCard = useAppSelector(getAutoPlayCard) - - const isMyGo = useAppSelector(getIsMyGo) const isInBunker = useAppSelector(getIsInBunker) - const playCard = (id: string, card: string) => - dispatch(GameService.playCard(id, card)).catch(e => { - enqueueSnackbar(parseError(e), { - variant: "error", - }) - }) - const call = (id: string, callAmount: number) => dispatch(GameService.call(id, callAmount)).catch(console.error) @@ -43,23 +18,6 @@ const AutoActionManager = () => { if (gameId && isInBunker) call(gameId, 0) }, [gameId, isInBunker]) - // 1. Play card when you've pre-selected a card - // 2. Play worst card if best card lead out - useEffect(() => { - if ( - gameId && - isMyGo && - round?.suit && - round.status === RoundStatus.PLAYING - ) { - if (autoPlayCard) playCard(gameId, autoPlayCard) - else if (bestCardLead(round)) { - const cardToPlay = getWorstCard(cards, round.suit) - if (cardToPlay) playCard(gameId, cardToPlay.name) - } - } - }, [gameId, round, isMyGo, cards, autoPlayCard]) - return null } diff --git a/src/components/Game/MyCards.tsx b/src/components/Game/MyCards.tsx index 20b2eb0..92946b5 100644 --- a/src/components/Game/MyCards.tsx +++ b/src/components/Game/MyCards.tsx @@ -24,10 +24,10 @@ import { toggleUniqueSelect, } from "caches/MyCardsSlice" import { - getAutoPlayCard, - toggleAutoPlay, + getCardToPlay, + togglePlayCard, clearAutoPlay, -} from "caches/AutoPlaySlice" +} from "caches/PlayCardSlice" import { CardContent, CardMedia, useTheme } from "@mui/material" import { pickBestCards } from "utils/GameUtils" @@ -55,7 +55,7 @@ const MyCards: React.FC = () => { const numPlayers = useAppSelector(getNumPlayers) const isRoundCalled = useAppSelector(getIsRoundCalled) const myCards = useAppSelector(getMyCards) - const autoPlayCard = useAppSelector(getAutoPlayCard) + const autoPlayCard = useAppSelector(getCardToPlay) const iamGoer = useAppSelector(getIamGoer) const prevRoundStatus = usePrevious(round?.status) @@ -104,7 +104,7 @@ const MyCards: React.FC = () => { dispatch(clearAutoPlay()) dispatch(clearSelectedCards()) } else if (event.detail === 2) { - dispatch(toggleAutoPlay(card)) + dispatch(togglePlayCard(card)) } else { dispatch(toggleUniqueSelect(card)) dispatch(clearAutoPlay()) diff --git a/src/components/Game/WebsocketManager.tsx b/src/components/Game/WebsocketManager.tsx index d4a2b00..234499b 100644 --- a/src/components/Game/WebsocketManager.tsx +++ b/src/components/Game/WebsocketManager.tsx @@ -16,7 +16,7 @@ import { GameState } from "model/Game" import { Actions, BuyCardsEvent } from "model/Events" import { useSnackbar } from "notistack" import { clearSelectedCards, updateMyCards } from "caches/MyCardsSlice" -import { clearAutoPlay } from "caches/AutoPlaySlice" +import { clearAutoPlay } from "caches/PlayCardSlice" import shuffleAudioFile from "assets/sounds/shuffle.ogg" import playCardAudioFile from "assets/sounds/play_card.ogg" diff --git a/src/pages/Game/Game.tsx b/src/pages/Game/Game.tsx index 01bec7e..75fe51f 100644 --- a/src/pages/Game/Game.tsx +++ b/src/pages/Game/Game.tsx @@ -10,7 +10,7 @@ import { useParams } from "react-router-dom" import { useAppDispatch, useAppSelector } from "caches/hooks" import { useSnackbar } from "notistack" import { getIamSpectator, getIsGameActive, resetGame } from "caches/GameSlice" -import { clearAutoPlay } from "caches/AutoPlaySlice" +import { clearAutoPlay } from "caches/PlayCardSlice" import { clearMyCards } from "caches/MyCardsSlice" import parseError from "utils/ErrorUtils" diff --git a/src/services/GameService.ts b/src/services/GameService.ts index 6c607d7..14d5609 100644 --- a/src/services/GameService.ts +++ b/src/services/GameService.ts @@ -14,7 +14,7 @@ import { removeCard, updateMyCards, } from "caches/MyCardsSlice" -import { clearAutoPlay } from "caches/AutoPlaySlice" +import { clearAutoPlay } from "caches/PlayCardSlice" const getGame = (gameId: string): AppThunk> => diff --git a/src/utils/GameUtils.ts b/src/utils/GameUtils.ts index 26a267c..3868fd8 100644 --- a/src/utils/GameUtils.ts +++ b/src/utils/GameUtils.ts @@ -147,8 +147,10 @@ export const bestCardLead = (round: Round) => { return round.currentHand.leadOut === trumpCards[0].name } -export const getWorstCard = (cards: string[], suit: Suit) => { - const myCardsRich = CARDS.filter(card => cards.some(c => c === card.name)) +export const getWorstCard = (cards: SelectableCard[], suit: Suit) => { + const myCardsRich = CARDS.filter(card => + cards.some(c => c.name === card.name), + ) const myTrumpCards = myCardsRich.filter( card => card.suit === suit || card.suit === Suit.WILD, ) @@ -161,13 +163,25 @@ export const getWorstCard = (cards: string[], suit: Suit) => { // Sort ascending by cold value myCardsRich.sort((a, b) => a.coldValue - b.coldValue) - // if we can't find a cold card that is clearly the worst card then do nothing - if ( - myCardsRich.length > 1 && - myCardsRich[0].coldValue === myCardsRich[1].coldValue - ) { - return - } + return myCardsRich[0] + } +} + +export const getBestCard = (cards: SelectableCard[], suit: Suit) => { + const myCardsRich = CARDS.filter(card => + cards.some(c => c.name === card.name), + ) + const myTrumpCards = myCardsRich.filter( + card => card.suit === 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 + myCardsRich.sort((a, b) => b.coldValue - a.coldValue) return myCardsRich[0] } From d93e6874a2ec9b707754fc93ec88faa2f8094667 Mon Sep 17 00:00:00 2001 From: Daithi Hearn Date: Sat, 8 Jul 2023 22:22:15 +0200 Subject: [PATCH 2/5] Making auto play button the priority --- src/components/Game/Actions/PlayCard.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/Game/Actions/PlayCard.tsx b/src/components/Game/Actions/PlayCard.tsx index 05f2388..d5e5c2f 100644 --- a/src/components/Game/Actions/PlayCard.tsx +++ b/src/components/Game/Actions/PlayCard.tsx @@ -62,7 +62,7 @@ const PlayCard = () => { // 2. If auto play is enabled, play best card // 3. Play worst card if best card lead out useEffect(() => { - if (round && round.suit && isMyGo) { + if (round?.suit && isMyGo) { if (cardToPlay) playCard(cardToPlay) else if (autoPlay) { const bestCard = getBestCard(myCards, round.suit) @@ -74,7 +74,6 @@ const PlayCard = () => { } }, [playCard, autoPlay, round, isMyGo, myCards, cardToPlay]) - if (!playButtonEnabled) return if (autoPlay) { return ( ) - } + } else if (!playButtonEnabled) return return ( <> ) - } else if (!playButtonEnabled) return + } else if (!playButtonEnabled) + return ( + <> + + + + ) return ( <>