|
- {-# LANGUAGE TypeSynonymInstances #-}
- {-# LANGUAGE FlexibleInstances #-}
- {-# LANGUAGE OverloadedStrings #-}
-
- module Skat.AI.Online where
-
- import Control.Monad.Reader
- import Control.Concurrent.Chan
- import Data.Aeson
- import Data.Maybe
- import qualified Data.ByteString.Lazy.Char8 as BS
-
- import Skat.Player
- import qualified Skat.Player.Utils as P
- import Skat.Pile
- import Skat.Card
- import Skat.Render
- import Skat.Preperation
- import Skat.Bidding
-
- class Communicator a where
- send :: a -> String -> IO ()
- receive :: a -> IO String
-
- instance Communicator (Chan String) where
- send = writeChan
- receive = readChan
-
- class Monad m => MonadClient m where
- query :: String -> m ()
- response :: m String
-
- data OnlineEnv c = OnlineEnv { getTeam :: Team
- , getHand :: Hand
- , connection :: c }
-
- data PrepOnline c = PrepOnline { prepHand :: Hand
- , prepConnection :: c
- , prepCards :: [Card] }
-
- instance Show (OnlineEnv c) where
- show _ = "An online env"
-
- instance Show (PrepOnline c) where
- show _ = "An online prep env"
-
- instance Communicator c => Player (OnlineEnv c) where
- team = getTeam
- hand = getHand
- chooseCard p table _ hand = runReaderT (choose table hand) p >>= \c -> return (c, p)
- onCardPlayed p c = runReaderT (cardPlayed c) p >> return p
- onGameResults p res = runReaderT (onResults res) p
- onGameStart p singlePlayer = runReaderT (onStartOnline singlePlayer) p
-
- instance Communicator c => Bidder (PrepOnline c) where
- hand = prepHand
- askBid p against bid = do
- liftIO $ send (prepConnection p) (BS.unpack $ encode $ BidQuery against bid)
- r <- liftIO $ receive (prepConnection p)
- case decode (BS.pack r) of
- Just (BidResponse newBid) -> do
- if newBid > bid then return $ Just newBid else return Nothing
- Nothing -> askBid p against bid
- askResponse p bidder bid = do
- liftIO $ send (prepConnection p) (BS.unpack $ encode $ BidResponseQuery bidder bid)
- r <- liftIO $ receive (prepConnection p)
- case decode (BS.pack r) of
- Just (YesNo value) -> return value
- Nothing -> askResponse p bidder bid
- askGame p bid = do
- liftIO $ send (prepConnection p) (BS.unpack $ encode $ AskGameQuery bid)
- r <- liftIO $ receive (prepConnection p)
- case decode (BS.pack r) of
- Just (GameResponse game) -> return game
- Nothing -> askGame p bid
- askHand p bid = do
- liftIO $ send (prepConnection p) (BS.unpack $ encode $ AskHandQuery)
- r <- liftIO $ receive (prepConnection p)
- case decode (BS.pack r) of
- Just (YesNo value) -> return value
- Nothing -> askHand p bid
- askSkat p bid cards = do
- liftIO $ send (prepConnection p) (BS.unpack $ encode $ AskSkatQuery cards bid)
- r <- liftIO $ receive (prepConnection p)
- case decode (BS.pack r) of
- Just (ChosenCards cards) -> return cards
- Nothing -> askSkat p bid cards
- toPlayer p tm = PL $ OnlineEnv tm (prepHand p) (prepConnection p)
- onStart p = do
- let cards = prepCards p
- liftIO $ send (prepConnection p) (BS.unpack $ encode $ CardsQuery cards)
-
- type Online a m = ReaderT (OnlineEnv a) m
-
- instance (Communicator c, MonadIO m) => MonadClient (Online c m) where
- query s = do
- conn <- asks connection
- liftIO $ send conn s
- response = do
- conn <- asks connection
- liftIO $ receive conn
-
- instance MonadPlayer m => MonadPlayer (Online a m) where
- trumpColour = lift $ trumpColour
- turnColour = lift $ turnColour
- showSkat = lift . showSkat
-
- choose :: HasCard a => (Communicator c, MonadPlayer m) => [CardS Played] -> [a] -> Online c m Card
- choose table hand' = do
- let hand = map toCard hand'
- query (BS.unpack $ encode $ ChooseQuery hand table)
- r <- response
- case decode (BS.pack r) of
- Just (ChosenResponse card) -> do
- allowed <- P.isAllowed hand card
- if card `elem` hand && allowed then return card else choose table hand'
- Nothing -> choose table hand'
-
- cardPlayed :: (Communicator c, MonadPlayer m) => CardS Played -> Online c m ()
- cardPlayed card = query (BS.unpack $ encode $ CardPlayedQuery card)
-
- onResults :: (Communicator c, MonadIO m) => (Int, Int) -> Online c m ()
- onResults (sgl, tm) = query (BS.unpack $ encode $ GameResultsQuery sgl tm)
-
- onStartOnline :: (Communicator c, MonadPlayer m) => Hand -> Online c m ()
- onStartOnline singlePlayer = do
- trCol <- trumpColour
- ownHand <- asks getHand
- query (BS.unpack $ encode $ GameStartQuery trCol ownHand singlePlayer)
-
- -- | QUERIES AND RESPONSES
-
- data Query = ChooseQuery [Card] [CardS Played]
- | CardPlayedQuery (CardS Played)
- | GameResultsQuery Int Int
- | GameStartQuery Colour Hand Hand
- | BidQuery Hand Bid
- | BidResponseQuery Hand Bid
- | AskGameQuery Bid
- | AskHandQuery
- | AskSkatQuery [Card] Bid
- | CardsQuery [Card]
-
- newtype ChosenResponse = ChosenResponse Card
- newtype BidResponse = BidResponse Int
- newtype YesNo = YesNo Bool
- newtype GameResponse = GameResponse Game
- newtype ChosenCards = ChosenCards [Card]
-
- instance ToJSON Query where
- toJSON (ChooseQuery hand table) =
- object ["query" .= ("choose_card" :: String), "hand" .= hand, "table" .= table]
- toJSON (CardPlayedQuery card) =
- object ["query" .= ("card_played" :: String), "card" .= card]
- toJSON (GameResultsQuery sgl tm) =
- object ["query" .= ("results" :: String), "single" .= sgl, "team" .= tm]
- toJSON (GameStartQuery trumps handNo sglPlayer) =
- object ["query" .= ("start_game" :: String), "trumps" .= show trumps,
- "hand" .= toInt handNo, "single" .= toInt sglPlayer ]
- toJSON (BidQuery hand bid) =
- object ["query" .= ("bid" :: String), "whom" .= show hand ]
- toJSON (BidResponseQuery hand bid) =
- object ["query" .= ("bid_response" :: String), "from" .= show hand ]
- toJSON (AskHandQuery) =
- object ["query" .= ("play_hand" :: String)]
- toJSON (AskSkatQuery cards bid) =
- object ["query" .= ("skat" :: String), "cards" .= cards, "bid" .= bid ]
- toJSON (CardsQuery cards) =
- object ["query" .= ("cards" :: String), "cards" .= cards ]
-
- instance FromJSON ChosenResponse where
- parseJSON = withObject "ChosenResponse" $ \v -> ChosenResponse
- <$> v .: "card"
-
- instance FromJSON BidResponse where
- parseJSON = withObject "BidResponse" $ \v -> BidResponse
- <$> v .: "bid"
-
- instance FromJSON YesNo where
- parseJSON = withObject "BidYesNo" $ \v -> YesNo
- <$> v .: "yesno"
-
- instance FromJSON GameResponse where
- parseJSON = withObject "GameResponse" $ \v -> GameResponse
- <$> v .: "game"
-
- instance FromJSON ChosenCards where
- parseJSON = withObject "ChosenCards" $ \v -> ChosenCards
- <$> v .: "cards"
|