{-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} module Skat.AI.Online where import Control.Monad.Reader import Control.Concurrent.Chan import Data.Aeson hiding (Result) 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 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) onBid p mayBid reizer gereizter = liftIO $ send (prepConnection p) (BS.unpack $ encode $ BidEvent mayBid reizer gereizter) onResponse p response reizer gereizter = liftIO $ send (prepConnection p) (BS.unpack $ encode $ ResponseEvent response reizer gereizter) onStart p = do let cards = sortRender Jacks $ prepCards p liftIO $ send (prepConnection p) (BS.unpack $ encode $ CardsQuery cards) onResult p res = liftIO $ send (prepConnection p) (BS.unpack $ encode $ GameResultsQuery res) onGame p game sglPlayer = do liftIO $ send (prepConnection p) (BS.unpack $ encode $ GameStartQuery game sglPlayer) 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 trump = lift $ trump 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 = sortRender Jacks $ 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) -- | QUERIES AND RESPONSES data Query = ChooseQuery [Card] [CardS Played] | CardPlayedQuery (CardS Played) | GameResultsQuery Result | GameStartQuery Game Hand | BidQuery Hand Bid | BidResponseQuery Hand Bid | AskGameQuery Bid | AskHandQuery | AskSkatQuery [Card] Bid | CardsQuery [Card] | BidEvent (Maybe Bid) Hand Hand | ResponseEvent Bool Hand Hand newtype ChosenResponse = ChosenResponse Card newtype BidResponse = BidResponse Int newtype YesNo = YesNo Bool newtype GameResponse = GameResponse Game deriving Show 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 result) = object ["query" .= ("results" :: String), "result" .= result] toJSON (GameStartQuery game sglPlayer) = object [ "query" .= ("start_game" :: String) , "game" .= game , "single" .= toInt sglPlayer ] toJSON (BidQuery hand bid) = object ["query" .= ("bid" :: String), "whom" .= show hand, "current" .= bid] toJSON (BidResponseQuery hand bid) = object ["query" .= ("bid_response" :: String), "from" .= show hand, "bid" .= bid ] 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 ] toJSON (AskGameQuery bid) = object ["query" .= ("ask_game" :: String), "bid" .= bid] toJSON (BidEvent (Just bid) reizer gereizter) = object ["query" .= ("bid_event" :: String), "bid" .= bid, "reizer" .= show reizer, "gereizter" .= show gereizter ] toJSON (BidEvent Nothing reizer gereizter) = object [ "query" .= ("bid_event" :: String) , "bid" .= ("weg" :: String) , "reizer" .= show reizer , "gereizter" .= show gereizter ] toJSON (ResponseEvent response reizer gereizter) = object [ "query" .= ("response_event" :: String) , "response" .= response , "reizer" .= show reizer , "gereizter" .= show gereizter ] 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"