Christian Merten 1 год назад
Родитель
Сommit
df561c2b85
Подписано: christian <christian@flavigny.de> Идентификатор GPG ключа: D953D69721B948B3
7 измененных файлов: 254 добавлений и 43 удалений
  1. +14
    -7
      src/Skat/AI/Base.hs
  2. +115
    -4
      src/Skat/AI/Games/Skat/Guess.hs
  3. +43
    -18
      src/Skat/AI/MonteCarlo.hs
  4. +47
    -8
      src/Skat/AI/Skat.hs
  5. +1
    -0
      src/Skat/Bidding.hs
  6. +3
    -3
      src/Skat/Card.hs
  7. +31
    -3
      src/Skat/Pile.hs

+ 14
- 7
src/Skat/AI/Base.hs Просмотреть файл

@@ -7,6 +7,8 @@


module Skat.AI.Base where module Skat.AI.Base where


import Data.Set (Set)
import qualified Data.Set as S
import System.Random (Random) import System.Random (Random)
import qualified System.Random as Rand import qualified System.Random as Rand
import Control.Monad.State import Control.Monad.State
@@ -49,14 +51,20 @@ class (MonadIO m, Show t, Show v, Show p, MonadGame t l v p m) => PlayableGame t
class Choose t m | m -> t where class Choose t m | m -> t where
choose :: m t choose :: m t


class MonadRandom m where
class Monad m => MonadRandom m where
random :: Random a => m a random :: Random a => m a
randomR :: Random a => (a, a) -> m a
chooser :: [a] -> m a chooser :: [a] -> m a
chooser [] = error "chooser: empty list"
chooser os = (os!!) <$> randomR (0, length os - 1)
chooserS :: Set a -> m a
chooserS set
| S.null set = error "chooserS: empty set"
| otherwise = (`S.elemAt` set) <$> randomR (0, S.size set - 1)


instance MonadRandom IO where instance MonadRandom IO where
random = Rand.randomIO random = Rand.randomIO
chooser [] = error "chooser: empty list"
chooser os = (os!!) <$> Rand.randomRIO (0, length os -1)
randomR = Rand.randomRIO


