| @@ -0,0 +1,105 @@ | |||||
| module AI.Server where | |||||
| import qualified Network.Socket as Net | |||||
| import qualified System.IO as Sys | |||||
| import Control.Concurrent | |||||
| import Control.Concurrent.Chan | |||||
| import Control.Monad (forever) | |||||
| import Control.Monad.Reader | |||||
| import Data.List.Split | |||||
| data Buffering = NoBuffering | |||||
| | LengthBuffering | |||||
| | DelimiterBuffering String | |||||
| deriving (Show) | |||||
| data ServerEnv = ServerEnv | |||||
| { buffering :: Buffering -- ^ Buffermode | |||||
| , socket :: Net.Socket -- ^ the socket used to communicate | |||||
| , global :: Chan String | |||||
| , onReceive :: OnReceive | |||||
| } | |||||
| instance Show ServerEnv where | |||||
| show env = "A Server" | |||||
| type Server = ReaderT ServerEnv IO | |||||
| type OnReceive = Sys.Handle -> Net.SockAddr -> String -> Server () | |||||
| broadcast :: String -> Server () | |||||
| broadcast msg = do | |||||
| bufmode <- asks buffering | |||||
| chan <- asks global | |||||
| case bufmode of | |||||
| DelimiterBuffering delim -> liftIO $ writeChan chan $ msg ++ delim | |||||
| _ -> liftIO $ writeChan chan msg | |||||
| send :: Sys.Handle -> String -> Server () | |||||
| send connhdl msg = do | |||||
| bufmode <- asks buffering | |||||
| case bufmode of | |||||
| DelimiterBuffering delim -> liftIO $ Sys.hPutStr connhdl $ msg ++ delim | |||||
| _ -> liftIO $ Sys.hPutStr connhdl msg | |||||
| -- | Initialize a new server with the given port number and buffering mode | |||||
| initServer :: Net.PortNumber -> Buffering -> OnReceive -> IO ServerEnv | |||||
| initServer port buffermode handler = do | |||||
| sock <- Net.socket Net.AF_INET Net.Stream 0 | |||||
| Net.setSocketOption sock Net.ReuseAddr 1 | |||||
| Net.bind sock (Net.SockAddrInet port Net.iNADDR_ANY) | |||||
| Net.listen sock 5 | |||||
| chan <- newChan | |||||
| forkIO $ forever $ do | |||||
| msg <- readChan chan -- clearing the main channel | |||||
| return () | |||||
| return (ServerEnv buffermode sock chan handler) | |||||
| close :: ServerEnv -> IO () | |||||
| close = Net.close . socket | |||||
| -- | Looping over requests and establish connection | |||||
| procRequests :: Server () | |||||
| procRequests = do | |||||
| sock <- asks socket | |||||
| (conn, clientaddr) <- liftIO $ Net.accept sock | |||||
| env <- ask | |||||
| liftIO $ forkIO $ runReaderT (procMessages conn clientaddr) env | |||||
| procRequests | |||||
| -- | Handle one client | |||||
| procMessages :: Net.Socket -> Net.SockAddr -> Server () | |||||
| procMessages conn clientaddr = do | |||||
| connhdl <- liftIO $ Net.socketToHandle conn Sys.ReadWriteMode | |||||
| liftIO $ Sys.hSetBuffering connhdl Sys.NoBuffering | |||||
| globalChan <- asks global | |||||
| commChan <- liftIO $ dupChan globalChan | |||||
| reader <- liftIO $ forkIO $ forever $ do | |||||
| msg <- readChan commChan | |||||
| Sys.hPutStrLn connhdl msg | |||||
| handler <- asks onReceive | |||||
| messages <- liftIO $ Sys.hGetContents connhdl | |||||
| buffermode <- asks buffering | |||||
| case buffermode of | |||||
| DelimiterBuffering delimiter -> | |||||
| mapM_ (handler connhdl clientaddr) (splitOn delimiter messages) | |||||
| LengthBuffering -> liftIO $ putStrLn (take 4 messages) | |||||
| _ -> return () | |||||
| -- clean up | |||||
| liftIO $ do killThread reader | |||||
| Sys.hClose connhdl | |||||
| sampleHandler :: OnReceive | |||||
| sampleHandler connhdl addr query = do | |||||
| liftIO $ putStrLn $ "new query " ++ query | |||||
| send connhdl $ "> " ++ query | |||||
| main :: IO () | |||||
| main = do | |||||
| env <- initServer 4242 LengthBuffering sampleHandler | |||||
| runReaderT procRequests env | |||||
| @@ -0,0 +1,98 @@ | |||||
| {-# LANGUAGE TypeSynonymInstances #-} | |||||
| {-# LANGUAGE FlexibleInstances #-} | |||||
| {-# LANGUAGE FlexibleContexts #-} | |||||
| module AI.Socket ( | |||||
| mkSocketEnv | |||||
| ) where | |||||
| import Control.Monad.Trans (liftIO) | |||||
| import Control.Monad.Reader | |||||
| import Control.Monad.State | |||||
| import Control.Concurrent | |||||
| import Control.Concurrent.Chan | |||||
| import Player | |||||
| import Pile | |||||
| import Card | |||||
| import Utils | |||||
| import Render | |||||
| import AI.Server | |||||
| data SocketEnv = SocketEnv { getTeam :: Team | |||||
| , getHand :: Hand | |||||
| , table :: [CardS Played] | |||||
| , myHand :: [Card] | |||||
| , socketThread :: Maybe ThreadId | |||||
| , socketServer :: Maybe ServerEnv } | |||||
| deriving Show | |||||
| setTable :: [CardS Played] -> SocketEnv -> SocketEnv | |||||
| setTable tab env = env { table = tab } | |||||
| setHand :: [Card] -> SocketEnv -> SocketEnv | |||||
| setHand hand env = env { myHand = hand } | |||||
| setSocket :: ThreadId -> SocketEnv -> SocketEnv | |||||
| setSocket n env = env { socketThread = Just n } | |||||
| clearSocket :: SocketEnv -> SocketEnv | |||||
| clearSocket env = env { socketThread = Nothing } | |||||
| setServer :: ServerEnv -> SocketEnv -> SocketEnv | |||||
| setServer s env = env { socketServer = Just s } | |||||
| type Socket m = StateT SocketEnv m | |||||
| instance MonadPlayer m => MonadPlayer (Socket m) where | |||||
| trumpColour = lift $ trumpColour | |||||
| turnColour = lift $ turnColour | |||||
| showSkat = lift . showSkat | |||||
| instance Player SocketEnv where | |||||
| team = getTeam | |||||
| hand = getHand | |||||
| chooseCard p table _ hand = runStateT (do | |||||
| modify $ setTable table | |||||
| modify $ setHand hand | |||||
| choose) p | |||||
| choose :: MonadPlayer m => Socket m Card | |||||
| choose = do | |||||
| initialize | |||||
| trumpCol <- trumpColour | |||||
| turnCol <- turnColour | |||||
| hand <- gets myHand | |||||
| (Just server) <- gets socketServer | |||||
| liftIO $ writeChan (global server) "hi" | |||||
| let possible = filter (isAllowed trumpCol turnCol hand) hand | |||||
| case length hand of | |||||
| 1 -> liftIO (putStrLn "stopping server") >> stop | |||||
| _ -> return () | |||||
| return $ head possible | |||||
| initialize :: MonadPlayer m => Socket m () | |||||
| initialize = do | |||||
| state <- gets socketThread | |||||
| case state of | |||||
| Just _ -> return () | |||||
| Nothing -> do | |||||
| liftIO $ putStrLn "initializing server" | |||||
| server <- liftIO $ initServer 4242 (DelimiterBuffering "\n") sampleHandler | |||||
| n <- liftIO $ forkIO $ runReaderT procRequests server | |||||
| modify $ setSocket n | |||||
| modify $ setServer server | |||||
| stop :: MonadPlayer m => Socket m () | |||||
| stop = do | |||||
| state <- gets socketThread | |||||
| case state of | |||||
| Just n -> do liftIO $ putStrLn "killing thread" | |||||
| liftIO $ killThread n | |||||
| modify clearSocket | |||||
| Just server <- gets socketServer | |||||
| liftIO $ close server | |||||
| Nothing -> return () | |||||
| mkSocketEnv :: Team -> Hand -> SocketEnv | |||||
| mkSocketEnv tm h = SocketEnv tm h [] [] Nothing Nothing | |||||
| @@ -9,7 +9,7 @@ import Player | |||||
| import Pile | import Pile | ||||
| import AI.Stupid | import AI.Stupid | ||||
| import AI.Human | |||||
| import AI.Socket | |||||
| import AI.Rulebased | import AI.Rulebased | ||||
| main :: IO () | main :: IO () | ||||
| @@ -28,7 +28,9 @@ runAI = do | |||||
| cs = handCards Hand3 ps | cs = handCards Hand3 ps | ||||
| trs = filter (isTrump Spades) cs | trs = filter (isTrump Spades) cs | ||||
| if length trs >= 5 && any ((==32) . getID) cs | if length trs >= 5 && any ((==32) . getID) cs | ||||
| then fst <$> evalStateT (turn Hand1) env | |||||
| then do | |||||
| pts <- fst <$> evalStateT (turn Hand1) env | |||||
| if pts > 60 then return 1 else return 0 | |||||
| else runAI | else runAI | ||||
| env :: SkatEnv | env :: SkatEnv | ||||
| @@ -42,7 +44,7 @@ envStupid = SkatEnv piles Nothing Spades pls2 | |||||
| playersExamp :: Players | playersExamp :: Players | ||||
| playersExamp = Players | playersExamp = Players | ||||
| (PL $ Stupid Team Hand1) | (PL $ Stupid Team Hand1) | ||||
| (PL $ Stupid Team Hand2) | |||||
| (PL $ mkSocketEnv Team Hand2) | |||||
| (PL $ mkAIEnv Single Hand3 10) | (PL $ mkAIEnv Single Hand3 10) | ||||
| pls2 :: Players | pls2 :: Players | ||||