4 changed files with 79 additions and 38 deletions
+59 -34
View File
@@ -4,12 +4,13 @@
{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleContexts #-}
module AI.Rulebased ( module AI.Rulebased (
mkAIEnv mkAIEnv, testds, simplify
) where ) where
import Data.Ord import Data.Ord
import Data.Monoid ((<>)) import Data.Monoid ((<>))
import Data.List import Data.List
import qualified Data.Set as S
import Control.Monad.State import Control.Monad.State
import Control.Monad.Reader import Control.Monad.Reader
import qualified Data.Map.Strict as M import qualified Data.Map.Strict as M
@@ -152,9 +153,16 @@ toPiles table (h1, h2, h3, skt) = Piles (cs1 ++ cs2 ++ cs3) table ss
cs3 = map (putAt Hand3) h3 cs3 = map (putAt Hand3) h3
ss = map (putAt SkatP) skt ss = map (putAt SkatP) skt
compareGuess :: (Card, [Option]) -> (Card, [Option]) -> Ordering
compareGuess (c1, ops1) (c2, ops2)
| length ops1 == 1 = LT
| length ops2 == 1 = GT
| c1 > c2 = LT
| c1 < c2 = GT
distributions :: Guess -> (Int, Int, Int, Int) -> [Distribution] distributions :: Guess -> (Int, Int, Int, Int) -> [Distribution]
distributions guess nos = distributions guess nos =
helper (sortBy (comparing $ length . snd) $ M.toList guess) nos helper (sortBy compareGuess $ M.toList guess) nos
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 =
@@ -177,30 +185,33 @@ distributions guess nos =
in filterMap isOk (f card) hands in filterMap isOk (f card) hands
cardsPerHand = (length guess - 2) `div` 3 cardsPerHand = (length guess - 2) `div` 3
simplify :: Int -> [Distribution] -> [Distribution] type Abstract = (Int, Int, Int, Int)
simplify 10 ds = nubBy is789Variation ds
simplify _ ds = ds
is789Variation :: Distribution -> Distribution -> Bool abstract :: [Card] -> Abstract
is789Variation (ha1, ha2, ha3, sa) (hb1, hb2, hb3, sb) = abstract cs = foldr f (0, 0, 0, 0) cs
f ha1 hb1 && f ha2 hb2 && f ha3 hb3 && f sa sb where f c (clubs, spades, hearts, diamonds) =
where f cs1 cs2 let v = getID c in
| n789s cs1 /= n789s cs2 = False case getColour c of
| otherwise = and (zipCs (c789s cs1) (c789s cs2)) Diamonds -> (clubs, spades, hearts, diamonds + 1 + v*100)
Hearts -> (clubs, spades, hearts + 1 + v*100, diamonds)
Spades -> (clubs, spades + 1 + v*100, hearts, diamonds)
Clubs -> (clubs + 1 + v*100, spades, hearts, diamonds)
zipCs :: [[Card]] -> [[Card]] -> [Bool] remove789s :: Hand
zipCs xs ys = zipWith g xs ys -> [Distribution]
-> M.Map (Abstract, Abstract) (Distribution, Int)
remove789s hand ds = foldl' f M.empty ds
where f cleaned d =
let (c1, c2) = reduce hand d
a = (abstract c1, abstract c2) in
M.insertWith (\(oldD, n) _ -> (oldD, n+1)) a (d, 1) cleaned
reduce Hand1 (_, h2, h3, _) = (h2, h3)
reduce Hand2 (h1, _, h3, _) = (h1, h3)
reduce Hand3 (h1, h2, _, _) = (h1, h2)
c789s :: [Card] -> [[Card]] simplify :: Hand -> [Distribution] -> [(Distribution, Int)]
c789s cs = groupBy (grouping getColour) $ simplify hand ds = M.elems cleaned
sortBy (comparing getColour) $ where cleaned = remove789s hand ds
filter ((==(0 :: Int)) . count) cs
n789s :: [Card] -> [Card]
n789s cs = filter ((/=(0 :: Int)) . count) cs
g :: [a] -> [b] -> Bool
g xs ys = length xs == length ys
onPlayed :: MonadPlayer m => CardS Played -> AI m () onPlayed :: MonadPlayer m => CardS Played -> AI m ()
onPlayed c = do onPlayed c = do
@@ -255,13 +266,16 @@ chooseStatistic = do
0 -> (0, 0, 0, 0) 0 -> (0, 0, 0, 0)
1 -> (-1, 0, -1, 0) 1 -> (-1, 0, -1, 0)
2 -> (0, 0, -1, 0) 2 -> (0, 0, -1, 0)
let dis = distributions guess ns let realDis = distributions guess ns
disNo = length dis realDisNo = length realDis
piless = map (toPiles table) dis reducedDis = simplify Hand3 realDis
reducedDisNo = length reducedDis
piless = map (\(d, n) -> (toPiles table d, n)) reducedDis
limit = if depth == 1 && length table == 2 limit = if depth == 1 && length table == 2
then 1 then 1
else min 10000 $ disNo `div` 2 else min 10000 $ realDisNo `div` 2
liftIO $ putStrLn $ "possible distrs " ++ show disNo liftIO $ putStrLn $ "possible distrs without simp " ++ show realDisNo
liftIO $ putStrLn $ "possible distrs " ++ show reducedDisNo
vals <- M.toList <$> foldWithLimit limit runOnPiles M.empty piless vals <- M.toList <$> foldWithLimit limit runOnPiles M.empty piless
liftIO $ print vals liftIO $ print vals
return $ fst $ maximumBy (comparing snd) vals return $ fst $ maximumBy (comparing snd) vals
@@ -280,10 +294,10 @@ foldWithLimit limit f start (x:xs) = do
_ -> return start _ -> return start
runOnPiles :: MonadPlayer m runOnPiles :: MonadPlayer m
=> M.Map Card Int -> Piles -> AI m (M.Map Card Int) => M.Map Card Int -> (Piles, Int) -> AI m (M.Map Card Int)
runOnPiles m ps = do runOnPiles m (ps, n) = do
c <- runWithPiles ps chooseOpen c <- runWithPiles ps chooseOpen
return $ M.insertWith (+) c 1 m return $ M.insertWith (+) c n m
chooseOpen :: (MonadState AIEnv m, MonadPlayerOpen m) => m Card chooseOpen :: (MonadState AIEnv m, MonadPlayerOpen m) => m Card
chooseOpen = do chooseOpen = do
@@ -396,10 +410,21 @@ aienv :: AIEnv
aienv = AIEnv Single Hand3 [] [] [] newGuess 10 aienv = AIEnv Single Hand3 [] [] [] newGuess 10
testguess :: Guess testguess :: Guess
testguess = isSkat (take 2 $ drop 10 allCards) testguess = isSkat (take 2 $ drop 10 cs)
$ Hand3 `has` (take 10 allCards) $ m $ Hand3 `has` (take 10 cs) $ m
where l = map (\c -> (c, [H Hand1, H Hand2, H Hand3, Skt])) (take 32 allCards) where l = map (\c -> (c, [H Hand1, H Hand2, H Hand3, Skt])) (take 32 cs)
m = M.fromList l m = M.fromList l
cs = allCards
testguess2 :: Guess
testguess2 = isSkat (take 2 $ drop 6 cs)
$ Hand3 `has` [head cs, head $ drop 5 cs] $ m
where l = map (\c -> (c, [H Hand1, H Hand2, H Hand3, Skt])) cs
m = M.fromList l
cs = take 8 $ drop 8 allCards
testds :: [Distribution] testds :: [Distribution]
testds = distributions testguess (0, 0, 0, 0) testds = distributions testguess (0, 0, 0, 0)
testds2 :: [Distribution]
testds2 = distributions testguess2 (0, 0, 0, 0)
+5
View File
@@ -0,0 +1,5 @@
import AI.Rulebased
import Pile
main :: IO ()
main = print $ length $ simplify Hand3 testds
+11
View File
@@ -40,6 +40,17 @@ data Card = Card Type Colour
getColour :: Card -> Colour getColour :: Card -> Colour
getColour (Card _ c) = c getColour (Card _ c) = c
getID :: Card -> Int
getID (Card t _) = case t of
Seven -> 0
Eight -> 0
Nine -> 0
Queen -> 2
King -> 4
Ten -> 8
Ace -> 16
Jack -> 32
instance Countable Card Int where instance Countable Card Int where
count (Card t _) = count t count (Card t _) = count t
+4 -4
View File
@@ -14,7 +14,7 @@ data Team = Team | Single
data CardS p = CardS { getCard :: Card data CardS p = CardS { getCard :: Card
, getPile :: p } , getPile :: p }
deriving (Show, Eq) deriving (Show, Eq, Ord)
instance Countable (CardS p) Int where instance Countable (CardS p) Int where
count = count . getCard count = count . getCard
@@ -34,15 +34,15 @@ prev Hand3 = Hand2
data Played = Table Hand data Played = Table Hand
| Won Hand Team | Won Hand Team
deriving (Show, Eq) deriving (Show, Eq, Ord)
data SkatP = SkatP data SkatP = SkatP
deriving (Show, Eq) deriving (Show, Eq, Ord)
data Piles = Piles { hands :: [CardS Hand] data Piles = Piles { hands :: [CardS Hand]
, played :: [CardS Played] , played :: [CardS Played]
, skat :: [CardS SkatP] } , skat :: [CardS SkatP] }
deriving (Show, Eq) deriving (Show, Eq, Ord)
instance Countable Piles (Int, Int) where instance Countable Piles (Int, Int) where
count ps = (sgl, tm) count ps = (sgl, tm)