From af9ba36883d902d2415811377e4a67fab4d11226 Mon Sep 17 00:00:00 2001 From: Jasper Van der Jeugt Date: Sun, 2 Aug 2020 17:39:26 +0200 Subject: Start voting phase --- server/cafp.cabal | 1 + server/lib/Cafp/Game.hs | 50 +++++++++++++++++++++++++++++++++++++-------- server/lib/Cafp/Messages.hs | 24 ++++++++++++++++------ 3 files changed, 60 insertions(+), 15 deletions(-) (limited to 'server') diff --git a/server/cafp.cabal b/server/cafp.cabal index e4d4194..14ef7ad 100644 --- a/server/cafp.cabal +++ b/server/cafp.cabal @@ -26,6 +26,7 @@ Library base >= 4.9 && < 5, bytestring >= 0.10 && < 0.11, elm-bridge >= 0.5 && < 0.6, + hashable >= 1.3 && < 1.4, lens >= 4.18 && < 4.19, mtl >= 2.2 && < 2.3, random >= 1.1 && < 1.2, diff --git a/server/lib/Cafp/Game.hs b/server/lib/Cafp/Game.hs index fa1c4aa..16350ab 100644 --- a/server/lib/Cafp/Game.hs +++ b/server/lib/Cafp/Game.hs @@ -36,13 +36,22 @@ import VectorShuffling.Immutable (shuffle) type PlayerId = Int +type Proposal = [WhiteCard] + data Table - = TableProposing BlackCard (HMS.HashMap PlayerId [WhiteCard]) + = TableProposing + !BlackCard + !(HMS.HashMap PlayerId Proposal) + | TableVoting + !BlackCard + !(HMS.HashMap PlayerId Proposal) + !(V.Vector (Proposal, [PlayerId])) + !(HMS.HashMap PlayerId Int) deriving (Show) data Player = Player - { _playerName :: Text - , _playerHand :: [WhiteCard] + { _playerName :: !Text + , _playerHand :: !(V.Vector WhiteCard) } deriving (Show) data Game = Game @@ -97,7 +106,7 @@ joinGame :: Game -> (PlayerId, Game) joinGame = runState $ do pid <- gameNextPlayerId %%= (\x -> (x, x + 1)) let name = "Player " <> T.pack (show pid) - hand <- replicateM 6 popWhiteCard + hand <- V.replicateM 6 popWhiteCard gamePlayers %= HMS.insert pid (Player name hand) pure pid @@ -108,20 +117,34 @@ blackCardBlanks :: Cards -> BlackCard -> Int blackCardBlanks cards (BlackCard c) = maybe 0 (length . T.breakOnAll "\\BLANK") $ cardsBlack cards V.!? c +stepGame :: Game -> Game +stepGame game = case game ^. gameTable of + TableProposing black proposals + | HMS.null ((game ^. gamePlayers) `HMS.difference` proposals) -> + let proposalsMap = HMS.fromListWith (++) $ do + (pid, proposal) <- HMS.toList proposals + pure (proposal, [pid]) + (shuffled, seed) = shuffle + (V.fromList $ HMS.toList proposalsMap) (game ^. gameSeed) in + game & gameSeed .~ seed + & gameTable .~ TableVoting black proposals shuffled HMS.empty + | otherwise -> game + TableVoting _ _ _ _ -> game + processClientMessage :: PlayerId -> ClientMessage -> Game -> Game processClientMessage pid msg game = case msg of ChangeMyName name -> game & gamePlayers . ix pid . playerName .~ name ProposeWhiteCards cs - -- Bad card(s) proposed. + -- Bad card(s) proposed, i.e. not in hand of player. | any (not . (`elem` hand)) cs -> game -- Proposal already made. | Just _ <- game ^? gameTable . _TableProposing . _2 . ix pid -> game -- Not enough cards submitted. | Just b <- game ^? gameTable . _TableProposing . _1 , blackCardBlanks (game ^. gameCards) b /= length cs -> game - -- TODO: Check that the card is in the hand of the player. - | otherwise -> + -- All good. + | otherwise -> stepGame $ game & gameTable . _TableProposing . _2 . at pid .~ Just cs where hand = game ^.. gamePlayers . ix pid . playerHand . traverse @@ -133,15 +156,24 @@ gameViewForPlayer self game = guard $ pid /= self pure $ Opponent (p ^. playerName) $ case game ^. gameTable of TableProposing _ proposals -> HMS.member pid proposals + TableVoting _ _ _ votes -> HMS.member pid votes player = game ^. gamePlayers . at self table = case game ^. gameTable of TableProposing black proposals -> - Proposing black . fromMaybe [] $ HMS.lookup self proposals in + Proposing black . fromMaybe [] $ HMS.lookup self proposals + TableVoting black proposals shuffled votes -> Voting + black + (fromMaybe [] $ HMS.lookup self proposals) + [ proposal + | (proposal, players) <- V.toList shuffled + , not $ self `elem` players + ] + (HMS.lookup self votes) in GameView { gameViewOpponents = opponents , gameViewMyName = maybe "" (^. playerName) player , gameViewTable = table - , gameViewHand = maybe [] (^. playerHand) player + , gameViewHand = player ^.. traverse . playerHand . traverse } diff --git a/server/lib/Cafp/Messages.hs b/server/lib/Cafp/Messages.hs index aae49cc..ea6361c 100644 --- a/server/lib/Cafp/Messages.hs +++ b/server/lib/Cafp/Messages.hs @@ -1,3 +1,4 @@ +{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE TemplateHaskell #-} module Cafp.Messages ( BlackCard (..) @@ -10,17 +11,23 @@ module Cafp.Messages , ClientMessage (..) ) where -import Data.Text (Text) -import Data.Vector (Vector) +import Data.Hashable (Hashable) +import Data.Text (Text) +import Data.Vector (Vector) import Elm.Derive +import GHC.Generics (Generic) -data BlackCard = BlackCard Int deriving (Eq, Show) +data BlackCard = BlackCard Int deriving (Eq, Generic, Show) -data WhiteCard = WhiteCard Int deriving (Eq, Show) +instance Hashable BlackCard + +data WhiteCard = WhiteCard Int deriving (Eq, Generic, Show) + +instance Hashable WhiteCard data Cards = Cards - { cardsBlack :: Vector Text - , cardsWhite :: Vector Text + { cardsBlack :: Vector Text + , cardsWhite :: Vector Text } deriving (Show) data Opponent = Opponent @@ -30,6 +37,11 @@ data Opponent = Opponent data TableView = Proposing BlackCard [WhiteCard] + | Voting + BlackCard + [WhiteCard] -- ^ My proposal + [[WhiteCard]] -- ^ Proposals to vote for + (Maybe Int) -- ^ My vote deriving (Show) data GameView = GameView -- cgit v1.2.3