instance MonadRandom (State Rand.StdGen) where instance MonadRandom (State Rand.StdGen) where
random = do random = do
@@ -64,9 +72,8 @@ instance MonadRandom (State Rand.StdGen) where
let (a, gen') = Rand.random gen let (a, gen') = Rand.random gen
put gen' put gen'
return a return a
chooser [] = error "chooser: empty list"
chooser os = do
randomR bds = do
gen <- get gen <- get
let (a, gen') = Rand.randomR (0, length os -1) gen
let (a, gen') = Rand.randomR bds gen
put gen' put gen'
return (os !! a)
return a

+ 115
- 4
src/Skat/AI/Games/Skat/Guess.hs Просмотреть файл

@@ -6,6 +6,7 @@ module Skat.AI.Games.Skat.Guess where


import GHC.Generics (Generic, Generic1) import GHC.Generics (Generic, Generic1)
import Data.Ord import Data.Ord
import Data.Aeson
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import Data.List import Data.List
import Data.Set (Set) import Data.Set (Set)
@@ -30,7 +31,7 @@ import Control.DeepSeq


data Option = H Hand data Option = H Hand
| Skt | Skt
deriving (Show, Eq, Ord, Generic, NFData)
deriving (Show, Eq, Ord, Generic, NFData, ToJSON)


type Guess = Map Card (Set Option) type Guess = Map Card (Set Option)


@@ -69,6 +70,22 @@ hasNoLonger trump hand effCol = M.mapWithKey f
S.filter (/=H hand) hands S.filter (/=H hand) hands
| otherwise = hands | otherwise = hands


observe :: Trump -> Maybe TurnColour -> [CardS Played] -> Guess -> Guess
observe _ Nothing _ guess = guess
observe trpCol (Just turnCol) tbl oldGuess = foldr f oldGuess tbl
where f :: CardS Played -> Guess -> Guess
f c g = let col = effectiveColour trpCol (toCard c)
in if col /= turnCol
then hasNoLonger trpCol (uorigin $ getPile c) turnCol g
else g

observeS :: Guess -> Skat Guess
observeS guess = do
trpCol <- trump
turnCol <- gets Skat.turnColour
tbl <- getp tableCards
pure $ observe trpCol turnCol tbl guess

isSkat :: [Card] -> Guess -> Guess isSkat :: [Card] -> Guess -> Guess
isSkat cs = M.mapWithKey f isSkat cs = M.mapWithKey f
where f card hands where f card hands
@@ -96,6 +113,36 @@ choosen = choosen2
smplguess :: Guess smplguess :: Guess
smplguess = Hand1 `hasOnly` [(Card Seven Diamonds)..(Card Eight Hearts)] $! newGuess smplguess = Hand1 `hasOnly` [(Card Seven Diamonds)..(Card Eight Hearts)] $! newGuess


smplguess2 :: Guess
smplguess2 = M.fromList
[ ( Card Seven Diamonds, S.fromList [H Hand2, H Hand3] )
, ( Card Eight Hearts, S.fromList [H Hand2, H Hand1] )
, ( Card Nine Spades, S.fromList [H Hand1, H Hand2] )
, ( Card Nine Diamonds, S.fromList [Skt] )
, ( Card Eight Diamonds, S.fromList [Skt] )
]

smplguess3 :: Guess
smplguess3 = M.fromList
[ (Card Nine Clubs, S.fromList [Skt])
, (Card Queen Clubs, S.fromList [Skt])
, (Card Ten Hearts, S.fromList [H Hand2,H Hand3])
, (Card Ace Diamonds, S.fromList [H Hand2])
]

smplguess4 :: Guess
smplguess4 = M.fromList
[ (Card Seven Spades, S.fromList [H Hand1])
, (Card Nine Spades, S.fromList [H Hand1])
, (Card Eight Spades, S.fromList [H Hand2])
, (Card Queen Diamonds, S.fromList [H Hand3])
, (Card Ace Diamonds, S.fromList [H Hand3])
, (Card King Clubs, S.fromList [H Hand2,H Hand3])
, (Card Ace Clubs, S.fromList [H Hand2,H Hand3])
, (Card Nine Clubs, S.fromList [Skt])
, (Card Queen Clubs, S.fromList [Skt])
]

distributions2 :: Guess -> (Int, Int, Int, Int) -> [Distribution] distributions2 :: Guess -> (Int, Int, Int, Int) -> [Distribution]
distributions2 !guess1 !(n1, n2, n3, nskt) = do distributions2 !guess1 !(n1, n2, n3, nskt) = do
let h1cards = M.keys $!! M.filter (H Hand1 `elem`) guess1 let h1cards = M.keys $!! M.filter (H Hand1 `elem`) guess1
@@ -142,7 +189,7 @@ randomChoice options = do
g Skt = n4 > 0 g Skt = n4 > 0
opts = S.toList $ S.filter g options opts = S.toList $ S.filter g options
--when (null opts) $ error "randomChoice: after filtering options are empty" --when (null opts) $ error "randomChoice: after filtering options are empty"
option <- lift $ chooser opts
option <- if null opts then (error ("randomChoice: opts empty, " ++ show options ++ " " ++ show (n1,n2,n3,n4))) else lift (chooser opts)
let (n1', n2', n3', n4') = case option of let (n1', n2', n3', n4') = case option of
H Hand1 -> (n1-1, n2, n3, n4) H Hand1 -> (n1-1, n2, n3, n4)
H Hand2 -> (n1, n2-1, n3, n4) H Hand2 -> (n1, n2-1, n3, n4)
@@ -163,9 +210,73 @@ randomGuess guess (n1, n2, n3, n4) = (flip evalStateT) ( cardsPerHand + n1
let opts = M.findWithDefault (error "findWithDefault") card g let opts = M.findWithDefault (error "findWithDefault") card g
o <- randomChoice opts o <- randomChoice opts
pure $ M.insert card (S.singleton o) g pure $ M.insert card (S.singleton o) g

choosern :: (Eq a, Monad m, MonadRandom m) => Int -> [a] -> m [a]
choosern 0 _ = pure []
choosern _ [] = error "chooseRn: list is empty and n /= 0"
choosern !n !os = do
o <- chooser os
let !os' = delete o os
rest <- choosern (n-1) os'
pure $ o : rest

choosernS :: (Ord a, Monad m, MonadRandom m) => Int -> Set a -> m (Set a)
choosernS 0 _ = pure S.empty
choosernS !n !os
| S.size os == 0 = error "chooseRn: list is empty and n /= 0"
| otherwise = do
o <- chooserS os
let !os' = S.delete o os
rest <- choosernS (n-1) os'
pure $ S.insert o rest


snd3 :: (a,b,c) -> b
snd3 (a,b,c) = b

randomDistr2 :: (MonadRandom m, Monad m) => Guess -> (Int, Int, Int, Int) -> m Distribution
randomDistr2 guess1 (n1, n2, n3, _) = do
let h1cs = M.keysSet $!! M.filter (H Hand1 `S.member`) guess1
h2cs = M.keysSet $!! M.filter (H Hand2 `S.member`) guess1
h3cs = M.keysSet $!! M.filter (H Hand3 `S.member`) guess1
skcs = M.keysSet $!! M.filter (Skt `S.member`) guess1
priority = M.filter ((==1) . S.size) guess1
predist = M.foldrWithKey
(\card opts dist -> M.insertWith (++) (S.elemAt 0 opts) [card] dist)
M.empty
priority
banned = M.keysSet priority
pots = sortBy (comparing $ \(_, cs, n) -> length cs - n)
$ [ (H Hand1, h1cs, nh1 - length (M.findWithDefault [] (H Hand1) predist))
, (H Hand2, h2cs, nh2 - length (M.findWithDefault [] (H Hand2) predist))
, (H Hand3, h3cs, nh3 - length (M.findWithDefault [] (H Hand3) predist))
, (Skt , skcs, nh4 - length (M.findWithDefault [] Skt predist))
]
(dist, _) <- foldM f (predist, banned) pots

return ( M.findWithDefault (error "randomDistr: missing option Hand1") (H Hand1) dist
, M.findWithDefault (error "randomDistr: missing option Hand2") (H Hand2) dist
, M.findWithDefault (error "randomDistr: missing option Hand3") (H Hand3) dist
, M.findWithDefault (error "randomDistr: missing option Skt") Skt dist
)
where cardsPerHand = (length guess1-2-n1-n2-n3) `div` 3
nh1 = cardsPerHand + n1
nh2 = cardsPerHand + n2
nh3 = cardsPerHand + n3
nh4 = 2
f (dist, banned) (option, cards, n) = do
let available = S.filter (not . (`S.member` banned)) cards
cs <- if S.size available < n
then error ("Not enough options available: wanted " ++ show n ++ " for " ++ show option ++ " and got " ++ show (length available) ++ ", " ++ show guess1 ++ " with " ++ show (n1, n2, n3))
else choosernS n available
let dist' = M.insertWith (++) option (S.toList cs) dist
pure (dist', S.union banned cs)

randomDistr :: (MonadRandom m, Monad m) => Guess -> (Int, Int, Int, Int) -> m Distribution randomDistr :: (MonadRandom m, Monad m) => Guess -> (Int, Int, Int, Int) -> m Distribution
randomDistr guess (n1, n2, n3, n4) = (flip evalStateT) ( cardsPerHand + n1
randomDistr = randomDistr2
randomDistr1 :: (MonadRandom m, Monad m) => Guess -> (Int, Int, Int, Int) -> m Distribution
randomDistr1 guess (n1, n2, n3, n4) = (flip evalStateT) ( cardsPerHand + n1
, cardsPerHand + n2 , cardsPerHand + n2
, cardsPerHand + n3 , cardsPerHand + n3
, 2 + n4 , 2 + n4


+ 43
- 18
src/Skat/AI/MonteCarlo.hs Просмотреть файл

@@ -1,3 +1,4 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE BlockArguments #-} {-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE TypeSynonymInstances #-}
@@ -9,9 +10,11 @@
{-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE ImportQualifiedPost #-} {-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DeriveGeneric #-}


module Skat.AI.MonteCarlo where module Skat.AI.MonteCarlo where


import GHC.Generics
import Control.Monad.State import Control.Monad.State
import Control.Exception (assert) import Control.Exception (assert)
import Control.Monad.Fail import Control.Monad.Fail
@@ -31,6 +34,7 @@ import System.Random (Random)
import qualified System.Random as Rand import qualified System.Random as Rand
import Text.Printf import Text.Printf
import Data.List.Split import Data.List.Split
import Data.Aeson hiding (Value)


import Skat.AI.Base hiding (simulate) import Skat.AI.Base hiding (simulate)
import qualified Skat as S import qualified Skat as S
@@ -48,6 +52,19 @@ type SimCount = Int
data Tree t s = Leaf s Bool (WinCount, SimCount) data Tree t s = Leaf s Bool (WinCount, SimCount)
| Node s Bool (WinCount, SimCount) [Tree t s] | Node s Bool (WinCount, SimCount) [Tree t s]
| Pending s t | Pending s t
deriving (Generic)

instance (ToJSON t, ToJSON s) => ToJSON (Tree t s) where
toJSON x@Leaf{} = object [ "state" .= toJSON (treestate x)
, "valuation" .= toJSON (valuation x)
]
toJSON x@(Node _ _ _ children) = object [ "state" .= toJSON (treestate x)
, "valuation" .= toJSON (valuation x)
, "children" .= toJSON children
]
toJSON x@(Pending _ t) = object [ "valuation" .= ("pending" :: String)
, "turn" .= toJSON t
]


simruns :: Tree t s -> SimCount simruns :: Tree t s -> SimCount
simruns (Leaf _ _ d) = snd d simruns (Leaf _ _ d) = snd d
@@ -106,8 +123,10 @@ valuetonum v
| v == tie = 0.5 | v == tie = 0.5
-} -}


{-
restoint :: (Player p, Value v) => p -> v -> Float restoint :: (Player p, Value v) => p -> v -> Float
restoint p v = tonum $ if maxing p then v else invert v restoint p v = tonum $ if maxing p then v else invert v
-}


{- {-
updateval :: (Player p, Value d) => p -> [d] -> (WinCount, SimCount) -> (WinCount, SimCount) updateval :: (Player p, Value d) => p -> [d] -> (WinCount, SimCount) -> (WinCount, SimCount)
@@ -133,12 +152,13 @@ montecarlo (Pending state turn) = do
let currentTeam = current state let currentTeam = current state
state' = execute turn state state' = execute turn state
-- objectively get a final score of random playout (independent of perspective) -- objectively get a final score of random playout (independent of perspective)
values <- replicateM 100 (simulate state')
let tr = if maxing (current state) then id else invert
values <- replicateM 1000 (simulate state')
let --tr = if maxing (current state) then id else invert
tr = id
vs = fmap (tonum . tr) values vs = fmap (tonum . tr) values
n = sum vs n = sum vs
--let v = if maxing (current state') then value else invert value --let v = if maxing (current state') then value else invert value
let val = (n, 100)
let val = (n, 1000)
pure $ Leaf state' False val pure $ Leaf state' False val
montecarlo (Leaf state terminal d) montecarlo (Leaf state terminal d)
| terminal || length ms == 0 = pure $ Leaf state True d | terminal || length ms == 0 = pure $ Leaf state True d
@@ -152,20 +172,22 @@ montecarlo n@(Node state _ d children)
in pure $ Node state True d' children in pure $ Node state True d' children
| otherwise = do | otherwise = do
let myruns = snd d let myruns = snd d
cmp c = if isterminal c then -1 else selectcoeff myruns $ valuation c
cmp c
| isterminal c = -1
| otherwise = selectcoeff (maxing $ current state) myruns $ valuation c
(idx, bestChild) = (idx, bestChild) =
maximumBy (comparing $ cmp . snd) $ zipWith (,) [0..] children maximumBy (comparing $ cmp . snd) $ zipWith (,) [0..] children
updated <- montecarlo bestChild updated <- montecarlo bestChild
let cs = updateAt idx children updated let cs = updateAt idx children updated
newSimRuns = simruns updated - simruns bestChild + snd d newSimRuns = simruns updated - simruns bestChild + snd d
diff = wins updated - wins bestChild diff = wins updated - wins bestChild
diff2 =
if newSimRuns == snd d then 0
else
if current state == current (treestate updated)
then diff
else fromIntegral (simruns updated) - diff
newWins = diff2 + fst d
--diff2 =
-- if newSimRuns == snd d then 0
-- else
-- if current state == current (treestate updated)
-- then diff
-- else fromIntegral (simruns updated) - diff
newWins = diff + fst d
--return $ trace ("updating node " ++ show diff2 ++ "\n" ++ show updated ++ "\n" ++ show bestChild) (Node state False (newWins, newSimRuns) cs) --return $ trace ("updating node " ++ show diff2 ++ "\n" ++ show updated ++ "\n" ++ show bestChild) (Node state False (newWins, newSimRuns) cs)
return $ Node state False (newWins, newSimRuns) cs return $ Node state False (newWins, newSimRuns) cs


@@ -189,15 +211,17 @@ bestmove (Node s _ _ cs) = treestate $ selection (comparing $ rate . valuation)
mxing = maxing . current $ s mxing = maxing . current $ s
selection = if mxing then maximumBy else minimumBy selection = if mxing then maximumBy else minimumBy
-} -}
bestmove :: Tree t s -> s
bestmove :: (HasGameState t p d s, Player p) => Tree t s -> s
bestmove (Leaf s _ _) = s bestmove (Leaf s _ _) = s
bestmove (Node s _ _ cs) = treestate $ maximumBy (comparing $ rate . valuation) cs
bestmove (Node s _ _ cs) = treestate $ choice (comparing $ rate . valuation) cs
where rate (w, s) = w / fromIntegral s where rate (w, s) = w / fromIntegral s
choice = if maxing (current s) then maximumBy else minimumBy


selectcoeff :: SimCount -> (WinCount, SimCount) -> Float
selectcoeff _ (_, 0) = 10000000
selectcoeff t (w, s) = w / fromIntegral s + explorationParam * sqrt (log (fromIntegral t) / fromIntegral s)
selectcoeff :: Bool -> SimCount -> (WinCount, SimCount) -> Float
selectcoeff _ _ (_, 0) = 10000000
selectcoeff m t (w, s) = w' / fromIntegral s + explorationParam * sqrt (log (fromIntegral t) / fromIntegral s)
where explorationParam = sqrt 2 where explorationParam = sqrt 2
w' = if m then w else fromIntegral s - w


reevaluate :: Tree t s -> (WinCount, SimCount) reevaluate :: Tree t s -> (WinCount, SimCount)
reevaluate tree reevaluate tree
@@ -218,9 +242,10 @@ reevaluateminmax tree
(Node state _ _ children) -> (Node state _ _ children) ->
let vals = fmap ((\(w, s) -> w / fromIntegral s) . valuation) children let vals = fmap ((\(w, s) -> w / fromIntegral s) . valuation) children
-- m = maxing . current $ state -- m = maxing . current $ state
childrenMaxing = all (maxing . current . treestate) children
--childrenMaxing = all (maxing . current . treestate) children
selfMaxing = maxing . current $ state selfMaxing = maxing . current $ state
newval = if childrenMaxing /= selfMaxing then 1 - maximum vals else maximum vals
choice = if selfMaxing then maximum else minimum
newval = choice vals
in (newval, 1) in (newval, 1)


--playCLI :: (MonadFail m, Read t, Choose t m, PlayableGame t l v p m) => m () --playCLI :: (MonadFail m, Read t, Choose t m, PlayableGame t l v p m) => m ()

+ 47
- 8
src/Skat/AI/Skat.hs Просмотреть файл

@@ -1,3 +1,4 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeSynonymInstances #-} {-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleInstances #-}
@@ -5,20 +6,26 @@
{-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TupleSections #-} {-# LANGUAGE TupleSections #-}
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DeriveGeneric #-}


module Skat.AI.Skat where module Skat.AI.Skat where


import Data.String
import System.IO
import GHC.Generics
import Control.Monad.State import Control.Monad.State
import Control.Exception (assert) import Control.Exception (assert)
import Control.Monad.Fail import Control.Monad.Fail
import Control.Monad.Writer import Control.Monad.Writer
import Data.Ord import Data.Ord
import Data.Aeson hiding (Value)
import Text.Read (readMaybe) import Text.Read (readMaybe)
import Data.List (maximumBy, sortBy) import Data.List (maximumBy, sortBy)
import Debug.Trace import Debug.Trace
import Data.Map.Strict (Map) import Data.Map.Strict (Map)
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
import qualified System.Random as Rand import qualified System.Random as Rand
import qualified Data.ByteString.Lazy.Char8 as BS8


import System.IO.Unsafe import System.IO.Unsafe


@@ -61,7 +68,14 @@ data SkatState = SkatState { skatEnv :: S.SkatEnv
, self :: S.Hand , self :: S.Hand
, guess :: Guess , guess :: Guess
} }
deriving Show
deriving (Show, Generic)

instance ToJSON SkatState where
toJSON state = object [ "guess" .= toJSON (guess state)
, "table" .= toJSON (S.tableCards $ S.piles $ skatEnv state)
, "won_single" .= toJSON (S.wonCards S.Single $ S.piles $ skatEnv state)
, "won_team" .= toJSON (S.wonCards S.Team $ S.piles $ skatEnv state)
]


instance Draw SkatState where instance Draw SkatState where
draw = show . S.tableCards . S.piles . skatEnv draw = show . S.tableCards . S.piles . skatEnv
@@ -129,6 +143,9 @@ data Turn = Turn { turnStartingEnv :: S.SkatEnv
, turnCard :: S.Card } , turnCard :: S.Card }
deriving Show deriving Show


instance ToJSON Turn where
toJSON turn = object [ "turn_card" .= turnCard turn ]

instance Draw Turn where instance Draw Turn where
draw = show . turnCard draw = show . turnCard


@@ -140,9 +157,17 @@ instance HasGameState Turn Bool Float SkatState where
monteevaluate s = let (sgl, tm) = ev S.countGame (skatEnv s) monteevaluate s = let (sgl, tm) = ev S.countGame (skatEnv s)
in if sgl > tm then 1.0 else 0.0 --fromIntegral sgl / (fromIntegral $ sgl + tm) in if sgl > tm then 1.0 else 0.0 --fromIntegral sgl / (fromIntegral $ sgl + tm)
execute turn state = execute turn state =
let newEnv = ex (S.play_ card) env
let tbl = ev (S.getp S.tableCards) env
curhand = S.currentHand env
trpCol :: S.Trump
trpCol = ev (S.getTrump <$> gets S.skatGame) env
turnCol = ev (gets S.turnColour) env
observed = observe trpCol turnCol (card':tbl) (guess state)
guess' = card `hasBeenPlayed` observed
card' = S.CardS card (S.P curhand)
newEnv = ex (S.play_ card) env
in state { skatEnv = newEnv in state { skatEnv = newEnv
, guess = card `hasBeenPlayed` (guess state)
, guess = guess'
} }
where env = turnStartingEnv turn where env = turnStartingEnv turn
card = turnCard turn card = turnCard turn
@@ -202,10 +227,20 @@ playCLI n = do
liftIO $ putStrLn "iterating" liftIO $ putStrLn "iterating"
s <- get s <- get
let tree = Leaf s False (0, 0) let tree = Leaf s False (0, 0)
t = runmonte n (foldM (\tree _ -> montecarlo tree) tree [1..100])
l = length $ guess s
depth
| l >= 26 = 15
| l >= 20 = 100
| l >= 14 = 2000
| otherwise = 5000
t = runmonte n (foldM (\tree _ -> montecarlo tree) tree [1..depth])
newstate = bestmove t newstate = bestmove t
--liftIO $ putStrLn $ visualise t
json :: String
json = BS8.unpack $ encode t
liftIO $ print newstate liftIO $ print newstate
--liftIO $ withFile "tree.json" WriteMode $ \handle ->
-- hPutStrLn handle json
--liftIO $ putStrLn $ visualise t
put newstate put newstate
lift (put $ skatEnv newstate) lift (put $ skatEnv newstate)
else do else do
@@ -215,7 +250,11 @@ playCLI n = do
lift $ play t lift $ play t
s <- get s <- get
env <- lift get env <- lift get
let s' = s { skatEnv = env }
let guess' = (S.toCard t) `hasBeenPlayed` (guess s)
observed <- lift $ observeS guess'
let s' = s { skatEnv = env
, guess = observed
}
put s' put s'
{- {-
showBoard showBoard
@@ -245,13 +284,13 @@ initSkatEnv n =
let gen = Rand.mkStdGen n let gen = Rand.mkStdGen n
--cards = S.shuffle gen S.allCards --cards = S.shuffle gen S.allCards
--piles = S.distribute cards --piles = S.distribute cards
piles = S.cardDistr3
piles = S.cardDistr9
players = P.Players players = P.Players
(P.PL $ S.Stupid S.Single S.Hand1) (P.PL $ S.Stupid S.Single S.Hand1)
(P.PL $ S.Stupid S.Team S.Hand2) (P.PL $ S.Stupid S.Team S.Hand2)
(P.PL $ S.Stupid S.Team S.Hand3) (P.PL $ S.Stupid S.Team S.Hand3)
in S.SkatEnv { S.piles = piles in S.SkatEnv { S.piles = piles
, S.turnColour = Nothing
, S.turnColour = Just (S.TurnColour S.Hearts)
, S.skatGame = S.Colour S.Spades S.Einfach , S.skatGame = S.Colour S.Spades S.Einfach
, S.players = players , S.players = players
, S.currentHand = S.Hand1 , S.currentHand = S.Hand1


+ 1
- 0
src/Skat/Bidding.hs Просмотреть файл

@@ -153,6 +153,7 @@ modifierFactor Ouvert = 7
allTrumps :: Game -> [Card] allTrumps :: Game -> [Card]
allTrumps (Grand _) = jacks allTrumps (Grand _) = jacks
allTrumps (Colour col _) = jacks ++ [Card t col | t <- [Ace,Ten .. Seven] ] allTrumps (Colour col _) = jacks ++ [Card t col | t <- [Ace,Ten .. Seven] ]
allTrumps _ = []


jacks :: [Card] jacks :: [Card]
jacks = [ Card Jack Clubs, Card Jack Spades, Card Jack Hearts, Card Jack Diamonds ] jacks = [ Card Jack Clubs, Card Jack Spades, Card Jack Hearts, Card Jack Diamonds ]


+ 3
- 3
src/Skat/Card.hs Просмотреть файл

@@ -33,7 +33,7 @@ data Type = Seven
| Ten | Ten
| Ace | Ace
| Jack | Jack
deriving (Eq, Ord, Show, Enum, Read, Bounded, Generic, NFData)
deriving (Eq, Ord, Show, Enum, Read, Bounded, Generic, NFData, ToJSON)


data NullType = NSeven data NullType = NSeven
| NEight | NEight
@@ -57,7 +57,7 @@ data Colour = Diamonds
| Hearts | Hearts
| Spades | Spades
| Clubs | Clubs
deriving (Eq, Ord, Show, Enum, Read, Bounded, Generic, NFData)
deriving (Eq, Ord, Show, Enum, Read, Bounded, Generic, NFData, ToJSON)


data Trump = TrumpColour Colour data Trump = TrumpColour Colour
| Jacks | Jacks
@@ -69,7 +69,7 @@ data TurnColour = TurnColour Colour
deriving (Show, Eq) deriving (Show, Eq)


data Card = Card !Type !Colour data Card = Card !Type !Colour
deriving (Eq, Show, Ord, Read, Bounded, Generic)
deriving (Eq, Show, Ord, Read, Bounded, Generic, ToJSONKey)


getType :: Card -> Type getType :: Card -> Type
getType (Card t _) = t getType (Card t _) = t


+ 31
- 3
src/Skat/Pile.hs Просмотреть файл

@@ -53,7 +53,7 @@ instance ToJSON p => ToJSON (CardS p) where
object ["card" .= card, "pile" .= pile] object ["card" .= card, "pile" .= pile]


data Hand = Hand1 | Hand2 | Hand3 data Hand = Hand1 | Hand2 | Hand3
deriving (Show, Eq, Ord, Read, Enum, Bounded, Generic, NFData)
deriving (Show, Eq, Ord, Read, Enum, Bounded, Generic, NFData, ToJSON)


toInt :: Hand -> Int toInt :: Hand -> Int
toInt Hand1 = 1 toInt Hand1 = 1
@@ -249,10 +249,10 @@ instance Serialize String [Trick] where


cardDistr :: Piles cardDistr :: Piles
cardDistr = emptyPiles hand1 hand2 hand3 skt cardDistr = emptyPiles hand1 hand2 hand3 skt
where hand3 = [Card Ace Spades, Card Jack Diamonds, Card Jack Clubs, Card King Spades,
where hand1 = [Card Ace Spades, Card Jack Diamonds, Card Jack Clubs, Card King Spades,
Card Nine Spades, Card Ace Diamonds, Card Queen Diamonds, Card Ten Clubs, Card Nine Spades, Card Ace Diamonds, Card Queen Diamonds, Card Ten Clubs,
Card Eight Clubs, Card King Clubs] Card Eight Clubs, Card King Clubs]
hand1 = [Card Jack Spades, Card Jack Hearts, Card Ten Spades, Card Ace Hearts, Card Ten Hearts,
hand3 = [Card Jack Spades, Card Jack Hearts, Card Ten Spades, Card Ace Hearts, Card Ten Hearts,
Card Nine Hearts, Card Seven Clubs, Card Ace Clubs, Card King Diamonds, Card Nine Hearts, Card Seven Clubs, Card Ace Clubs, Card King Diamonds,
Card Ten Diamonds] Card Ten Diamonds]
hand2 = [Card Eight Spades, Card Queen Spades, Card Seven Spades, Card Seven Diamonds, hand2 = [Card Eight Spades, Card Queen Spades, Card Seven Spades, Card Seven Diamonds,
@@ -302,3 +302,31 @@ cardDistr6 = emptyPiles hand1 hand2 hand3 skt
Card Seven Hearts, Card Eight Hearts, Card Queen Hearts Card Seven Hearts, Card Eight Hearts, Card Queen Hearts
] ]
skt = [Card Nine Clubs, Card Queen Clubs] skt = [Card Nine Clubs, Card Queen Clubs]

cardDistr7 :: Piles
cardDistr7 = emptyPiles hand1 hand2 hand3 skt
where hand3 = [Card Eight Spades, Card Ace Clubs]
hand1 = [Card Seven Spades, Card Nine Spades]
hand2 = [Card Ace Hearts, Card Ten Clubs]
skt = [Card Nine Clubs, Card Seven Clubs]

cardDistr8 :: Piles
cardDistr8 = emptyPiles hand1 hand2 hand3 skt
where hand3 = [Card Ace Spades, Card Ace Clubs]
hand1 = [Card Jack Spades, Card Seven Spades]
hand2 = [Card Eight Hearts, Card King Clubs]
skt = [Card Nine Clubs, Card Seven Clubs]

cardDistr9 :: Piles
cardDistr9 = makePiles hand1 hand2 hand3 tbl skt
where hand1 = [Card Ace Spades, Card Jack Diamonds, Card Jack Clubs, Card King Spades,
Card Nine Spades, Card Ace Diamonds, Card Queen Diamonds, Card Ten Clubs,
Card Eight Clubs]
hand3 = [Card Jack Spades, Card Jack Hearts, Card Ten Spades, Card Ten Hearts,
Card Nine Hearts, Card Seven Clubs, Card King Diamonds,
Card Ten Diamonds]
hand2 = [Card Eight Spades, Card Seven Spades, Card Seven Diamonds,
Card Seven Hearts, Card Eight Hearts, Card Queen Hearts,
Card Nine Diamonds, Card Eight Diamonds]
skt = [Card Nine Clubs, Card Queen Clubs]
tbl = [CardS (Card Ace Hearts) (P Hand3), CardS (Card King Hearts) (P Hand2)]

Загрузка…
Отмена
Сохранить