Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f726da241 | ||
|
|
da217b5196 |
@@ -6,3 +6,4 @@
|
|||||||
*.hi
|
*.hi
|
||||||
*.o
|
*.o
|
||||||
*.prof
|
*.prof
|
||||||
|
*.hp
|
||||||
|
|||||||
+6
-3
@@ -7,6 +7,8 @@ module AI.Rulebased (
|
|||||||
mkAIEnv, testds, simplify
|
mkAIEnv, testds, simplify
|
||||||
) where
|
) where
|
||||||
|
|
||||||
|
import Control.Parallel.Strategies
|
||||||
|
|
||||||
import Data.Ord
|
import Data.Ord
|
||||||
import Data.Monoid ((<>))
|
import Data.Monoid ((<>))
|
||||||
import Data.List
|
import Data.List
|
||||||
@@ -163,6 +165,7 @@ compareGuess (c1, ops1) (c2, ops2)
|
|||||||
distributions :: Guess -> (Int, Int, Int, Int) -> [Distribution]
|
distributions :: Guess -> (Int, Int, Int, Int) -> [Distribution]
|
||||||
distributions guess nos =
|
distributions guess nos =
|
||||||
helper (sortBy compareGuess $ M.toList guess) nos
|
helper (sortBy compareGuess $ M.toList guess) nos
|
||||||
|
`using` parList rdeepseq
|
||||||
where helper [] _ = []
|
where helper [] _ = []
|
||||||
helper ((c, hs):[]) ns = map fst (distr c hs ns)
|
helper ((c, hs):[]) ns = map fst (distr c hs ns)
|
||||||
helper ((c, hs):gs) ns =
|
helper ((c, hs):gs) ns =
|
||||||
@@ -246,9 +249,9 @@ chooseStatistic = do
|
|||||||
2 -> 2
|
2 -> 2
|
||||||
3 -> 3
|
3 -> 3
|
||||||
-- simulate only partially
|
-- simulate only partially
|
||||||
4 -> 2
|
4 -> 3
|
||||||
5 -> 1
|
5 -> 2
|
||||||
6 -> 1
|
6 -> 2
|
||||||
7 -> 1
|
7 -> 1
|
||||||
8 -> 1
|
8 -> 1
|
||||||
9 -> 1
|
9 -> 1
|
||||||
|
|||||||
+105
@@ -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
|
||||||
@@ -6,6 +6,7 @@ module Card where
|
|||||||
import Data.List
|
import Data.List
|
||||||
import System.Random (newStdGen)
|
import System.Random (newStdGen)
|
||||||
import Utils
|
import Utils
|
||||||
|
import Control.DeepSeq
|
||||||
|
|
||||||
class Countable a b where
|
class Countable a b where
|
||||||
count :: a -> b
|
count :: a -> b
|
||||||
@@ -57,6 +58,9 @@ instance Countable Card Int where
|
|||||||
instance Countable [Card] Int where
|
instance Countable [Card] Int where
|
||||||
count = sum . map count
|
count = sum . map count
|
||||||
|
|
||||||
|
instance NFData Card where
|
||||||
|
rnf (Card t c) = t `seq` c `seq` ()
|
||||||
|
|
||||||
equals :: Colour -> Maybe Colour -> Bool
|
equals :: Colour -> Maybe Colour -> Bool
|
||||||
equals col (Just x) = col == x
|
equals col (Just x) = col == x
|
||||||
equals col Nothing = True
|
equals col Nothing = True
|
||||||
|
|||||||
@@ -9,11 +9,29 @@ 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 ()
|
||||||
main = putStrLn "Hello World"
|
main = testAI 10
|
||||||
|
|
||||||
|
testAI :: Int -> IO ()
|
||||||
|
testAI n = do
|
||||||
|
let acs = repeat runAI
|
||||||
|
vals <- sequence (take n acs)
|
||||||
|
putStrLn $ "average won points " ++ show (fromIntegral (sum vals) / fromIntegral n)
|
||||||
|
|
||||||
|
runAI :: IO Int
|
||||||
|
runAI = do
|
||||||
|
env <- shuffledEnv
|
||||||
|
let ps = piles env
|
||||||
|
cs = handCards Hand3 ps
|
||||||
|
trs = filter (isTrump Spades) cs
|
||||||
|
if length trs >= 5 && any ((==32) . getID) cs
|
||||||
|
then do
|
||||||
|
pts <- fst <$> evalStateT (turn Hand1) env
|
||||||
|
if pts > 60 then return 1 else return 0
|
||||||
|
else runAI
|
||||||
|
|
||||||
env :: SkatEnv
|
env :: SkatEnv
|
||||||
env = SkatEnv piles Nothing Spades playersExamp
|
env = SkatEnv piles Nothing Spades playersExamp
|
||||||
@@ -26,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
|
||||||
@@ -50,8 +68,3 @@ env2 = SkatEnv piles Nothing Spades playersExamp
|
|||||||
h3 = map (putAt Hand3) hand3
|
h3 = map (putAt Hand3) hand3
|
||||||
piles = Piles (h1 ++ h2 ++ h3) [] []
|
piles = Piles (h1 ++ h2 ++ h3) [] []
|
||||||
|
|
||||||
testAI :: Int -> IO ()
|
|
||||||
testAI n = do
|
|
||||||
let acs = repeat (shuffledEnv >>= evalStateT (turnGeneric playOpen 10 Hand1) )
|
|
||||||
vals <- sequence (take n acs)
|
|
||||||
putStrLn $ "average won points " ++ show (fromIntegral (sum (map fst vals)) / fromIntegral n)
|
|
||||||
|
|||||||
Reference in New Issue
Block a user