some optimizations
This commit is contained in:
+12
-15
@@ -19,7 +19,12 @@ import Skat.AI.Rulebased
|
|||||||
import Skat.AI.Minmax (playCLI)
|
import Skat.AI.Minmax (playCLI)
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = testAI 10
|
main = testMinmax 10
|
||||||
|
|
||||||
|
testMinmax :: Int -> IO ()
|
||||||
|
testMinmax n = do
|
||||||
|
let acs = repeat playSkat
|
||||||
|
sequence_ (take n acs)
|
||||||
|
|
||||||
testAI :: Int -> IO ()
|
testAI :: Int -> IO ()
|
||||||
testAI n = do
|
testAI n = do
|
||||||
@@ -71,14 +76,11 @@ shuffledEnv2 = do
|
|||||||
return $ SkatEnv (distribute cards) Nothing Spades pls2 Hand1
|
return $ SkatEnv (distribute cards) Nothing Spades pls2 Hand1
|
||||||
|
|
||||||
env2 :: SkatEnv
|
env2 :: SkatEnv
|
||||||
env2 = SkatEnv piles Nothing Spades playersExamp Hand1
|
env2 = SkatEnv piles Nothing Hearts playersExamp Hand2
|
||||||
where hand1 = [Card Seven Clubs, Card King Clubs, Card Ace Clubs, Card Queen Diamonds]
|
where hand1 = [Card Eight Hearts, Card Queen Hearts, Card Ace Clubs, Card Queen Diamonds]
|
||||||
hand2 = [Card Seven Hearts, Card King Hearts, Card Ace Hearts, Card Queen Spades]
|
hand2 = [Card Seven Hearts, Card King Hearts, Card Ten Hearts, Card Queen Spades]
|
||||||
hand3 = [Card Seven Spades, Card King Spades, Card Ace Spades, Card Queen Clubs]
|
hand3 = [Card Seven Spades, Card King Spades, Card Ace Spades, Card Queen Clubs]
|
||||||
h1 = map (putAt Hand1) hand1
|
piles = emptyPiles hand1 hand2 hand3 []
|
||||||
h2 = map (putAt Hand2) hand2
|
|
||||||
h3 = map (putAt Hand3) hand3
|
|
||||||
piles = Piles (h1 ++ h2 ++ h3) [] []
|
|
||||||
|
|
||||||
env3 :: SkatEnv
|
env3 :: SkatEnv
|
||||||
env3 = SkatEnv piles Nothing Diamonds pls2 Hand3
|
env3 = SkatEnv piles Nothing Diamonds pls2 Hand3
|
||||||
@@ -91,11 +93,7 @@ env3 = SkatEnv piles Nothing Diamonds pls2 Hand3
|
|||||||
hand3 = [ Card Jack Hearts, Card Jack Spades, Card Ten Spades, Card Ace Spades, Card Eight Diamonds
|
hand3 = [ Card Jack Hearts, Card Jack Spades, Card Ten Spades, Card Ace Spades, Card Eight Diamonds
|
||||||
, Card Queen Diamonds, Card Ten Diamonds, Card Ten Hearts, Card Queen Hearts, Card King Hearts ]
|
, Card Queen Diamonds, Card Ten Diamonds, Card Ten Hearts, Card Queen Hearts, Card King Hearts ]
|
||||||
skat = [ Card Queen Clubs, Card Queen Spades]
|
skat = [ Card Queen Clubs, Card Queen Spades]
|
||||||
h1 = map (putAt Hand1) hand1
|
piles = emptyPiles hand1 hand2 hand3 skat
|
||||||
h2 = map (putAt Hand2) hand2
|
|
||||||
h3 = map (putAt Hand3) hand3
|
|
||||||
skt = map (putAt SkatP) skat
|
|
||||||
piles = Piles (h1 ++ h2 ++ h3) [] skt
|
|
||||||
|
|
||||||
runWebSocketServer :: IO ()
|
runWebSocketServer :: IO ()
|
||||||
runWebSocketServer = do
|
runWebSocketServer = do
|
||||||
@@ -110,5 +108,4 @@ application pending = do
|
|||||||
putStrLn $ BS.unpack msg
|
putStrLn $ BS.unpack msg
|
||||||
|
|
||||||
playSkat :: IO ()
|
playSkat :: IO ()
|
||||||
playSkat = do
|
playSkat = void $ (flip runStateT) env3 playCLI
|
||||||
void $ (flip runStateT) env3 playCLI
|
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
module TestEnvs where
|
||||||
|
|
||||||
|
import Skat
|
||||||
|
import Skat.Card
|
||||||
|
import Skat.Pile
|
||||||
|
import Skat.Player
|
||||||
|
import Skat.AI.Stupid
|
||||||
|
|
||||||
|
pls2 :: Players
|
||||||
|
pls2 = Players
|
||||||
|
(PL $ Stupid Team Hand1)
|
||||||
|
(PL $ Stupid Team Hand2)
|
||||||
|
(PL $ Stupid Single Hand3)
|
||||||
|
|
||||||
|
env3 :: SkatEnv
|
||||||
|
env3 = SkatEnv piles Nothing Diamonds pls2 Hand3
|
||||||
|
where hand1 = [ Card Jack Diamonds, Card Jack Clubs, Card Nine Spades, Card King Spades
|
||||||
|
, Card Seven Diamonds, Card Nine Diamonds, Card Seven Clubs, Card Eight Clubs
|
||||||
|
, Card Ten Clubs, Card Eight Hearts ]
|
||||||
|
hand2 = [ Card Seven Spades, Card Eight Spades, Card Seven Hearts, Card Nine Hearts
|
||||||
|
, Card Ace Hearts, Card King Diamonds, Card Ace Diamonds, Card Nine Clubs
|
||||||
|
, Card King Clubs, Card Ace Clubs ]
|
||||||
|
hand3 = [ Card Jack Hearts, Card Jack Spades, Card Ten Spades, Card Ace Spades, Card Eight Diamonds
|
||||||
|
, Card Queen Diamonds, Card Ten Diamonds, Card Ten Hearts, Card Queen Hearts, Card King Hearts ]
|
||||||
|
skat = [ Card Queen Clubs, Card Queen Spades]
|
||||||
|
piles = emptyPiles hand1 hand2 hand3 skat
|
||||||
|
|
||||||
|
shuffledEnv2 :: IO SkatEnv
|
||||||
|
shuffledEnv2 = do
|
||||||
|
cards <- shuffleCards
|
||||||
|
return $ SkatEnv (distribute cards) Nothing Spades pls2 Hand1
|
||||||
@@ -33,6 +33,7 @@ dependencies:
|
|||||||
- parallel
|
- parallel
|
||||||
- containers
|
- containers
|
||||||
- case-insensitive
|
- case-insensitive
|
||||||
|
- vector
|
||||||
|
|
||||||
library:
|
library:
|
||||||
source-dirs: src
|
source-dirs: src
|
||||||
@@ -45,6 +46,7 @@ executables:
|
|||||||
- -threaded
|
- -threaded
|
||||||
- -rtsopts
|
- -rtsopts
|
||||||
- -with-rtsopts=-N
|
- -with-rtsopts=-N
|
||||||
|
- -O2
|
||||||
dependencies:
|
dependencies:
|
||||||
- skat
|
- skat
|
||||||
|
|
||||||
@@ -56,5 +58,6 @@ tests:
|
|||||||
- -threaded
|
- -threaded
|
||||||
- -rtsopts
|
- -rtsopts
|
||||||
- -with-rtsopts=-N
|
- -with-rtsopts=-N
|
||||||
|
- -O2
|
||||||
dependencies:
|
dependencies:
|
||||||
- skat
|
- skat
|
||||||
|
|||||||
+7
-3
@@ -4,7 +4,7 @@ cabal-version: 1.12
|
|||||||
--
|
--
|
||||||
-- see: https://github.com/sol/hpack
|
-- see: https://github.com/sol/hpack
|
||||||
--
|
--
|
||||||
-- hash: 589f4321e3ce9847f3a53afb14e0fa9eaa1b98b3fc7386eac20f8fae7f7b6bf7
|
-- hash: 3f130a9bf454b63893b6f1958214229a75ad6916b19eb7bb6797a19f0f14dd3e
|
||||||
|
|
||||||
name: skat
|
name: skat
|
||||||
version: 0.1.0.1
|
version: 0.1.0.1
|
||||||
@@ -60,16 +60,18 @@ library
|
|||||||
, random
|
, random
|
||||||
, split
|
, split
|
||||||
, text
|
, text
|
||||||
|
, vector
|
||||||
, websockets
|
, websockets
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
executable skat-exe
|
executable skat-exe
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
other-modules:
|
other-modules:
|
||||||
|
TestEnvs
|
||||||
Paths_skat
|
Paths_skat
|
||||||
hs-source-dirs:
|
hs-source-dirs:
|
||||||
app
|
app
|
||||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N -O2
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson
|
aeson
|
||||||
, base >=4.7 && <5
|
, base >=4.7 && <5
|
||||||
@@ -84,6 +86,7 @@ executable skat-exe
|
|||||||
, skat
|
, skat
|
||||||
, split
|
, split
|
||||||
, text
|
, text
|
||||||
|
, vector
|
||||||
, websockets
|
, websockets
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|
||||||
@@ -94,7 +97,7 @@ test-suite skat-test
|
|||||||
Paths_skat
|
Paths_skat
|
||||||
hs-source-dirs:
|
hs-source-dirs:
|
||||||
test
|
test
|
||||||
ghc-options: -threaded -rtsopts -with-rtsopts=-N
|
ghc-options: -threaded -rtsopts -with-rtsopts=-N -O2
|
||||||
build-depends:
|
build-depends:
|
||||||
aeson
|
aeson
|
||||||
, base >=4.7 && <5
|
, base >=4.7 && <5
|
||||||
@@ -109,5 +112,6 @@ test-suite skat-test
|
|||||||
, skat
|
, skat
|
||||||
, split
|
, split
|
||||||
, text
|
, text
|
||||||
|
, vector
|
||||||
, websockets
|
, websockets
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
|||||||
+3
-5
@@ -7,6 +7,7 @@ module Skat where
|
|||||||
import Control.Monad.State
|
import Control.Monad.State
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.List
|
import Data.List
|
||||||
|
import Data.Vector (Vector)
|
||||||
|
|
||||||
import Skat.Card
|
import Skat.Card
|
||||||
import Skat.Pile
|
import Skat.Pile
|
||||||
@@ -52,13 +53,10 @@ setCurrentHand hand sk = sk { currentHand = hand }
|
|||||||
mkSkatEnv :: Piles -> Maybe Colour -> Colour -> Players -> Hand -> SkatEnv
|
mkSkatEnv :: Piles -> Maybe Colour -> Colour -> Players -> Hand -> SkatEnv
|
||||||
mkSkatEnv = SkatEnv
|
mkSkatEnv = SkatEnv
|
||||||
|
|
||||||
allowedCards :: Skat [Card]
|
allowedCards :: Skat [CardS Owner]
|
||||||
allowedCards = do
|
allowedCards = do
|
||||||
curHand <- gets currentHand
|
curHand <- gets currentHand
|
||||||
pls <- gets players
|
pls <- gets players
|
||||||
turnCol <- gets turnColour
|
turnCol <- gets turnColour
|
||||||
trumpCol <- gets trumpColour
|
trumpCol <- gets trumpColour
|
||||||
ps <- gets piles
|
getp $ allowed curHand trumpCol turnCol
|
||||||
let p = P.player pls curHand
|
|
||||||
cards = handCards curHand ps
|
|
||||||
return $ filter (isAllowed trumpCol turnCol cards) cards
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ instance Player Human where
|
|||||||
trumpCol <- trumpColour
|
trumpCol <- trumpColour
|
||||||
turnCol <- turnColour
|
turnCol <- turnColour
|
||||||
let possible = filter (isAllowed trumpCol turnCol hand) hand
|
let possible = filter (isAllowed trumpCol turnCol hand) hand
|
||||||
c <- liftIO $ askIO (map getCard table) possible hand
|
c <- liftIO $ askIO (map getCard table) (map toCard possible) (map toCard hand)
|
||||||
return $ (c, p)
|
return $ (c, p)
|
||||||
|
|
||||||
askIO :: [Card] -> [Card] -> [Card] -> IO Card
|
askIO :: [Card] -> [Card] -> [Card] -> IO Card
|
||||||
|
|||||||
+61
-41
@@ -10,18 +10,20 @@ module Skat.AI.Minmax (
|
|||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.State
|
import Control.Monad.State
|
||||||
|
import Control.Exception (assert)
|
||||||
import Control.Monad.Fail
|
import Control.Monad.Fail
|
||||||
import Data.Ord
|
import Data.Ord
|
||||||
import Text.Read (readMaybe)
|
import Text.Read (readMaybe)
|
||||||
import Data.List (minimumBy, maximumBy)
|
import Data.List (maximumBy, sortBy)
|
||||||
import Debug.Trace
|
import Debug.Trace
|
||||||
|
|
||||||
import qualified Skat as S
|
import qualified Skat as S
|
||||||
import qualified Skat.Card as S
|
import qualified Skat.Card as S
|
||||||
import qualified Skat.Operations as S
|
import qualified Skat.Operations as S
|
||||||
import qualified Skat.Pile as S
|
import qualified Skat.Pile as S
|
||||||
import qualified Skat.Player as S
|
import qualified Skat.Player as S hiding (trumpColour, turnColour)
|
||||||
import qualified Skat.Render as S
|
import qualified Skat.Render as S
|
||||||
|
--import TestEnvs (env3, shuffledEnv2)
|
||||||
|
|
||||||
debug :: Bool
|
debug :: Bool
|
||||||
debug = False
|
debug = False
|
||||||
@@ -34,15 +36,15 @@ class (Ord v, Eq v) => Value v where
|
|||||||
class Player p where
|
class Player p where
|
||||||
maxing :: p -> Bool
|
maxing :: p -> Bool
|
||||||
|
|
||||||
class (Monad m, Value v, Player p, Eq t) => MonadGame t v p m | m -> t, m -> p, m -> v where
|
class (Traversable l, Monad m, Value v, Player p, Eq t) => MonadGame t l v p m | m -> t, m -> p, m -> v, m -> l where
|
||||||
currentPlayer :: m p
|
currentPlayer :: m p
|
||||||
turns :: m [t]
|
turns :: m (l t)
|
||||||
play :: t -> m ()
|
play :: t -> m ()
|
||||||
simulate :: t -> m a -> m a
|
simulate :: t -> m a -> m a
|
||||||
evaluate :: m v
|
evaluate :: m v
|
||||||
over :: m Bool
|
over :: m Bool
|
||||||
|
|
||||||
class (MonadIO m, Show t, Show v, Show p, MonadGame t v p m) => PlayableGame t v p m | m -> t, m -> p, m -> v where
|
class (MonadIO m, Show t, Show v, Show p, MonadGame t l v p m) => PlayableGame t l v p m | m -> t, m -> p, m -> v where
|
||||||
showTurns :: m ()
|
showTurns :: m ()
|
||||||
showBoard :: m ()
|
showBoard :: m ()
|
||||||
askTurn :: m (Maybe t)
|
askTurn :: m (Maybe t)
|
||||||
@@ -59,25 +61,50 @@ instance Value Int where
|
|||||||
win = 120
|
win = 120
|
||||||
loss = -120
|
loss = -120
|
||||||
|
|
||||||
instance MonadGame S.Card Int S.PL S.Skat where
|
instance MonadGame (S.CardS S.Owner) [] Int S.PL S.Skat where
|
||||||
currentPlayer = do
|
currentPlayer = do
|
||||||
hand <- gets S.currentHand
|
hand <- gets S.currentHand
|
||||||
pls <- gets S.players
|
pls <- gets S.players
|
||||||
return $ S.player pls hand
|
return $! S.player pls hand
|
||||||
turns = S.allowedCards
|
turns = S.allowedCards
|
||||||
|
--player <- currentPlayer
|
||||||
|
--trCol <- gets S.trumpColour
|
||||||
|
--return $! if maxing player
|
||||||
|
-- then sortBy (optimalTeam trCol) cards
|
||||||
|
-- else sortBy (optimalSingle trCol) cards
|
||||||
play = S.play_
|
play = S.play_
|
||||||
simulate card action = do
|
simulate card action = do
|
||||||
|
--oldCurrent <- gets S.currentHand
|
||||||
|
--oldTurnCol <- gets S.turnColour
|
||||||
backup <- get
|
backup <- get
|
||||||
play card
|
play card
|
||||||
|
--oldWinner <- currentPlayer
|
||||||
res <- action
|
res <- action
|
||||||
|
--S.undo_ card oldCurrent oldTurnCol (S.team oldWinner)
|
||||||
put backup
|
put backup
|
||||||
return res
|
return $! res
|
||||||
over = ((==0) . length) <$> S.allowedCards
|
over = ((==0) . length) <$!> S.allowedCards
|
||||||
evaluate = do
|
evaluate = do
|
||||||
player <- currentPlayer
|
player <- currentPlayer
|
||||||
piles <- gets S.piles
|
piles <- gets S.piles
|
||||||
let (sgl, tm) = S.count piles
|
let (sgl, tm) = S.count piles
|
||||||
return $ (if maxing player then tm - sgl else sgl - tm)
|
return $! (if maxing player then tm - sgl else sgl - tm)
|
||||||
|
|
||||||
|
potentialByType :: S.Type -> Int
|
||||||
|
potentialByType S.Ace = 11
|
||||||
|
potentialByType S.Jack = 10
|
||||||
|
potentialByType S.Ten = 4
|
||||||
|
potentialByType S.Seven = 7
|
||||||
|
potentialByType S.Eight = 7
|
||||||
|
potentialByType S.Nine = 7
|
||||||
|
potentialByType S.Queen = 5
|
||||||
|
potentialByType S.King = 5
|
||||||
|
|
||||||
|
optimalSingle :: S.Colour -> S.Card -> S.Card -> Ordering
|
||||||
|
optimalSingle trCol (S.Card t1 _) (S.Card t2 _) = (comparing potentialByType) t2 t1
|
||||||
|
|
||||||
|
optimalTeam :: S.Colour -> S.Card -> S.Card -> Ordering
|
||||||
|
optimalTeam trCol (S.Card t1 _) (S.Card t2 _) = (comparing potentialByType) t2 t1
|
||||||
|
|
||||||
-- TIC TAC TOE implementation
|
-- TIC TAC TOE implementation
|
||||||
|
|
||||||
@@ -106,7 +133,7 @@ data GameState = GameState { getBoard :: [TicTacToe]
|
|||||||
instance Player Bool where
|
instance Player Bool where
|
||||||
maxing = id
|
maxing = id
|
||||||
|
|
||||||
instance Monad m => MonadGame Int WinLossTie Bool (StateT GameState m) where
|
instance Monad m => MonadGame Int [] WinLossTie Bool (StateT GameState m) where
|
||||||
currentPlayer = gets getCurrent
|
currentPlayer = gets getCurrent
|
||||||
turns = do
|
turns = do
|
||||||
board <- gets getBoard
|
board <- gets getBoard
|
||||||
@@ -123,7 +150,7 @@ instance Monad m => MonadGame Int WinLossTie Bool (StateT GameState m) where
|
|||||||
play turn
|
play turn
|
||||||
res <- action
|
res <- action
|
||||||
put backup
|
put backup
|
||||||
return res
|
return $! res
|
||||||
evaluate = do
|
evaluate = do
|
||||||
board <- gets getBoard
|
board <- gets getBoard
|
||||||
current <- currentPlayer
|
current <- currentPlayer
|
||||||
@@ -162,45 +189,37 @@ updateAt :: Int -> [a] -> a -> [a]
|
|||||||
updateAt n xs y = map f $ zip [0..] xs
|
updateAt n xs y = map f $ zip [0..] xs
|
||||||
where f (i, x) = if i == n then y else x
|
where f (i, x) = if i == n then y else x
|
||||||
|
|
||||||
minmax :: (MonadIO m, Show v, Show t, Show p, Value v, Eq t, Player p, MonadGame t v p m)
|
minmax :: (MonadIO m, Show v, Show t, Show p, Value v, Eq t, Player p, MonadGame t l v p m)
|
||||||
=> Int
|
=> Int
|
||||||
-> t
|
-> t
|
||||||
-> v
|
-> v
|
||||||
-> v
|
-> v
|
||||||
-> m (t, v)
|
-> m (t, v)
|
||||||
minmax depth turn alpha beta = (flip evalStateT) (alpha, beta) $ do
|
minmax depth turn_ alpha beta = (flip evalStateT) (alpha, beta) $ do
|
||||||
gameOver <- lift over
|
gameOver <- lift over
|
||||||
-- if last step or game is over then evaluate situation
|
-- if last step or game is over then evaluate situation
|
||||||
if depth == 0 || gameOver then do
|
if depth == 0 || gameOver then (turn_,) <$> lift evaluate
|
||||||
val <- lift evaluate
|
|
||||||
when debug $ liftIO $ putStrLn $ "evaluation: " ++ show val
|
|
||||||
return (turn, val)
|
|
||||||
else do
|
else do
|
||||||
when debug $ liftIO $ putStrLn $ "depth " ++ show depth
|
|
||||||
-- generate a list of possible turns
|
-- generate a list of possible turns
|
||||||
currentlyMaxing <- maxing <$> lift currentPlayer
|
currentlyMaxing <- maxing <$> lift currentPlayer
|
||||||
availableTurns <- lift turns
|
availableTurns <- lift turns
|
||||||
(alpha, beta) <- get
|
(alpha, beta) <- get
|
||||||
-- try every turn, StateT wraps current best turn and current max value
|
-- try every turn, StateT wraps current best turn and current max value
|
||||||
(flip execStateT) (undefined, alpha) $ forM_ availableTurns $ \turn -> do
|
(flip execStateT) (turn_, alpha) $ forM_ availableTurns $ \turn -> do
|
||||||
currentMax <- gets snd
|
currentMax <- gets snd
|
||||||
when debug $ liftIO $ putStrLn $ "simulating " ++ show turn ++ " with max " ++ show currentMax
|
|
||||||
++ " and beta " ++ show beta
|
|
||||||
--when (currentMax >= beta && debug) $ liftIO $ putStrLn "beta cutoff"
|
|
||||||
-- beta cutoff
|
-- beta cutoff
|
||||||
unless (currentMax >= beta) $ do
|
unless (currentMax >= beta) $ do
|
||||||
--unless False $ do
|
value <- lift $! lift $! simulate turn $! do
|
||||||
value <- lift $ lift $ simulate turn $ step currentlyMaxing beta currentMax
|
nextMaxing <- maxing <$!> currentPlayer
|
||||||
when debug $ liftIO $ putStrLn $ "value " ++ show value
|
if nextMaxing /= currentlyMaxing
|
||||||
|
then (invert . snd) <$!> minmax (depth-1) turn (invert beta) (invert currentMax)
|
||||||
|
else snd <$!> minmax (depth-1) turn currentMax beta
|
||||||
when (value > currentMax) (put (turn, value))
|
when (value > currentMax) (put (turn, value))
|
||||||
where step currentlyMaxing beta currentMax = do
|
|
||||||
nextMaxing <- maxing <$> currentPlayer
|
|
||||||
if nextMaxing /= currentlyMaxing
|
|
||||||
then (invert . snd) <$> minmax (depth-1) turn (invert beta) (invert currentMax)
|
|
||||||
else snd <$> minmax (depth-1) turn currentMax beta
|
|
||||||
|
|
||||||
choose :: (MonadIO m, Show v, Show t, Show p, Value v, Eq t, Player p, MonadGame t v p m) => m t
|
choose :: (MonadIO m, Show v, Show t, Show p, Value v, Eq t, Player p, MonadGame t l v p m)
|
||||||
choose = fst <$> minmax 10 undefined loss win
|
=> Int
|
||||||
|
-> m t
|
||||||
|
choose depth = fst <$> minmax depth (error "choose") loss win
|
||||||
|
|
||||||
emptyBoard :: [TicTacToe]
|
emptyBoard :: [TicTacToe]
|
||||||
emptyBoard = [Toe, Toe, Toe, Toe, Toe, Toe, Toe, Toe, Toe]
|
emptyBoard = [Toe, Toe, Toe, Toe, Toe, Toe, Toe, Toe, Toe]
|
||||||
@@ -223,7 +242,7 @@ printOptions opts = print9x9 pr
|
|||||||
| n `elem` opts = putStr (show n) >> putStr " "
|
| n `elem` opts = putStr (show n) >> putStr " "
|
||||||
| otherwise = putStr " "
|
| otherwise = putStr " "
|
||||||
|
|
||||||
instance MonadIO m => PlayableGame Int WinLossTie Bool (StateT GameState m) where
|
instance MonadIO m => PlayableGame Int [] WinLossTie Bool (StateT GameState m) where
|
||||||
showBoard = do
|
showBoard = do
|
||||||
board <- gets getBoard
|
board <- gets getBoard
|
||||||
liftIO $ printBoard board
|
liftIO $ printBoard board
|
||||||
@@ -239,7 +258,7 @@ instance MonadIO m => PlayableGame Int WinLossTie Bool (StateT GameState m) wher
|
|||||||
askTurn = readMaybe <$> liftIO getLine
|
askTurn = readMaybe <$> liftIO getLine
|
||||||
showTurn _ = return ()
|
showTurn _ = return ()
|
||||||
|
|
||||||
instance PlayableGame S.Card Int S.PL S.Skat where
|
instance PlayableGame (S.CardS S.Owner) [] Int S.PL S.Skat where
|
||||||
showBoard = do
|
showBoard = do
|
||||||
liftIO $ putStrLn ""
|
liftIO $ putStrLn ""
|
||||||
table <- S.getp S.tableCards
|
table <- S.getp S.tableCards
|
||||||
@@ -249,7 +268,7 @@ instance PlayableGame S.Card Int S.PL S.Skat where
|
|||||||
cards <- turns
|
cards <- turns
|
||||||
player <- currentPlayer
|
player <- currentPlayer
|
||||||
liftIO $ print player
|
liftIO $ print player
|
||||||
liftIO $ S.render (S.sortRender cards)
|
liftIO $ S.render cards
|
||||||
winner = do
|
winner = do
|
||||||
piles <- gets S.piles
|
piles <- gets S.piles
|
||||||
pls <- gets S.players
|
pls <- gets S.players
|
||||||
@@ -259,7 +278,7 @@ instance PlayableGame S.Card Int S.PL S.Skat where
|
|||||||
return $ Just $ head winners
|
return $ Just $ head winners
|
||||||
askTurn = do
|
askTurn = do
|
||||||
cards <- turns
|
cards <- turns
|
||||||
let sorted = S.sortRender cards
|
let sorted = cards
|
||||||
input <- liftIO getLine
|
input <- liftIO getLine
|
||||||
case readMaybe input of
|
case readMaybe input of
|
||||||
Just n -> if n >= 0 && n < length sorted then return $ Just (sorted !! n)
|
Just n -> if n >= 0 && n < length sorted then return $ Just (sorted !! n)
|
||||||
@@ -269,19 +288,20 @@ instance PlayableGame S.Card Int S.PL S.Skat where
|
|||||||
player <- currentPlayer
|
player <- currentPlayer
|
||||||
liftIO $ putStrLn $ show player ++ " plays " ++ show card
|
liftIO $ putStrLn $ show player ++ " plays " ++ show card
|
||||||
|
|
||||||
playCLI :: (MonadFail m, Read t, PlayableGame t v p m) => m ()
|
playCLI :: (MonadFail m, Read t, PlayableGame t l v p m) => m ()
|
||||||
playCLI = do
|
playCLI = do
|
||||||
gameOver <- over
|
gameOver <- over
|
||||||
if gameOver
|
if gameOver
|
||||||
then announceWinner
|
then announceWinner
|
||||||
else do
|
else do
|
||||||
showBoard
|
when debug showBoard
|
||||||
current <- currentPlayer
|
current <- currentPlayer
|
||||||
turn <- if not (maxing current) then readTurn else choose
|
turn <- choose 10
|
||||||
showTurn turn
|
when debug $ showTurn turn
|
||||||
play turn
|
play turn
|
||||||
playCLI
|
playCLI
|
||||||
where
|
where
|
||||||
|
readTurn :: (MonadFail m, Read t, PlayableGame t l v p m) => m t
|
||||||
readTurn = do
|
readTurn = do
|
||||||
options <- turns
|
options <- turns
|
||||||
showTurns
|
showTurns
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ module Skat.AI.Online where
|
|||||||
|
|
||||||
import Control.Monad.Reader
|
import Control.Monad.Reader
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
|
import Data.Maybe
|
||||||
import qualified Data.ByteString.Lazy.Char8 as BS
|
import qualified Data.ByteString.Lazy.Char8 as BS
|
||||||
|
|
||||||
import Skat.Player
|
import Skat.Player
|
||||||
@@ -52,15 +53,16 @@ instance MonadPlayer m => MonadPlayer (Online a m) where
|
|||||||
turnColour = lift $ turnColour
|
turnColour = lift $ turnColour
|
||||||
showSkat = lift . showSkat
|
showSkat = lift . showSkat
|
||||||
|
|
||||||
choose :: (Communicator c, MonadPlayer m) => [CardS Played] -> [Card] -> Online c m Card
|
choose :: HasCard a => (Communicator c, MonadPlayer m) => [CardS Played] -> [a] -> Online c m Card
|
||||||
choose table hand = do
|
choose table hand' = do
|
||||||
|
let hand = map toCard hand'
|
||||||
query (BS.unpack $ encode $ ChooseQuery hand table)
|
query (BS.unpack $ encode $ ChooseQuery hand table)
|
||||||
r <- response
|
r <- response
|
||||||
case decode (BS.pack r) of
|
case decode (BS.pack r) of
|
||||||
Just (ChosenResponse card) -> do
|
Just (ChosenResponse card) -> do
|
||||||
allowed <- P.isAllowed hand card
|
allowed <- P.isAllowed hand card
|
||||||
if card `elem` hand && allowed then return card else choose table hand
|
if card `elem` hand && allowed then return card else choose table hand'
|
||||||
Nothing -> choose table hand
|
Nothing -> choose table hand'
|
||||||
|
|
||||||
cardPlayed :: (Communicator c, MonadPlayer m) => CardS Played -> Online c m ()
|
cardPlayed :: (Communicator c, MonadPlayer m) => CardS Played -> Online c m ()
|
||||||
cardPlayed card = query (BS.unpack $ encode $ CardPlayedQuery card)
|
cardPlayed card = query (BS.unpack $ encode $ CardPlayedQuery card)
|
||||||
|
|||||||
+28
-20
@@ -19,7 +19,7 @@ import qualified Data.Map.Strict as M
|
|||||||
|
|
||||||
import Skat.Player
|
import Skat.Player
|
||||||
import qualified Skat.Player.Utils as P
|
import qualified Skat.Player.Utils as P
|
||||||
import Skat.Pile
|
import Skat.Pile hiding (isSkat)
|
||||||
import Skat.Card
|
import Skat.Card
|
||||||
import Skat.Utils
|
import Skat.Utils
|
||||||
import Skat (Skat, modifyp, mkSkatEnv)
|
import Skat (Skat, modifyp, mkSkatEnv)
|
||||||
@@ -81,7 +81,7 @@ instance Player AIEnv where
|
|||||||
hand = getHand
|
hand = getHand
|
||||||
chooseCard p table fallen hand = runStateT (do
|
chooseCard p table fallen hand = runStateT (do
|
||||||
modify $ setTable table
|
modify $ setTable table
|
||||||
modify $ setHand hand
|
modify $ setHand (map toCard hand)
|
||||||
modify $ setFallen fallen
|
modify $ setFallen fallen
|
||||||
choose) p
|
choose) p
|
||||||
onCardPlayed p card = execStateT (do
|
onCardPlayed p card = execStateT (do
|
||||||
@@ -142,20 +142,16 @@ analyzeTurn (c1, c2, c3) = do
|
|||||||
col2 = effectiveColour trCol (getCard c2)
|
col2 = effectiveColour trCol (getCard c2)
|
||||||
col3 = effectiveColour trCol (getCard c3)
|
col3 = effectiveColour trCol (getCard c3)
|
||||||
if col2 /= demanded
|
if col2 /= demanded
|
||||||
then origin c2 `hasNoLonger` demanded
|
then uorigin (getPile c2) `hasNoLonger` demanded
|
||||||
else return ()
|
else return ()
|
||||||
if col3 /= demanded
|
if col3 /= demanded
|
||||||
then origin c3 `hasNoLonger` demanded
|
then uorigin (getPile c3) `hasNoLonger` demanded
|
||||||
else return ()
|
else return ()
|
||||||
|
|
||||||
type Distribution = ([Card], [Card], [Card], [Card])
|
type Distribution = ([Card], [Card], [Card], [Card])
|
||||||
|
|
||||||
toPiles :: [CardS Played] -> Distribution -> Piles
|
toPiles :: [CardS Played] -> Distribution -> Piles
|
||||||
toPiles table (h1, h2, h3, skt) = Piles (cs1 ++ cs2 ++ cs3) table ss
|
toPiles table (h1, h2, h3, skt) = makePiles h1 h2 h3 table skt
|
||||||
where cs1 = map (putAt Hand1) h1
|
|
||||||
cs2 = map (putAt Hand2) h2
|
|
||||||
cs3 = map (putAt Hand3) h3
|
|
||||||
ss = map (putAt SkatP) skt
|
|
||||||
|
|
||||||
compareGuess :: (Card, [Option]) -> (Card, [Option]) -> Ordering
|
compareGuess :: (Card, [Option]) -> (Card, [Option]) -> Ordering
|
||||||
compareGuess (c1, ops1) (c2, ops2)
|
compareGuess (c1, ops1) (c2, ops2)
|
||||||
@@ -227,7 +223,7 @@ onPlayed c = do
|
|||||||
let col = effectiveColour trCol (getCard c)
|
let col = effectiveColour trCol (getCard c)
|
||||||
case turnCol of
|
case turnCol of
|
||||||
Just demanded -> if col /= demanded
|
Just demanded -> if col /= demanded
|
||||||
then origin c `hasNoLonger` demanded else return ()
|
then uorigin (getPile c) `hasNoLonger` demanded else return ()
|
||||||
Nothing -> return ()
|
Nothing -> return ()
|
||||||
|
|
||||||
choose :: MonadPlayer m => AI m Card
|
choose :: MonadPlayer m => AI m Card
|
||||||
@@ -237,6 +233,19 @@ chooseStatistic :: MonadPlayer m => AI m Card
|
|||||||
chooseStatistic = do
|
chooseStatistic = do
|
||||||
h <- gets getHand
|
h <- gets getHand
|
||||||
handCards <- gets myHand
|
handCards <- gets myHand
|
||||||
|
table <- gets table
|
||||||
|
let tableNo = length table
|
||||||
|
left = 3 - tableNo
|
||||||
|
depth = case length handCards of
|
||||||
|
10 -> 3 + tableNo
|
||||||
|
9 -> 3 + tableNo
|
||||||
|
8 -> 3 + tableNo
|
||||||
|
7 -> 6 + tableNo
|
||||||
|
6 -> 9 + tableNo
|
||||||
|
5 -> 12 + tableNo
|
||||||
|
4 -> 15 + tableNo
|
||||||
|
_ -> 100
|
||||||
|
modify $ setDepth depth
|
||||||
guess__ <- gets guess
|
guess__ <- gets guess
|
||||||
self <- get
|
self <- get
|
||||||
maySkat <- showSkat self
|
maySkat <- showSkat self
|
||||||
@@ -244,8 +253,7 @@ chooseStatistic = do
|
|||||||
guess = case maySkat of
|
guess = case maySkat of
|
||||||
Just cs -> (cs `isSkat`) guess_
|
Just cs -> (cs `isSkat`) guess_
|
||||||
Nothing -> guess_
|
Nothing -> guess_
|
||||||
table <- gets table
|
let ns = case tableNo of
|
||||||
let ns = case length table of
|
|
||||||
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)
|
||||||
@@ -286,14 +294,13 @@ chooseOpen = do
|
|||||||
piles <- showPiles
|
piles <- showPiles
|
||||||
hand <- gets getHand
|
hand <- gets getHand
|
||||||
let myCards = handCards hand piles
|
let myCards = handCards hand piles
|
||||||
liftIO $ putStrLn $ show hand ++ " chooses from " ++ show myCards
|
|
||||||
possible <- filterM (P.isAllowed myCards) myCards
|
possible <- filterM (P.isAllowed myCards) myCards
|
||||||
case length possible of
|
case length possible of
|
||||||
0 -> do
|
0 -> do
|
||||||
liftIO $ print hand
|
liftIO $ print hand
|
||||||
liftIO $ print piles
|
liftIO $ print piles
|
||||||
error "no cards left to choose from"
|
error "no cards left to choose from"
|
||||||
1 -> return $ head possible
|
1 -> return $ toCard $ head possible
|
||||||
_ -> chooseSimulating
|
_ -> chooseSimulating
|
||||||
|
|
||||||
chooseSimulating :: (MonadState AIEnv m, MonadPlayerOpen m)
|
chooseSimulating :: (MonadState AIEnv m, MonadPlayerOpen m)
|
||||||
@@ -303,11 +310,12 @@ chooseSimulating = do
|
|||||||
turnCol <- turnColour
|
turnCol <- turnColour
|
||||||
trumpCol <- trumpColour
|
trumpCol <- trumpColour
|
||||||
myHand <- gets getHand
|
myHand <- gets getHand
|
||||||
|
depth <- gets simulationDepth
|
||||||
let ps = Players (PL $ Stupid.Stupid Team Hand1)
|
let ps = Players (PL $ Stupid.Stupid Team Hand1)
|
||||||
(PL $ Stupid.Stupid Team Hand2)
|
(PL $ Stupid.Stupid Team Hand2)
|
||||||
(PL $ Stupid.Stupid Single Hand3)
|
(PL $ Stupid.Stupid Single Hand3)
|
||||||
env = mkSkatEnv piles turnCol trumpCol ps myHand
|
env = mkSkatEnv piles turnCol trumpCol ps myHand
|
||||||
liftIO $ evalStateT (Minmax.choose :: Skat Card) env
|
liftIO $ evalStateT (toCard <$> (Minmax.choose depth :: Skat (CardS Owner))) env
|
||||||
|
|
||||||
simulate :: (MonadState AIEnv m, MonadPlayerOpen m)
|
simulate :: (MonadState AIEnv m, MonadPlayerOpen m)
|
||||||
=> Card -> m Int
|
=> Card -> m Int
|
||||||
@@ -329,7 +337,7 @@ simulate card = do
|
|||||||
env = mkSkatEnv piles turnCol trumpCol ps (next myHand)
|
env = mkSkatEnv piles turnCol trumpCol ps (next myHand)
|
||||||
-- simulate the game after playing the given card
|
-- simulate the game after playing the given card
|
||||||
(sgl, tm) <- liftIO $ evalStateT (do
|
(sgl, tm) <- liftIO $ evalStateT (do
|
||||||
modifyp $ playCard card
|
modifyp $ playCard myHand card
|
||||||
turnGeneric playOpen depth) env
|
turnGeneric playOpen depth) env
|
||||||
let v = if myTeam == Single then (sgl, tm) else (tm, sgl)
|
let v = if myTeam == Single then (sgl, tm) else (tm, sgl)
|
||||||
-- put the value into context for when not the whole game is
|
-- put the value into context for when not the whole game is
|
||||||
@@ -346,13 +354,13 @@ predictValue (own, others) = do
|
|||||||
--return $ own + pot
|
--return $ own + pot
|
||||||
return (own-others)
|
return (own-others)
|
||||||
|
|
||||||
potential :: (MonadState AIEnv m, MonadPlayerOpen m)
|
potential :: (MonadState AIEnv m, MonadPlayerOpen m, HasCard c)
|
||||||
=> [Card] -> m Int
|
=> [c] -> m Int
|
||||||
potential cs = do
|
potential cs = do
|
||||||
tr <- trumpColour
|
tr <- trumpColour
|
||||||
let trs = filter (isTrump tr) cs
|
let trs = filter (isTrump tr) cs
|
||||||
value = count cs
|
value = count . map toCard $ cs
|
||||||
positions <- filter (==0) <$> mapM position cs
|
positions <- filter (==0) <$> mapM (position . toCard) cs
|
||||||
return $ length trs * 10 + value + length positions * 5
|
return $ length trs * 10 + value + length positions * 5
|
||||||
|
|
||||||
position :: (MonadState AIEnv m, MonadPlayer m)
|
position :: (MonadState AIEnv m, MonadPlayer m)
|
||||||
|
|||||||
@@ -15,4 +15,4 @@ instance Player Stupid where
|
|||||||
trumpCol <- trumpColour
|
trumpCol <- trumpColour
|
||||||
turnCol <- turnColour
|
turnCol <- turnColour
|
||||||
let possible = filter (isAllowed trumpCol turnCol hand) hand
|
let possible = filter (isAllowed trumpCol turnCol hand) hand
|
||||||
return (head possible, p)
|
return (toCard $ head possible, p)
|
||||||
|
|||||||
+48
-23
@@ -1,16 +1,23 @@
|
|||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
|
||||||
module Skat.Card where
|
module Skat.Card where
|
||||||
|
|
||||||
import Data.List
|
import Data.List
|
||||||
|
import Data.Foldable (Foldable)
|
||||||
|
import qualified Data.Foldable as F
|
||||||
|
import qualified Data.Set as S
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import System.Random (newStdGen, StdGen)
|
import System.Random (newStdGen, StdGen)
|
||||||
import Control.DeepSeq
|
import Control.DeepSeq
|
||||||
|
|
||||||
import Skat.Utils
|
import Skat.Utils
|
||||||
|
|
||||||
|
class HasCard c where
|
||||||
|
toCard :: c -> Card
|
||||||
|
|
||||||
class Countable a b where
|
class Countable a b where
|
||||||
count :: a -> b
|
count :: a -> b
|
||||||
|
|
||||||
@@ -41,6 +48,15 @@ data Colour = Diamonds
|
|||||||
data Card = Card Type Colour
|
data Card = Card Type Colour
|
||||||
deriving (Eq, Show, Ord, Read)
|
deriving (Eq, Show, Ord, Read)
|
||||||
|
|
||||||
|
getType :: Card -> Type
|
||||||
|
getType (Card t _) = t
|
||||||
|
|
||||||
|
getColour :: Card -> Colour
|
||||||
|
getColour (Card _ c) = c
|
||||||
|
|
||||||
|
instance HasCard Card where
|
||||||
|
toCard = id
|
||||||
|
|
||||||
instance ToJSON Card where
|
instance ToJSON Card where
|
||||||
toJSON (Card t c) =
|
toJSON (Card t c) =
|
||||||
object ["type" .= show t, "colour" .= show c]
|
object ["type" .= show t, "colour" .= show c]
|
||||||
@@ -51,11 +67,8 @@ instance FromJSON Card where
|
|||||||
c <- v .: "colour"
|
c <- v .: "colour"
|
||||||
return $ Card (read t) (read c)
|
return $ Card (read t) (read c)
|
||||||
|
|
||||||
getColour :: Card -> Colour
|
getID :: HasCard c => c -> Int
|
||||||
getColour (Card _ c) = c
|
getID card = let t = getType $ toCard card in case t of
|
||||||
|
|
||||||
getID :: Card -> Int
|
|
||||||
getID (Card t _) = case t of
|
|
||||||
Seven -> 0
|
Seven -> 0
|
||||||
Eight -> 0
|
Eight -> 0
|
||||||
Nine -> 0
|
Nine -> 0
|
||||||
@@ -65,11 +78,22 @@ getID (Card t _) = case t of
|
|||||||
Ace -> 16
|
Ace -> 16
|
||||||
Jack -> 32
|
Jack -> 32
|
||||||
|
|
||||||
|
instance Enum Card where
|
||||||
|
fromEnum (Card tp col) = fromEnum col * 8 + fromEnum tp
|
||||||
|
toEnum n = Card tp col
|
||||||
|
where col = toEnum (n `div` 8)
|
||||||
|
tp = toEnum (n `mod` 8)
|
||||||
|
|
||||||
instance Countable Card Int where
|
instance Countable Card Int where
|
||||||
count (Card t _) = count t
|
count (Card t _) = count t
|
||||||
|
|
||||||
instance Countable [Card] Int where
|
instance Foldable t => Countable (t Card) Int where
|
||||||
count = sum . map count
|
count = foldl' f 0
|
||||||
|
where f acc c = count c + acc
|
||||||
|
|
||||||
|
instance Countable (S.Set Card) Int where
|
||||||
|
count = S.foldl' f 0
|
||||||
|
where f acc card = count card + acc
|
||||||
|
|
||||||
instance NFData Card where
|
instance NFData Card where
|
||||||
rnf (Card t c) = t `seq` c `seq` ()
|
rnf (Card t c) = t `seq` c `seq` ()
|
||||||
@@ -78,22 +102,21 @@ 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
|
||||||
|
|
||||||
isTrump :: Colour -> Card -> Bool
|
isTrump :: HasCard c => Colour -> c -> Bool
|
||||||
isTrump trumpCol (Card tp col)
|
isTrump trumpCol crd
|
||||||
| tp == Jack = True
|
| getType (toCard crd) == Jack = True
|
||||||
| otherwise = col == trumpCol
|
| otherwise = getColour (toCard crd) == trumpCol
|
||||||
|
|
||||||
effectiveColour :: Colour -> Card -> Colour
|
effectiveColour :: HasCard c => Colour -> c -> Colour
|
||||||
effectiveColour trumpCol card@(Card _ col) =
|
effectiveColour trumpCol crd = if trump then trumpCol else getColour (toCard crd)
|
||||||
if trump then trumpCol else col
|
where trump = isTrump trumpCol crd
|
||||||
where trump = isTrump trumpCol card
|
|
||||||
|
|
||||||
isAllowed :: Colour -> Maybe Colour -> [Card] -> Card -> Bool
|
isAllowed :: (Foldable t, HasCard c1, HasCard c2) => Colour -> Maybe Colour -> t c1 -> c2 -> Bool
|
||||||
isAllowed trumpCol turnCol cs card =
|
isAllowed trumpCol turnCol cs crd =
|
||||||
if col `equals` turnCol
|
if col `equals` turnCol
|
||||||
then True
|
then True
|
||||||
else not $ any (\ca -> effectiveColour trumpCol ca `equals` turnCol && ca /= card) cs
|
else not $ F.any (\ca -> effectiveColour trumpCol ca `equals` turnCol && toCard ca /= toCard crd) cs
|
||||||
where col = effectiveColour trumpCol card
|
where col = effectiveColour trumpCol (toCard crd)
|
||||||
|
|
||||||
compareCards :: Colour
|
compareCards :: Colour
|
||||||
-> Maybe Colour
|
-> Maybe Colour
|
||||||
@@ -112,11 +135,13 @@ compareCards trumpCol turnCol c1@(Card tp1 col1) c2@(Card tp2 col2) =
|
|||||||
where trp1 = isTrump trumpCol c1
|
where trp1 = isTrump trumpCol c1
|
||||||
trp2 = isTrump trumpCol c2
|
trp2 = isTrump trumpCol c2
|
||||||
|
|
||||||
sortCards :: Colour -> Maybe Colour -> [Card] -> [Card]
|
sortCards :: HasCard c => Colour -> Maybe Colour -> [c] -> [c]
|
||||||
sortCards trumpCol turnCol cs = sortBy (compareCards trumpCol turnCol) cs
|
sortCards trumpCol turnCol cs = sortBy f cs
|
||||||
|
where f c1 c2 = compareCards trumpCol turnCol (toCard c1) (toCard c2)
|
||||||
|
|
||||||
highestCard :: Colour -> Maybe Colour -> [Card] -> Card
|
highestCard :: HasCard c => Colour -> Maybe Colour -> [c] -> c
|
||||||
highestCard trumpCol turnCol cs = maximumBy (compareCards trumpCol turnCol) cs
|
highestCard trumpCol turnCol cs = maximumBy f cs
|
||||||
|
where f c1 c2 = compareCards trumpCol turnCol (toCard c1) (toCard c2)
|
||||||
|
|
||||||
shuffleCards :: IO [Card]
|
shuffleCards :: IO [Card]
|
||||||
shuffleCards = do
|
shuffleCards = do
|
||||||
|
|||||||
+1
-4
@@ -17,7 +17,7 @@ import Skat.AI.Stupid
|
|||||||
|
|
||||||
-- | predefined card distribution for testing purposes
|
-- | predefined card distribution for testing purposes
|
||||||
cardDistr :: Piles
|
cardDistr :: Piles
|
||||||
cardDistr = Piles hands [] (map (putAt SkatP) skt)
|
cardDistr = emptyPiles hand1 hand2 hand3 skt
|
||||||
where hand3 = [Card Ace Spades, Card Jack Diamonds, Card Jack Clubs, Card King Spades,
|
where hand3 = [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]
|
||||||
@@ -27,9 +27,6 @@ cardDistr = Piles hands [] (map (putAt SkatP) skt)
|
|||||||
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,
|
||||||
Card Seven Hearts, Card Eight Hearts, Card Queen Hearts, Card King Hearts,
|
Card Seven Hearts, Card Eight Hearts, Card Queen Hearts, Card King Hearts,
|
||||||
Card Nine Diamonds, Card Eight Diamonds]
|
Card Nine Diamonds, Card Eight Diamonds]
|
||||||
hands = map (putAt Hand1) hand1
|
|
||||||
++ map (putAt Hand2) hand2
|
|
||||||
++ map (putAt Hand3) hand3
|
|
||||||
skt = [Card Nine Clubs, Card Queen Clubs]
|
skt = [Card Nine Clubs, Card Queen Clubs]
|
||||||
|
|
||||||
singleVsBots :: Communicator c => c -> IO ()
|
singleVsBots :: Communicator c => c -> IO ()
|
||||||
|
|||||||
+21
-15
@@ -1,12 +1,13 @@
|
|||||||
module Skat.Operations (
|
module Skat.Operations (
|
||||||
turn, turnGeneric, play, playOpen, publishGameResults,
|
turn, turnGeneric, play, playOpen, publishGameResults,
|
||||||
publishGameStart, play_, sortRender
|
publishGameStart, play_, sortRender, undo_
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.State
|
import Control.Monad.State
|
||||||
import System.Random (newStdGen, randoms)
|
import System.Random (newStdGen, randoms)
|
||||||
import Data.List
|
import Data.List
|
||||||
import Data.Ord
|
import Data.Ord
|
||||||
|
import qualified Data.Set as S
|
||||||
|
|
||||||
import Skat
|
import Skat
|
||||||
import Skat.Card
|
import Skat.Card
|
||||||
@@ -23,11 +24,11 @@ compareRender (Card t1 c1) (Card t2 c2) = case compare c1 c2 of
|
|||||||
sortRender :: [Card] -> [Card]
|
sortRender :: [Card] -> [Card]
|
||||||
sortRender = sortBy compareRender
|
sortRender = sortBy compareRender
|
||||||
|
|
||||||
play_ :: Card -> Skat ()
|
play_ :: HasCard c => c -> Skat ()
|
||||||
play_ card = do
|
play_ card = do
|
||||||
hand <- gets currentHand
|
hand <- gets currentHand
|
||||||
trCol <- gets trumpColour
|
trCol <- gets trumpColour
|
||||||
modifyp $ playCard card
|
modifyp $ playCard hand card
|
||||||
table <- getp tableCards
|
table <- getp tableCards
|
||||||
case length table of
|
case length table of
|
||||||
1 -> do modify (setCurrentHand $ next hand)
|
1 -> do modify (setCurrentHand $ next hand)
|
||||||
@@ -35,6 +36,12 @@ play_ card = do
|
|||||||
3 -> evaluateTable >>= modify . setCurrentHand
|
3 -> evaluateTable >>= modify . setCurrentHand
|
||||||
_ -> modify (setCurrentHand $ next hand)
|
_ -> modify (setCurrentHand $ next hand)
|
||||||
|
|
||||||
|
undo_ :: HasCard c => c -> Hand -> Maybe Colour -> Team -> Skat ()
|
||||||
|
undo_ card oldCurrent oldTurnCol oldWinner = do
|
||||||
|
modify $ setCurrentHand oldCurrent
|
||||||
|
modify $ setTurnColour oldTurnCol
|
||||||
|
modifyp $ unplayCard oldCurrent (toCard card) oldWinner
|
||||||
|
|
||||||
turnGeneric :: (PL -> Skat Card)
|
turnGeneric :: (PL -> Skat Card)
|
||||||
-> Int
|
-> Int
|
||||||
-> Skat (Int, Int)
|
-> Skat (Int, Int)
|
||||||
@@ -43,7 +50,7 @@ turnGeneric playFunc depth = do
|
|||||||
table <- getp tableCards
|
table <- getp tableCards
|
||||||
ps <- gets players
|
ps <- gets players
|
||||||
let p = player ps n
|
let p = player ps n
|
||||||
hand <- getp $ handCards n
|
over <- getp $ handEmpty n
|
||||||
trCol <- gets trumpColour
|
trCol <- gets trumpColour
|
||||||
case length table of
|
case length table of
|
||||||
0 -> playFunc p >> modify (setCurrentHand $ next n) >> turnGeneric playFunc depth
|
0 -> playFunc p >> modify (setCurrentHand $ next n) >> turnGeneric playFunc depth
|
||||||
@@ -56,7 +63,7 @@ turnGeneric playFunc depth = do
|
|||||||
2 -> playFunc p >> modify (setCurrentHand $ next n) >> turnGeneric playFunc depth
|
2 -> playFunc p >> modify (setCurrentHand $ next n) >> turnGeneric playFunc depth
|
||||||
3 -> do
|
3 -> do
|
||||||
w <- evaluateTable
|
w <- evaluateTable
|
||||||
if depth <= 1 || length hand == 0
|
if depth <= 1 || over
|
||||||
then countGame
|
then countGame
|
||||||
else modify (setCurrentHand w) >> turnGeneric playFunc (depth - 1)
|
else modify (setCurrentHand w) >> turnGeneric playFunc (depth - 1)
|
||||||
|
|
||||||
@@ -69,9 +76,8 @@ evaluateTable = do
|
|||||||
turnCol <- gets turnColour
|
turnCol <- gets turnColour
|
||||||
table <- getp tableCards
|
table <- getp tableCards
|
||||||
ps <- gets players
|
ps <- gets players
|
||||||
let winningCard = highestCard trumpCol turnCol table
|
let winnerHand = uorigin $ getPile $ highestCard trumpCol turnCol table
|
||||||
Just winnerHand <- getp $ originOfCard winningCard
|
winner = player ps winnerHand
|
||||||
let winner = player ps winnerHand
|
|
||||||
modifyp $ cleanTable (team winner)
|
modifyp $ cleanTable (team winner)
|
||||||
modify $ setTurnColour Nothing
|
modify $ setTurnColour Nothing
|
||||||
return $ hand winner
|
return $ hand winner
|
||||||
@@ -82,25 +88,25 @@ countGame = getp count
|
|||||||
play :: (Show p, Player p) => p -> Skat Card
|
play :: (Show p, Player p) => p -> Skat Card
|
||||||
play p = do
|
play p = do
|
||||||
liftIO $ putStrLn "playing"
|
liftIO $ putStrLn "playing"
|
||||||
table <- getp tableCardsS
|
table <- getp tableCards
|
||||||
turnCol <- gets turnColour
|
turnCol <- gets turnColour
|
||||||
trump <- gets trumpColour
|
trump <- gets trumpColour
|
||||||
hand <- getp $ handCards (hand p)
|
cards <- getp $ handCards (hand p)
|
||||||
fallen <- getp played
|
fallen <- getp played
|
||||||
(card, p') <- chooseCard p table fallen hand
|
(card, p') <- chooseCard p table fallen cards
|
||||||
modifyPlayers $ updatePlayer p'
|
modifyPlayers $ updatePlayer p'
|
||||||
modifyp $ playCard card
|
modifyp $ playCard (hand p) card
|
||||||
ps <- fmap playersToList $ gets players
|
ps <- fmap playersToList $ gets players
|
||||||
table' <- getp tableCardsS
|
table' <- getp tableCards
|
||||||
ps' <- mapM (\p -> onCardPlayed p (head table')) ps
|
ps' <- mapM (\p -> onCardPlayed p (head table')) ps
|
||||||
mapM_ (modifyPlayers . updatePlayer) ps'
|
mapM_ (modifyPlayers . updatePlayer) ps'
|
||||||
return card
|
return (toCard card)
|
||||||
|
|
||||||
playOpen :: (Show p, Player p) => p -> Skat Card
|
playOpen :: (Show p, Player p) => p -> Skat Card
|
||||||
playOpen p = do
|
playOpen p = do
|
||||||
--liftIO $ putStrLn $ show (hand p) ++ " playing open"
|
--liftIO $ putStrLn $ show (hand p) ++ " playing open"
|
||||||
card <- chooseCardOpen p
|
card <- chooseCardOpen p
|
||||||
modifyp $ playCard card
|
modifyp $ playCard (hand p) card
|
||||||
return card
|
return card
|
||||||
|
|
||||||
publishGameResults :: (Int, Int) -> Skat ()
|
publishGameResults :: (Int, Int) -> Skat ()
|
||||||
|
|||||||
+99
-51
@@ -1,32 +1,47 @@
|
|||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
|
{-# LANGUAGE TupleSections #-}
|
||||||
|
|
||||||
module Skat.Pile where
|
module Skat.Pile where
|
||||||
|
|
||||||
import Data.List
|
import Prelude hiding (lookup)
|
||||||
|
import qualified Data.Map.Strict as M
|
||||||
|
import qualified Data.Vector as V
|
||||||
|
import Data.Vector (Vector)
|
||||||
|
import Data.Foldable (toList, foldl', Foldable)
|
||||||
|
import Data.Maybe
|
||||||
import Data.Aeson
|
import Data.Aeson
|
||||||
import Control.Exception
|
import Control.Exception
|
||||||
|
import Data.List (delete)
|
||||||
|
|
||||||
import Skat.Card
|
import Skat.Card
|
||||||
import Skat.Utils
|
import Skat.Utils
|
||||||
|
|
||||||
data Team = Team | Single
|
data Team = Team | Single
|
||||||
deriving (Show, Eq, Ord, Enum)
|
deriving (Show, Eq, Ord, Enum, Read)
|
||||||
|
|
||||||
data CardS p = CardS { getCard :: Card
|
data CardS p = CardS { getCard :: Card
|
||||||
, getPile :: p }
|
, getPile :: p }
|
||||||
deriving (Show, Eq, Ord)
|
deriving (Show, Eq, Ord, Read)
|
||||||
|
|
||||||
|
instance HasCard (CardS p) where
|
||||||
|
toCard = getCard
|
||||||
|
|
||||||
instance Countable (CardS p) Int where
|
instance Countable (CardS p) Int where
|
||||||
count = count . getCard
|
count = count . getCard
|
||||||
|
|
||||||
|
instance Foldable t => Countable (t (CardS p)) Int where
|
||||||
|
count = foldl' f 0
|
||||||
|
where f acc c = count c + acc
|
||||||
|
|
||||||
instance ToJSON p => ToJSON (CardS p) where
|
instance ToJSON p => ToJSON (CardS p) where
|
||||||
toJSON (CardS card pile) =
|
toJSON (CardS card pile) =
|
||||||
object ["card" .= card, "pile" .= pile]
|
object ["card" .= card, "pile" .= pile]
|
||||||
|
|
||||||
data Hand = Hand1 | Hand2 | Hand3
|
data Hand = Hand1 | Hand2 | Hand3
|
||||||
deriving (Show, Eq, Ord)
|
deriving (Show, Eq, Ord, Read)
|
||||||
|
|
||||||
toInt :: Hand -> Int
|
toInt :: Hand -> Int
|
||||||
toInt Hand1 = 1
|
toInt Hand1 = 1
|
||||||
@@ -43,76 +58,112 @@ prev Hand1 = Hand3
|
|||||||
prev Hand2 = Hand1
|
prev Hand2 = Hand1
|
||||||
prev Hand3 = Hand2
|
prev Hand3 = Hand2
|
||||||
|
|
||||||
data Played = Table Hand
|
data Owner = P Hand | S
|
||||||
| Won Hand Team
|
deriving (Show, Eq, Ord, Read)
|
||||||
deriving (Show, Eq, Ord)
|
|
||||||
|
|
||||||
instance ToJSON Played where
|
instance ToJSON Owner where
|
||||||
toJSON (Table hand) =
|
toJSON _ = undefined -- TODO: fix
|
||||||
object ["state" .= ("table" :: String), "played_by" .= show hand]
|
|
||||||
toJSON (Won hand team) =
|
|
||||||
object ["state" .= ("won" :: String), "played_by" .= show hand, "won_by" .= show team]
|
|
||||||
|
|
||||||
data SkatP = SkatP
|
type Played = Owner -- TODO: remove
|
||||||
|
|
||||||
|
data Piles = Piles { _hand1 :: [CardS Owner]
|
||||||
|
, _hand2 :: [CardS Owner]
|
||||||
|
, _hand3 :: [CardS Owner]
|
||||||
|
, _table :: [CardS Owner]
|
||||||
|
, _wonSingle :: [CardS Owner]
|
||||||
|
, _wonTeam :: [CardS Owner]
|
||||||
|
, _skat :: [CardS Owner] }
|
||||||
deriving (Show, Eq, Ord)
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
data Piles = Piles { hands :: [CardS Hand]
|
toTable :: Hand -> Card -> Piles -> Piles
|
||||||
, played :: [CardS Played]
|
toTable hand card ps = ps { _table = (CardS card (P hand)) : _table ps }
|
||||||
, skat :: [CardS SkatP] }
|
|
||||||
deriving (Show, Eq, Ord)
|
|
||||||
|
|
||||||
instance Countable Piles (Int, Int) where
|
instance Countable Piles (Int, Int) where
|
||||||
count ps = (sgl, tm)
|
count ps = (sgl, tm)
|
||||||
where sgl = count (skatCards ps) + count (wonCards Single ps)
|
where sgl = count (skatCards ps) + count (wonCards Single ps)
|
||||||
tm = count (wonCards Team ps)
|
tm = count (wonCards Team ps)
|
||||||
|
|
||||||
origin :: CardS Played -> Hand
|
played :: Piles -> [CardS Owner]
|
||||||
origin (CardS _ (Table hand)) = hand
|
played ps = _wonSingle ps ++ _wonTeam ps ++ _table ps
|
||||||
origin (CardS _ (Won hand _)) = hand
|
|
||||||
|
|
||||||
originOfCard :: Card -> Piles -> Maybe Hand
|
origin :: Owner -> Maybe Hand
|
||||||
originOfCard card (Piles _ pld _) = origin <$> find ((==card) . getCard) pld
|
origin (P hand) = Just hand
|
||||||
|
origin S = Nothing
|
||||||
|
|
||||||
playCard :: Card -> Piles -> Piles
|
uorigin :: Owner -> Hand
|
||||||
playCard card (Piles hs pld skt) = Piles hs' (ca : pld) skt
|
uorigin owner = case origin owner of
|
||||||
where (CardS _ hand, hs') = remove ((==card) . getCard) hs
|
Just hand -> hand
|
||||||
ca = CardS card (Table hand)
|
Nothing -> error "has no origin"
|
||||||
|
|
||||||
winCard :: Team -> CardS Played -> CardS Played
|
removeFromHand :: Hand -> Card -> Piles -> Piles
|
||||||
winCard team (CardS card (Table hand)) = CardS card (Won hand team)
|
removeFromHand Hand1 card ps = ps { _hand1 = delete (CardS card (P Hand1)) (_hand1 ps) }
|
||||||
winCard team c = c
|
removeFromHand Hand2 card ps = ps { _hand2 = delete (CardS card (P Hand2)) (_hand2 ps) }
|
||||||
|
removeFromHand Hand3 card ps = ps { _hand3 = delete (CardS card (P Hand3)) (_hand3 ps) }
|
||||||
|
|
||||||
wonCards :: Team -> Piles -> [Card]
|
addToHand :: Hand -> Card -> Piles -> Piles
|
||||||
wonCards team (Piles _ pld _) = filterMap (f . getPile) getCard pld
|
addToHand Hand1 card ps = ps { _hand1 = (CardS card (P Hand1)) : (_hand1 ps) }
|
||||||
where f (Won _ tm) = tm == team
|
addToHand Hand2 card ps = ps { _hand2 = (CardS card (P Hand2)) : (_hand2 ps) }
|
||||||
f _ = False
|
addToHand Hand3 card ps = ps { _hand3 = (CardS card (P Hand3)) : (_hand3 ps) }
|
||||||
|
|
||||||
|
playCard :: HasCard c => Hand -> c -> Piles -> Piles
|
||||||
|
playCard hand card' ps = (removeFromHand hand card ps) { _table = (CardS card (P hand)) : _table ps }
|
||||||
|
where card = toCard card'
|
||||||
|
|
||||||
|
unplayCard :: Hand -> Card -> Team -> Piles -> Piles
|
||||||
|
unplayCard hand card winner ps
|
||||||
|
| null table = case winner of
|
||||||
|
Team -> ps' { _table = tail $ take 3 (_wonTeam ps), _wonTeam = drop 3 (_wonTeam ps) }
|
||||||
|
Single -> ps' { _table = tail $ take 3 (_wonSingle ps), _wonSingle = drop 3 (_wonSingle ps) }
|
||||||
|
| otherwise = ps' { _table = tail (_table ps) }
|
||||||
|
where ps' = addToHand hand card ps
|
||||||
|
table = tableCards ps
|
||||||
|
|
||||||
|
wonCards :: Team -> Piles -> [CardS Owner]
|
||||||
|
wonCards Team = _wonTeam
|
||||||
|
wonCards Single = _wonSingle
|
||||||
|
|
||||||
cleanTable :: Team -> Piles -> Piles
|
cleanTable :: Team -> Piles -> Piles
|
||||||
cleanTable winner ps@(Piles hs pld skt) = Piles hs pld' skt
|
cleanTable Team ps = ps { _table = [], _wonTeam = _table ps ++ _wonTeam ps }
|
||||||
where table = tableCards ps
|
cleanTable Single ps = ps { _table = [], _wonSingle = _table ps ++ _wonSingle ps }
|
||||||
pld' = map (winCard winner) pld
|
|
||||||
|
|
||||||
tableCards :: Piles -> [Card]
|
tableCards :: Piles -> [CardS Owner]
|
||||||
tableCards (Piles _ pld _) = filterMap (f . getPile) getCard pld
|
tableCards = _table
|
||||||
where f (Table _) = True
|
|
||||||
f _ = False
|
|
||||||
|
|
||||||
tableCardsS :: Piles -> [CardS Played]
|
handEmpty :: Hand -> Piles -> Bool
|
||||||
tableCardsS (Piles _ pld _) = filter (f . getPile) pld
|
handEmpty Hand1 = null . _hand1
|
||||||
where f (Table _) = True
|
handEmpty Hand2 = null . _hand2
|
||||||
f _ = False
|
handEmpty Hand3 = null . _hand3
|
||||||
|
|
||||||
handCards :: Hand -> Piles -> [Card]
|
handCards :: Hand -> Piles -> [CardS Owner]
|
||||||
handCards hand (Piles hs _ _) = filterMap ((==hand) . getPile) getCard hs
|
handCards Hand1 = _hand1
|
||||||
|
handCards Hand2 = _hand2
|
||||||
|
handCards Hand3 = _hand3
|
||||||
|
|
||||||
|
allowed :: Hand -> Colour -> Maybe Colour -> Piles -> [CardS Owner]
|
||||||
|
allowed hand trCol turnCol ps
|
||||||
|
| null sameColour = cards
|
||||||
|
| otherwise = sameColour
|
||||||
|
where cards = handCards hand ps
|
||||||
|
sameColour = filter (\ca -> effectiveColour trCol ca `equals` turnCol) cards
|
||||||
|
|
||||||
skatCards :: Piles -> [Card]
|
skatCards :: Piles -> [Card]
|
||||||
skatCards (Piles _ _ skat) = map getCard skat
|
skatCards = map getCard . _skat
|
||||||
|
|
||||||
|
emptyPiles :: [Card] -> [Card] -> [Card] -> [Card] -> Piles
|
||||||
|
emptyPiles h1 h2 h3 skt = makePiles h1 h2 h3 [] skt
|
||||||
|
|
||||||
putAt :: p -> Card -> CardS p
|
putAt :: p -> Card -> CardS p
|
||||||
putAt = flip CardS
|
putAt = flip CardS
|
||||||
|
|
||||||
|
makePiles :: [Card] -> [Card] -> [Card] -> [CardS Owner] -> [Card] -> Piles
|
||||||
|
makePiles h1 h2 h3 table skt = Piles h1' h2' h3' table [] [] skt'
|
||||||
|
where h1' = map (putAt $ P Hand1) h1
|
||||||
|
h2' = map (putAt $ P Hand2) h2
|
||||||
|
h3' = map (putAt $ P Hand3) h3
|
||||||
|
skt' = map (putAt S) skt
|
||||||
|
|
||||||
distribute :: [Card] -> Piles
|
distribute :: [Card] -> Piles
|
||||||
distribute cards = Piles hands [] (map (putAt SkatP) skt)
|
distribute cards = emptyPiles hand1 hand2 hand3 skt
|
||||||
where round1 = chunksOf 3 (take 9 cards)
|
where round1 = chunksOf 3 (take 9 cards)
|
||||||
skt = take 2 $ drop 9 cards
|
skt = take 2 $ drop 9 cards
|
||||||
round2 = chunksOf 4 (take 12 $ drop 11 cards)
|
round2 = chunksOf 4 (take 12 $ drop 11 cards)
|
||||||
@@ -120,6 +171,3 @@ distribute cards = Piles hands [] (map (putAt SkatP) skt)
|
|||||||
hand1 = concatMap (!! 0) [round1, round2, round3]
|
hand1 = concatMap (!! 0) [round1, round2, round3]
|
||||||
hand2 = concatMap (!! 1) [round1, round2, round3]
|
hand2 = concatMap (!! 1) [round1, round2, round3]
|
||||||
hand3 = concatMap (!! 2) [round1, round2, round3]
|
hand3 = concatMap (!! 2) [round1, round2, round3]
|
||||||
hands = map (putAt Hand1) hand1
|
|
||||||
++ map (putAt Hand2) hand2
|
|
||||||
++ map (putAt Hand3) hand3
|
|
||||||
|
|||||||
+4
-4
@@ -18,11 +18,11 @@ class (Monad m, MonadIO m, MonadPlayer m) => MonadPlayerOpen m where
|
|||||||
class Player p where
|
class Player p where
|
||||||
team :: p -> Team
|
team :: p -> Team
|
||||||
hand :: p -> Hand
|
hand :: p -> Hand
|
||||||
chooseCard :: MonadPlayer m
|
chooseCard :: (HasCard c, MonadPlayer m)
|
||||||
=> p
|
=> p
|
||||||
-> [CardS Played]
|
-> [CardS Played]
|
||||||
-> [CardS Played]
|
-> [CardS Played]
|
||||||
-> [Card]
|
-> [c]
|
||||||
-> m (Card, p)
|
-> m (Card, p)
|
||||||
onCardPlayed :: MonadPlayer m
|
onCardPlayed :: MonadPlayer m
|
||||||
=> p
|
=> p
|
||||||
@@ -34,10 +34,10 @@ class Player p where
|
|||||||
-> m Card
|
-> m Card
|
||||||
chooseCardOpen p = do
|
chooseCardOpen p = do
|
||||||
piles <- showPiles
|
piles <- showPiles
|
||||||
let table = tableCardsS piles
|
let table = tableCards piles
|
||||||
fallen = played piles
|
fallen = played piles
|
||||||
myCards = handCards (hand p) piles
|
myCards = handCards (hand p) piles
|
||||||
fmap fst $ chooseCard p table fallen myCards
|
fst <$> chooseCard p table fallen myCards
|
||||||
onGameResults :: MonadIO m
|
onGameResults :: MonadIO m
|
||||||
=> p
|
=> p
|
||||||
-> (Int, Int)
|
-> (Int, Int)
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ module Skat.Player.Utils (
|
|||||||
|
|
||||||
import Skat.Player
|
import Skat.Player
|
||||||
import qualified Skat.Card as C
|
import qualified Skat.Card as C
|
||||||
import Skat.Card (Card)
|
import Skat.Card (Card, HasCard(..))
|
||||||
|
|
||||||
isAllowed :: MonadPlayer m => [Card] -> Card -> m Bool
|
isAllowed :: (HasCard c, MonadPlayer m) => [c] -> c -> m Bool
|
||||||
isAllowed hand card = do
|
isAllowed hand card = do
|
||||||
trCol <- trumpColour
|
trCol <- trumpColour
|
||||||
turnCol <- turnColour
|
turnCol <- turnColour
|
||||||
|
|||||||
+6
-2
@@ -1,8 +1,12 @@
|
|||||||
module Skat.Render where
|
module Skat.Render where
|
||||||
|
|
||||||
import Data.List
|
import Data.List
|
||||||
|
import Data.Vector (Vector, toList)
|
||||||
|
|
||||||
import Skat.Card
|
import Skat.Card
|
||||||
|
|
||||||
render :: [Card] -> IO ()
|
render :: HasCard c => [c] -> IO ()
|
||||||
render = putStrLn . intercalate "\n" . zipWith (\n c -> show n ++ ") " ++ show c) [0..]
|
render = putStrLn . intercalate "\n" . zipWith (\n c -> show n ++ ") " ++ show c) [0..] . map toCard
|
||||||
|
|
||||||
|
renderVector :: Vector Card -> IO ()
|
||||||
|
renderVector = render . toList
|
||||||
|
|||||||
+2
-1
@@ -4,6 +4,7 @@ import System.Random
|
|||||||
import Text.Read
|
import Text.Read
|
||||||
import qualified Data.ByteString.Char8 as B (ByteString, unpack, pack)
|
import qualified Data.ByteString.Char8 as B (ByteString, unpack, pack)
|
||||||
import qualified Data.Text as T (Text, unpack, pack)
|
import qualified Data.Text as T (Text, unpack, pack)
|
||||||
|
import Data.List (foldl')
|
||||||
|
|
||||||
shuffle :: StdGen -> [a] -> [a]
|
shuffle :: StdGen -> [a] -> [a]
|
||||||
shuffle g xs = shuffle' (randoms g) xs
|
shuffle g xs = shuffle' (randoms g) xs
|
||||||
@@ -31,7 +32,7 @@ remove pred xs = foldr f (undefined, []) xs
|
|||||||
|
|
||||||
filterMap :: (a -> Bool) -> (a -> b) -> [a] -> [b]
|
filterMap :: (a -> Bool) -> (a -> b) -> [a] -> [b]
|
||||||
filterMap pred f as = foldr g [] as
|
filterMap pred f as = foldr g [] as
|
||||||
where g a bs = if pred a then f a : bs else bs
|
where g a bs = if pred a then (f $! a) : bs else bs
|
||||||
|
|
||||||
--filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
|
--filterM :: Monad m => (a -> m Bool) -> [a] -> m [a]
|
||||||
--filterM _ [] = return []
|
--filterM _ [] = return []
|
||||||
|
|||||||
Reference in New Issue
Block a user