Просмотр исходного кода

implement grand and null mechanics, fix some online player issues

master
flavis 6 лет назад
Родитель
Сommit
2567bf4cd9
17 измененных файлов: 291 добавлений и 173 удалений
  1. +8
    -7
      app/Main.hs
  2. +3
    -2
      app/TestEnvs.hs
  3. +1
    -1
      package.yaml
  4. +2
    -1
      skat.cabal
  5. +8
    -7
      src/Skat.hs
  6. +1
    -1
      src/Skat/AI/Human.hs
  7. +17
    -23
      src/Skat/AI/Online.hs
  8. +19
    -16
      src/Skat/AI/Rulebased.hs
  9. +6
    -5
      src/Skat/AI/Stupid.hs
  10. +75
    -4
      src/Skat/Bidding.hs
  11. +79
    -25
      src/Skat/Card.hs
  12. +20
    -23
      src/Skat/Matches.hs
  13. +8
    -27
      src/Skat/Operations.hs
  14. +3
    -3
      src/Skat/Pile.hs
  15. +2
    -14
      src/Skat/Player.hs
  16. +4
    -4
      src/Skat/Player/Utils.hs
  17. +35
    -10
      src/Skat/Preperation.hs

+ 8
- 7
app/Main.hs Просмотреть файл

@@ -12,6 +12,7 @@ import Skat.Card
import Skat.Operations import Skat.Operations
import Skat.Player import Skat.Player
import Skat.Pile import Skat.Pile
import Skat.Bidding


import Skat.AI.Stupid import Skat.AI.Stupid
import Skat.AI.Online import Skat.AI.Online
@@ -37,7 +38,7 @@ runAI = do
env <- shuffledEnv env <- shuffledEnv
let ps = piles env let ps = piles env
cs = handCards Hand3 ps cs = handCards Hand3 ps
trs = filter (isTrump Spades) cs
trs = filter (isTrump $ TrumpColour Spades) cs
if length trs >= 5 && any ((==32) . getID) cs if length trs >= 5 && any ((==32) . getID) cs
then do then do
pts <- fst <$> evalStateT turn env pts <- fst <$> evalStateT turn env
@@ -46,11 +47,11 @@ runAI = do
else runAI else runAI


env :: SkatEnv env :: SkatEnv
env = SkatEnv piles Nothing Spades playersExamp Hand1
env = SkatEnv piles Nothing (Colour Spades Einfach) playersExamp Hand1
where piles = distribute allCards where piles = distribute allCards


envStupid :: SkatEnv envStupid :: SkatEnv
envStupid = SkatEnv piles Nothing Spades pls2 Hand1
envStupid = SkatEnv piles Nothing (Colour Spades Einfach) pls2 Hand1
where piles = distribute allCards where piles = distribute allCards


playersExamp :: Players playersExamp :: Players
@@ -68,22 +69,22 @@ pls2 = Players
shuffledEnv :: IO SkatEnv shuffledEnv :: IO SkatEnv
shuffledEnv = do shuffledEnv = do
cards <- shuffleCards cards <- shuffleCards
return $ SkatEnv (distribute cards) Nothing Spades playersExamp Hand1
return $ SkatEnv (distribute cards) Nothing (Colour Spades Einfach) playersExamp Hand1


shuffledEnv2 :: IO SkatEnv shuffledEnv2 :: IO SkatEnv
shuffledEnv2 = do shuffledEnv2 = do
cards <- shuffleCards cards <- shuffleCards
return $ SkatEnv (distribute cards) Nothing Spades pls2 Hand1
return $ SkatEnv (distribute cards) Nothing (Colour Spades Einfach) pls2 Hand1


env2 :: SkatEnv env2 :: SkatEnv
env2 = SkatEnv piles Nothing Hearts playersExamp Hand2
env2 = SkatEnv piles Nothing (Colour Hearts Einfach) playersExamp Hand2
where hand1 = [Card Eight Hearts, Card Queen Hearts, 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 Ten 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]
piles = emptyPiles hand1 hand2 hand3 [] piles = emptyPiles hand1 hand2 hand3 []


env3 :: SkatEnv env3 :: SkatEnv
env3 = SkatEnv piles Nothing Diamonds pls2 Hand3
env3 = SkatEnv piles Nothing (Colour Diamonds Einfach) pls2 Hand3
where hand1 = [ Card Jack Diamonds, Card Jack Clubs, Card Nine Spades, Card King Spades 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 Seven Diamonds, Card Nine Diamonds, Card Seven Clubs, Card Eight Clubs
, Card Ten Clubs, Card Eight Hearts ] , Card Ten Clubs, Card Eight Hearts ]


+ 3
- 2
app/TestEnvs.hs Просмотреть файл

@@ -5,6 +5,7 @@ import Skat.Card
import Skat.Pile import Skat.Pile
import Skat.Player import Skat.Player
import Skat.AI.Stupid import Skat.AI.Stupid
import Skat.Bidding


pls2 :: Players pls2 :: Players
pls2 = Players pls2 = Players
@@ -13,7 +14,7 @@ pls2 = Players
(PL $ Stupid Single Hand3) (PL $ Stupid Single Hand3)


env3 :: SkatEnv env3 :: SkatEnv
env3 = SkatEnv piles Nothing Diamonds pls2 Hand3
env3 = SkatEnv piles Nothing (Colour Diamonds Einfach) pls2 Hand3
where hand1 = [ Card Jack Diamonds, Card Jack Clubs, Card Nine Spades, Card King Spades 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 Seven Diamonds, Card Nine Diamonds, Card Seven Clubs, Card Eight Clubs
, Card Ten Clubs, Card Eight Hearts ] , Card Ten Clubs, Card Eight Hearts ]
@@ -28,4 +29,4 @@ env3 = SkatEnv piles Nothing Diamonds pls2 Hand3
shuffledEnv2 :: IO SkatEnv shuffledEnv2 :: IO SkatEnv
shuffledEnv2 = do shuffledEnv2 = do
cards <- shuffleCards cards <- shuffleCards
return $ SkatEnv (distribute cards) Nothing Spades pls2 Hand1
return $ SkatEnv (distribute cards) Nothing (Colour Spades Einfach) pls2 Hand1

+ 1
- 1
package.yaml Просмотреть файл

@@ -1,5 +1,5 @@
name: skat name: skat
version: 0.1.0.5
version: 0.1.0.7
github: "githubuser/skat" github: "githubuser/skat"
license: BSD3 license: BSD3
author: "flavis" author: "flavis"


+ 2
- 1
skat.cabal Просмотреть файл

@@ -4,10 +4,10 @@ cabal-version: 1.12
-- --
-- see: https://github.com/sol/hpack -- see: https://github.com/sol/hpack
-- --
-- hash: 9c412ae20820c69f342fb431118c3d2be6a5461e1b5a521d92c1546f163ee94a


name: skat name: skat
version: 0.1.0.5
version: 0.1.0.7
description: Please see the README on Gitea at <https://git.flavigny.de/christian/skat> description: Please see the README on Gitea at <https://git.flavigny.de/christian/skat>
homepage: https://github.com/githubuser/skat#readme homepage: https://github.com/githubuser/skat#readme
bug-reports: https://github.com/githubuser/skat/issues bug-reports: https://github.com/githubuser/skat/issues


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

@@ -10,13 +10,14 @@ import Data.List
import Data.Vector (Vector) import Data.Vector (Vector)


import Skat.Card import Skat.Card
import Skat.Bidding
import Skat.Pile import Skat.Pile
import Skat.Player (Players) import Skat.Player (Players)
import qualified Skat.Player as P import qualified Skat.Player as P


data SkatEnv = SkatEnv { piles :: Piles data SkatEnv = SkatEnv { piles :: Piles
, turnColour :: Maybe Colour
, trumpColour :: Colour
, turnColour :: Maybe TurnColour
, game :: Game
, players :: Players , players :: Players
, currentHand :: Hand } , currentHand :: Hand }
deriving Show deriving Show
@@ -24,7 +25,7 @@ data SkatEnv = SkatEnv { piles :: Piles
type Skat = StateT SkatEnv IO type Skat = StateT SkatEnv IO


instance P.MonadPlayer Skat where instance P.MonadPlayer Skat where
trumpColour = gets trumpColour
trump = gets $ getTrump . game
turnColour = gets turnColour turnColour = gets turnColour
showSkat p = case P.team p of showSkat p = case P.team p of
Single -> fmap (Just . skatCards) $ gets piles Single -> fmap (Just . skatCards) $ gets piles
@@ -44,19 +45,19 @@ modifyPlayers :: (Players -> Players) -> Skat ()
modifyPlayers f = modify g modifyPlayers f = modify g
where g env@(SkatEnv {players}) = env { players = f players } where g env@(SkatEnv {players}) = env { players = f players }


setTurnColour :: Maybe Colour -> SkatEnv -> SkatEnv
setTurnColour :: Maybe TurnColour -> SkatEnv -> SkatEnv
setTurnColour col sk = sk { turnColour = col } setTurnColour col sk = sk { turnColour = col }


setCurrentHand :: Hand -> SkatEnv -> SkatEnv setCurrentHand :: Hand -> SkatEnv -> SkatEnv
setCurrentHand hand sk = sk { currentHand = hand } setCurrentHand hand sk = sk { currentHand = hand }


mkSkatEnv :: Piles -> Maybe Colour -> Colour -> Players -> Hand -> SkatEnv
mkSkatEnv :: Piles -> Maybe TurnColour -> Game -> Players -> Hand -> SkatEnv
mkSkatEnv = SkatEnv mkSkatEnv = SkatEnv


allowedCards :: Skat [CardS Owner] allowedCards :: Skat [CardS Owner]
allowedCards = do allowedCards = do
curHand <- gets currentHand curHand <- gets currentHand
pls <- gets players pls <- gets players
turnCol <- gets turnColour
trumpCol <- gets trumpColour
turnCol <- P.turnColour
trumpCol <- P.trump
getp $ allowed curHand trumpCol turnCol getp $ allowed curHand trumpCol turnCol

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

@@ -16,7 +16,7 @@ instance Player Human where
team = getTeam team = getTeam
hand = getHand hand = getHand
chooseCard p table _ hand = do chooseCard p table _ hand = do
trumpCol <- trumpColour
trumpCol <- trump
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) (map toCard possible) (map toCard hand) c <- liftIO $ askIO (map getCard table) (map toCard possible) (map toCard hand)


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

@@ -6,7 +6,7 @@ module Skat.AI.Online where


import Control.Monad.Reader import Control.Monad.Reader
import Control.Concurrent.Chan import Control.Concurrent.Chan
import Data.Aeson
import Data.Aeson hiding (Result)
import Data.Maybe import Data.Maybe
import qualified Data.ByteString.Lazy.Char8 as BS import qualified Data.ByteString.Lazy.Char8 as BS


@@ -49,8 +49,6 @@ instance Communicator c => Player (OnlineEnv c) where
hand = getHand hand = getHand
chooseCard p table _ hand = runReaderT (choose table hand) p >>= \c -> return (c, p) chooseCard p table _ hand = runReaderT (choose table hand) p >>= \c -> return (c, p)
onCardPlayed p c = runReaderT (cardPlayed c) p >> return p onCardPlayed p c = runReaderT (cardPlayed c) p >> return p
onGameResults p res = runReaderT (onResults res) p
onGameStart p singlePlayer = runReaderT (onStartOnline singlePlayer) p


instance Communicator c => Bidder (PrepOnline c) where instance Communicator c => Bidder (PrepOnline c) where
hand = prepHand hand = prepHand
@@ -87,8 +85,12 @@ instance Communicator c => Bidder (PrepOnline c) where
Nothing -> askSkat p bid cards Nothing -> askSkat p bid cards
toPlayer p tm = PL $ OnlineEnv tm (prepHand p) (prepConnection p) toPlayer p tm = PL $ OnlineEnv tm (prepHand p) (prepConnection p)
onStart p = do onStart p = do
let cards = prepCards p
let cards = sortRender Jacks $ prepCards p
liftIO $ send (prepConnection p) (BS.unpack $ encode $ CardsQuery cards) liftIO $ send (prepConnection p) (BS.unpack $ encode $ CardsQuery cards)
onResult p res =
liftIO $ send (prepConnection p) (BS.unpack $ encode $ GameResultsQuery res)
onGame p game sglPlayer = do
liftIO $ send (prepConnection p) (BS.unpack $ encode $ GameStartQuery game sglPlayer)


type Online a m = ReaderT (OnlineEnv a) m type Online a m = ReaderT (OnlineEnv a) m


@@ -101,13 +103,13 @@ instance (Communicator c, MonadIO m) => MonadClient (Online c m) where
liftIO $ receive conn liftIO $ receive conn


instance MonadPlayer m => MonadPlayer (Online a m) where instance MonadPlayer m => MonadPlayer (Online a m) where
trumpColour = lift $ trumpColour
trump = lift $ trump
turnColour = lift $ turnColour turnColour = lift $ turnColour
showSkat = lift . showSkat showSkat = lift . showSkat


choose :: HasCard a => (Communicator c, MonadPlayer m) => [CardS Played] -> [a] -> 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'
let hand = sortRender Jacks $ 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
@@ -119,21 +121,12 @@ choose table hand' = do
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)


onResults :: (Communicator c, MonadIO m) => (Int, Int) -> Online c m ()
onResults (sgl, tm) = query (BS.unpack $ encode $ GameResultsQuery sgl tm)

onStartOnline :: (Communicator c, MonadPlayer m) => Hand -> Online c m ()
onStartOnline singlePlayer = do
trCol <- trumpColour
ownHand <- asks getHand
query (BS.unpack $ encode $ GameStartQuery trCol ownHand singlePlayer)

-- | QUERIES AND RESPONSES -- | QUERIES AND RESPONSES
data Query = ChooseQuery [Card] [CardS Played] data Query = ChooseQuery [Card] [CardS Played]
| CardPlayedQuery (CardS Played) | CardPlayedQuery (CardS Played)
| GameResultsQuery Int Int
| GameStartQuery Colour Hand Hand
| GameResultsQuery Result
| GameStartQuery Game Hand
| BidQuery Hand Bid | BidQuery Hand Bid
| BidResponseQuery Hand Bid | BidResponseQuery Hand Bid
| AskGameQuery Bid | AskGameQuery Bid
@@ -153,15 +146,16 @@ instance ToJSON Query where
object ["query" .= ("choose_card" :: String), "hand" .= hand, "table" .= table] object ["query" .= ("choose_card" :: String), "hand" .= hand, "table" .= table]
toJSON (CardPlayedQuery card) = toJSON (CardPlayedQuery card) =
object ["query" .= ("card_played" :: String), "card" .= card] object ["query" .= ("card_played" :: String), "card" .= card]
toJSON (GameResultsQuery sgl tm) =
object ["query" .= ("results" :: String), "single" .= sgl, "team" .= tm]
toJSON (GameStartQuery trumps handNo sglPlayer) =
object ["query" .= ("start_game" :: String), "trumps" .= show trumps,
"hand" .= toInt handNo, "single" .= toInt sglPlayer ]
toJSON (GameResultsQuery result) =
object ["query" .= ("results" :: String), "result" .= result]
toJSON (GameStartQuery game sglPlayer) =
object [ "query" .= ("start_game" :: String)
, "game" .= game
, "single" .= toInt sglPlayer ]
toJSON (BidQuery hand bid) = toJSON (BidQuery hand bid) =
object ["query" .= ("bid" :: String), "whom" .= show hand, "current" .= bid] object ["query" .= ("bid" :: String), "whom" .= show hand, "current" .= bid]
toJSON (BidResponseQuery hand bid) = toJSON (BidResponseQuery hand bid) =
object ["query" .= ("bid_response" :: String), "from" .= show hand ]
object ["query" .= ("bid_response" :: String), "from" .= show hand, "bid" .= bid ]
toJSON (AskHandQuery) = toJSON (AskHandQuery) =
object ["query" .= ("play_hand" :: String)] object ["query" .= ("play_hand" :: String)]
toJSON (AskSkatQuery cards bid) = toJSON (AskSkatQuery cards bid) =


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

@@ -26,6 +26,7 @@ import Skat (Skat, modifyp, mkSkatEnv)
import Skat.Operations import Skat.Operations
import qualified Skat.AI.Minmax as Minmax import qualified Skat.AI.Minmax as Minmax
import qualified Skat.AI.Stupid as Stupid (Stupid(..)) import qualified Skat.AI.Stupid as Stupid (Stupid(..))
import Skat.Bidding


data AIEnv = AIEnv { getTeam :: Team data AIEnv = AIEnv { getTeam :: Team
, getHand :: Hand , getHand :: Hand
@@ -55,8 +56,8 @@ modifyg f = modify g
type AI m = StateT AIEnv m type AI m = StateT AIEnv m


instance MonadPlayer m => MonadPlayer (AI m) where instance MonadPlayer m => MonadPlayer (AI m) where
trumpColour = lift $ trumpColour
turnColour = lift $ turnColour
trump = lift trump
turnColour = lift turnColour
showSkat = lift . showSkat showSkat = lift . showSkat


instance MonadPlayerOpen m => MonadPlayerOpen (AI m) where instance MonadPlayerOpen m => MonadPlayerOpen (AI m) where
@@ -65,7 +66,7 @@ instance MonadPlayerOpen m => MonadPlayerOpen (AI m) where
type Simulator m = ReaderT Piles (AI m) type Simulator m = ReaderT Piles (AI m)


instance MonadPlayer m => MonadPlayer (Simulator m) where instance MonadPlayer m => MonadPlayer (Simulator m) where
trumpColour = lift $ trumpColour
trump = lift trump
turnColour = lift $ turnColour turnColour = lift $ turnColour
showSkat = lift . showSkat showSkat = lift . showSkat


@@ -112,15 +113,15 @@ has hand cs = M.mapWithKey f
| card `elem` cs = [H hand] | card `elem` cs = [H hand]
| otherwise = hands | otherwise = hands


hasNoLonger :: MonadPlayer m => Hand -> Colour -> AI m ()
hasNoLonger :: MonadPlayer m => Hand -> TurnColour -> AI m ()
hasNoLonger hand colour = do hasNoLonger hand colour = do
trCol <- trumpColour
trCol <- trump
modifyg $ hasNoLonger_ trCol hand colour modifyg $ hasNoLonger_ trCol hand colour


hasNoLonger_ :: Colour -> Hand -> Colour -> Guess -> Guess
hasNoLonger_ trColour hand effCol = M.mapWithKey f
hasNoLonger_ :: Trump -> Hand -> TurnColour -> Guess -> Guess
hasNoLonger_ trump hand effCol = M.mapWithKey f
where f card hands where f card hands
| effectiveColour trColour card == effCol && (H hand) `elem` hands = filter (/=H hand) hands
| effectiveColour trump card == effCol && (H hand) `elem` hands = filter (/=H hand) hands
| otherwise = hands | otherwise = hands


isSkat :: [Card] -> Guess -> Guess isSkat :: [Card] -> Guess -> Guess
@@ -136,7 +137,7 @@ analyzeTurn (c1, c2, c3) = do
modifyg (getCard c1 `hasBeenPlayed`) modifyg (getCard c1 `hasBeenPlayed`)
modifyg (getCard c2 `hasBeenPlayed`) modifyg (getCard c2 `hasBeenPlayed`)
modifyg (getCard c3 `hasBeenPlayed`) modifyg (getCard c3 `hasBeenPlayed`)
trCol <- trumpColour
trCol <- trump
let turnCol = getColour $ getCard c1 let turnCol = getColour $ getCard c1
demanded = effectiveColour trCol (getCard c1) demanded = effectiveColour trCol (getCard c1)
col2 = effectiveColour trCol (getCard c2) col2 = effectiveColour trCol (getCard c2)
@@ -218,7 +219,7 @@ onPlayed :: MonadPlayer m => CardS Played -> AI m ()
onPlayed c = do onPlayed c = do
liftIO $ print c liftIO $ print c
modifyg (getCard c `hasBeenPlayed`) modifyg (getCard c `hasBeenPlayed`)
trCol <- trumpColour
trCol <- trump
turnCol <- turnColour turnCol <- turnColour
let col = effectiveColour trCol (getCard c) let col = effectiveColour trCol (getCard c)
case turnCol of case turnCol of
@@ -308,13 +309,14 @@ chooseSimulating :: (MonadState AIEnv m, MonadPlayerOpen m)
chooseSimulating = do chooseSimulating = do
piles <- showPiles piles <- showPiles
turnCol <- turnColour turnCol <- turnColour
trumpCol <- trumpColour
trumpCol <- trump
myHand <- gets getHand myHand <- gets getHand
depth <- gets simulationDepth 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
-- TODO: fix
env = mkSkatEnv piles turnCol undefined ps myHand
liftIO $ evalStateT (toCard <$> (Minmax.choose depth :: Skat (CardS Owner))) env liftIO $ evalStateT (toCard <$> (Minmax.choose depth :: Skat (CardS Owner))) env


simulate :: (MonadState AIEnv m, MonadPlayerOpen m) simulate :: (MonadState AIEnv m, MonadPlayerOpen m)
@@ -323,7 +325,7 @@ simulate card = do
-- retrieve all relevant info -- retrieve all relevant info
piles <- showPiles piles <- showPiles
turnCol <- turnColour turnCol <- turnColour
trumpCol <- trumpColour
trumpCol <- trump
myTeam <- gets getTeam myTeam <- gets getTeam
myHand <- gets getHand myHand <- gets getHand
depth <- gets simulationDepth depth <- gets simulationDepth
@@ -334,7 +336,8 @@ simulate card = do
(PL $ mkAIEnv Team Hand1 newDepth) (PL $ mkAIEnv Team Hand1 newDepth)
(PL $ mkAIEnv Team Hand2 newDepth) (PL $ mkAIEnv Team Hand2 newDepth)
(PL $ mkAIEnv Single Hand3 newDepth) (PL $ mkAIEnv Single Hand3 newDepth)
env = mkSkatEnv piles turnCol trumpCol ps (next myHand)
-- TODO: fix
env = mkSkatEnv piles turnCol undefined 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 myHand card modifyp $ playCard myHand card
@@ -357,7 +360,7 @@ predictValue (own, others) = do
potential :: (MonadState AIEnv m, MonadPlayerOpen m, HasCard c) potential :: (MonadState AIEnv m, MonadPlayerOpen m, HasCard c)
=> [c] -> m Int => [c] -> m Int
potential cs = do potential cs = do
tr <- trumpColour
tr <- trump
let trs = filter (isTrump tr) cs let trs = filter (isTrump tr) cs
value = count . map toCard $ cs value = count . map toCard $ cs
positions <- filter (==0) <$> mapM (position . toCard) cs positions <- filter (==0) <$> mapM (position . toCard) cs
@@ -366,7 +369,7 @@ potential cs = do
position :: (MonadState AIEnv m, MonadPlayer m) position :: (MonadState AIEnv m, MonadPlayer m)
=> Card -> m Int => Card -> m Int
position card = do position card = do
tr <- trumpColour
tr <- trump
guess <- gets guess guess <- gets guess
let effCol = effectiveColour tr card let effCol = effectiveColour tr card
l = M.toList guess l = M.toList guess


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

@@ -4,6 +4,7 @@ import Skat.Player
import Skat.Pile import Skat.Pile
import Skat.Card import Skat.Card
import Skat.Preperation import Skat.Preperation
import Skat.Bidding


data Stupid = Stupid { getTeam :: Team data Stupid = Stupid { getTeam :: Team
, getHand :: Hand } , getHand :: Hand }
@@ -13,7 +14,7 @@ instance Player Stupid where
team = getTeam team = getTeam
hand = getHand hand = getHand
chooseCard p _ _ hand = do chooseCard p _ _ hand = do
trumpCol <- trumpColour
trumpCol <- trump
turnCol <- turnColour turnCol <- turnColour
let possible = filter (isAllowed trumpCol turnCol hand) hand let possible = filter (isAllowed trumpCol turnCol hand) hand
return (toCard $ head possible, p) return (toCard $ head possible, p)
@@ -24,10 +25,10 @@ newtype NoBidder = NoBidder Hand
-- | no bidding from that player -- | no bidding from that player
instance Bidder NoBidder where instance Bidder NoBidder where
hand (NoBidder h) = h hand (NoBidder h) = h
askBid _ _ _ = return Nothing
askResponse _ _ _ = return False
askGame _ _ = undefined -- never called
askHand _ _ = return False -- never called
askBid _ _ bid = return $ Just 20
askResponse _ _ bid = if bid < 24 then return True else return False
askGame _ _ = return $ Grand Hand
askHand _ _ = return True
askSkat _ _ _ = undefined -- never called askSkat _ _ _ = undefined -- never called
toPlayer (NoBidder h) team = PL $ Stupid team h toPlayer (NoBidder h) team = PL $ Stupid team h
onStart _ = return () onStart _ = return ()

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

@@ -1,15 +1,17 @@
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedStrings #-}


module Skat.Bidding ( module Skat.Bidding (
biddingScore, Game(..), Modifier(..), isHand
biddingScore, Game(..), Modifier(..), isHand, getTrump, Result(..),
getResults
) where ) where


import Data.Aeson hiding (Null)
import Data.Aeson hiding (Null, Result)


import Skat.Card import Skat.Card
import Data.List (sortOn) import Data.List (sortOn)
import Data.Ord (Down(..)) import Data.Ord (Down(..))
import Control.Monad import Control.Monad
import Skat.Pile


-- | different game types -- | different game types
data Game = Colour Colour Modifier data Game = Colour Colour Modifier
@@ -20,6 +22,16 @@ data Game = Colour Colour Modifier
| NullOuvertHand | NullOuvertHand
deriving (Show, Eq) deriving (Show, Eq)


instance ToJSON Game where
toJSON (Grand mod) =
object ["game" .= ("grand" :: String), "modifier" .= show mod]
toJSON (Colour col mod) =
object ["game" .= ("colour" :: String), "modifier" .= show mod, "colour" .= show col]
toJSON Null = object ["game" .= ("null" :: String)]
toJSON NullHand = object ["game" .= ("nullhand" :: String)]
toJSON NullOuvert = object ["game" .= ("nullouvert" :: String)]
toJSON NullOuvertHand = object ["game" .= ("nullouverthand" :: String)]

instance FromJSON Game where instance FromJSON Game where
parseJSON = withObject "Game" $ \v -> do parseJSON = withObject "Game" $ \v -> do
gamekind <- v .: "game" gamekind <- v .: "game"
@@ -118,6 +130,65 @@ spitzen game cards


-- | get all trumps for a given game out of a hand of cards -- | get all trumps for a given game out of a hand of cards
getTrumps :: HasCard c => Game -> [c] -> [Card] getTrumps :: HasCard c => Game -> [c] -> [Card]
getTrumps (Grand _) cards = sortOn Down $ filter ((==Jack) . getType) $ map toCard cards
getTrumps (Colour col _) cards = sortOn Down $ filter (isTrump col) $ map toCard cards
getTrumps (Grand _) cards = sortOn Down $ filter (isTrump Jacks) $ map toCard cards
getTrumps (Colour col _) cards = sortOn Down $ filter (isTrump $ TrumpColour col) $ map toCard cards
getTrumps _ _ = [] getTrumps _ _ = []

-- | get trump for a given game
getTrump :: Game -> Trump
getTrump (Colour col _) = TrumpColour col
getTrump (Grand _) = Jacks
getTrump _ = None

data Result = Result Game Int Int Int
deriving (Show, Eq)

instance ToJSON Result where
toJSON (Result game points sgl tm) =
object ["game" .= game, "points" .= points, "single" .= sgl, "team" .= tm]

isSchwarz :: Team -> Piles -> Bool
isSchwarz tm = null . wonCards tm

hasWon :: Game -> Piles -> (Bool, Game)
hasWon Null ps = (Single `isSchwarz` ps, Null)
hasWon NullHand ps = (Single `isSchwarz` ps, NullHand)
hasWon NullOuvert ps = (Single `isSchwarz` ps, NullOuvert)
hasWon NullOuvertHand ps = (Single `isSchwarz` ps, NullOuvertHand)
hasWon (Colour col mod) ps = let (b, mod') = meetsCall mod ps
in (b, Colour col mod')
hasWon (Grand mod) ps = let (b, mod') = meetsCall mod ps
in (b, Grand mod')

meetsCall :: Modifier -> Piles -> (Bool, Modifier)
meetsCall Hand ps = case wonByPoints ps of
(b, Schneider) -> (b, HandSchneider)
(b, Schwarz) -> (b, HandSchneiderSchwarz)
(b, Einfach) -> (b, Hand)
meetsCall HandSchneiderAngesagt ps = case wonByPoints ps of
(b, Schneider) -> (b, HandSchneiderAngesagt)
(b, Schwarz) -> (b, HandSchneiderAngesagtSchwarz)
(b, Einfach) -> (False, HandSchneiderAngesagt)
meetsCall HandSchwarzAngesagt ps = case wonByPoints ps of
(b, Schneider) -> (False, HandSchwarzAngesagt)
(b, Schwarz) -> (b, HandSchwarzAngesagt)
(b, Einfach) -> (False, HandSchwarzAngesagt)
meetsCall _ ps = wonByPoints ps

wonByPoints :: Piles -> (Bool, Modifier)
wonByPoints ps
| Team `isSchwarz` ps = (True, Schwarz)
| sgl >= 90 = (True, Schneider)
| Single `isSchwarz` ps = (False, Schwarz)
| sgl <= 30 = (False, Schneider)
| otherwise = (sgl > 60, Einfach)
where (sgl, _) = count ps :: (Int, Int)

-- | get result of game
getResults :: Game -> Hand -> Piles -> Piles -> Result
getResults game sglPlayer before after = Result afterGame score sglPoints teamPoints
where (won, afterGame) = hasWon game after
hand = skatCards before ++ (map toCard $ handCards sglPlayer before)
(sglPoints, teamPoints) = count after
gameScore = biddingScore afterGame hand
score = if won then gameScore else (-2) * gameScore

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

@@ -31,6 +31,16 @@ data Type = Seven
| Jack | Jack
deriving (Eq, Ord, Show, Enum, Read) deriving (Eq, Ord, Show, Enum, Read)


data NullType = NSeven
| NEight
| NNine
| NTen
| NJack
| NQueen
| NKing
| NAce
deriving (Eq, Ord, Show, Enum, Read)

instance Countable Type Int where instance Countable Type Int where
count Ace = 11 count Ace = 11
count Ten = 10 count Ten = 10
@@ -45,6 +55,15 @@ data Colour = Diamonds
| Clubs | Clubs
deriving (Eq, Ord, Show, Enum, Read) deriving (Eq, Ord, Show, Enum, Read)


data Trump = TrumpColour Colour
| Jacks
| None
deriving (Show, Eq)

data TurnColour = TurnColour Colour
| Trump
deriving (Show, Eq)

data Card = Card Type Colour data Card = Card Type Colour
deriving (Eq, Show, Ord, Read) deriving (Eq, Show, Ord, Read)


@@ -98,50 +117,85 @@ instance Countable (S.Set Card) Int where
instance NFData Card where instance NFData Card where
rnf (Card t c) = t `seq` c `seq` () rnf (Card t c) = t `seq` c `seq` ()


equals :: Colour -> Maybe Colour -> Bool
equals :: TurnColour -> Maybe TurnColour -> Bool
equals col (Just x) = col == x equals col (Just x) = col == x
equals col Nothing = True equals col Nothing = True


isTrump :: HasCard c => Colour -> c -> Bool
isTrump trumpCol crd
isTrump :: HasCard c => Trump -> c -> Bool
isTrump None crd = False
isTrump Jacks crd = getType (toCard crd) == Jack
isTrump (TrumpColour trumpCol) crd
| getType (toCard crd) == Jack = True | getType (toCard crd) == Jack = True
| otherwise = getColour (toCard crd) == trumpCol | otherwise = getColour (toCard crd) == trumpCol


effectiveColour :: HasCard c => Colour -> c -> Colour
effectiveColour trumpCol crd = if trump then trumpCol else getColour (toCard crd)
where trump = isTrump trumpCol crd
effectiveColour :: HasCard c => Trump -> c -> TurnColour
effectiveColour trump card
| isTrump trump card = Trump
| otherwise = TurnColour $ getColour (toCard card)


isAllowed :: (Foldable t, HasCard c1, HasCard c2) => Colour -> Maybe Colour -> t c1 -> c2 -> Bool
isAllowed trumpCol turnCol cs crd =
isAllowed :: (Foldable t, HasCard c1, HasCard c2) => Trump -> Maybe TurnColour -> t c1 -> c2 -> Bool
isAllowed trump turnCol cs crd =
if col `equals` turnCol if col `equals` turnCol
then True then True
else not $ F.any (\ca -> effectiveColour trumpCol ca `equals` turnCol && toCard ca /= toCard crd) cs
where col = effectiveColour trumpCol (toCard crd)
else not $ F.any (\ca -> effectiveColour trump ca `equals` turnCol && toCard ca /= toCard crd) cs
where col = effectiveColour trump (toCard crd)


compareCards :: Colour
-> Maybe Colour
compareCards :: Trump
-> Maybe TurnColour
-> Card -> Card
-> Card -> Card
-> Ordering -> Ordering
compareCards _ _ (Card Jack col1) (Card Jack col2) = compare col1 col2 compareCards _ _ (Card Jack col1) (Card Jack col2) = compare col1 col2
compareCards trumpCol turnCol c1@(Card tp1 col1) c2@(Card tp2 col2) =
compareCards trump turnCol c1@(Card tp1 col1) c2@(Card tp2 col2) =
case (trp1, trp2) of case (trp1, trp2) of
(True, True) -> compare tp1 tp2 (True, True) -> compare tp1 tp2
(False, False) -> case compare (col1 `equals` turnCol)
(col2 `equals` turnCol) of
EQ -> compare tp1 tp2
v -> v
(False, False) -> case ( effectiveColour trump c1 `equals` turnCol
, effectiveColour trump c2 `equals` turnCol ) of
(True, True) -> compareTypes trump tp1 tp2
(True, False) -> GT
(False, True) -> LT
_ -> EQ
_ -> compare trp1 trp2 _ -> compare trp1 trp2
where trp1 = isTrump trumpCol c1
trp2 = isTrump trumpCol c2
where trp1 = isTrump trump c1
trp2 = isTrump trump c2


sortCards :: HasCard c => Colour -> Maybe Colour -> [c] -> [c]
sortCards trumpCol turnCol cs = sortBy f cs
where f c1 c2 = compareCards trumpCol turnCol (toCard c1) (toCard c2)
compareRender :: Trump -> Card -> Card -> Ordering
compareRender trump c1@(Card tp1 col1) c2@(Card tp2 col2) =
case (trp1, trp2) of
(True, True) -> compare tp1 tp2
(False, False) -> case compare col1 col2 of
EQ -> compare tp1 tp2
v -> v
_ -> compare trp1 trp2
where trp1 = isTrump trump c1
trp2 = isTrump trump c2


highestCard :: HasCard c => Colour -> Maybe Colour -> [c] -> c
highestCard trumpCol turnCol cs = maximumBy f cs
where f c1 c2 = compareCards trumpCol turnCol (toCard c1) (toCard c2)
compareTypes :: Trump
-> Type
-> Type
-> Ordering
compareTypes None tp1 tp2 = compare (toNullType tp1) (toNullType tp2)
where toNullType Seven = NSeven
toNullType Eight = NEight
toNullType Nine = NNine
toNullType Ten = NTen
toNullType Jack = NJack
toNullType Queen = NQueen
toNullType King = NKing
toNullType Ace = NAce
compareTypes _ tp1 tp2 = compare tp1 tp2

sortCards :: HasCard c => Trump -> Maybe TurnColour -> [c] -> [c]
sortCards trump turnCol cs = sortBy f cs
where f c1 c2 = compareCards trump turnCol (toCard c1) (toCard c2)

sortRender :: HasCard c => Trump -> [c] -> [c]
sortRender trump cs = sortBy f cs
where f c1 c2 = compareRender trump (toCard c2) (toCard c1)

highestCard :: HasCard c => Trump -> Maybe TurnColour -> [c] -> c
highestCard trump turnCol cs = maximumBy f cs
where f c1 c2 = compareCards trump turnCol (toCard c1) (toCard c2)


shuffleCards :: IO [Card] shuffleCards :: IO [Card]
shuffleCards = do shuffleCards = do


+ 20
- 23
src/Skat/Matches.hs Просмотреть файл

@@ -1,5 +1,5 @@
module Skat.Matches ( module Skat.Matches (
singleVsBots, pvp, pvpWithBidding, singleWithBidding
singleVsBots, pvp, singleWithBidding
) where ) where


import Control.Monad.State import Control.Monad.State
@@ -12,11 +12,26 @@ import Skat.Player
import Skat.Pile import Skat.Pile
import Skat.Card import Skat.Card
import Skat.Preperation import Skat.Preperation
import Skat.Bidding


import Skat.AI.Rulebased import Skat.AI.Rulebased
import Skat.AI.Online import Skat.AI.Online
import Skat.AI.Stupid import Skat.AI.Stupid


match :: PrepEnv -> IO ()
match prepEnv = do
maySkatEnv <- runReaderT runPreperation prepEnv
case maySkatEnv of
Just (sglPlayer, skatEnv) -> do
finished <- execStateT turn skatEnv
let res = getResults
(game skatEnv)
sglPlayer
(Skat.piles skatEnv)
(Skat.piles finished)
publishGameResults res (bidders prepEnv)
Nothing -> putStrLn "no one wanted to play"

-- | predefined card distribution for testing purposes -- | predefined card distribution for testing purposes
cardDistr :: Piles cardDistr :: Piles
cardDistr = emptyPiles hand1 hand2 hand3 skt cardDistr = emptyPiles hand1 hand2 hand3 skt
@@ -38,8 +53,8 @@ singleVsBots comm = do
(PL $ OnlineEnv Team Hand1 comm) (PL $ OnlineEnv Team Hand1 comm)
(PL $ Stupid Team Hand2) (PL $ Stupid Team Hand2)
(PL $ mkAIEnv Single Hand3 10) (PL $ mkAIEnv Single Hand3 10)
env = SkatEnv (distribute cards) Nothing Spades ps Hand1
liftIO $ evalStateT (publishGameStart >> turn >>= publishGameResults) env
env = SkatEnv (distribute cards) Nothing (Colour Spades Einfach) ps Hand1
void $ evalStateT turn env


singleWithBidding :: Communicator c => c -> IO () singleWithBidding :: Communicator c => c -> IO ()
singleWithBidding comm = do singleWithBidding comm = do
@@ -51,24 +66,10 @@ singleWithBidding comm = do
(BD $ NoBidder Hand2) (BD $ NoBidder Hand2)
(BD $ NoBidder Hand3) (BD $ NoBidder Hand3)
env = PrepEnv ps bs env = PrepEnv ps bs
maySkatEnv <- liftIO $ runReaderT runPreperation env
case maySkatEnv of
Just skatEnv ->
liftIO $ evalStateT (publishGameStart >> turn >>= publishGameResults) skatEnv
Nothing -> putStrLn "No one wanted to play."
match env


pvp :: Communicator c => c -> c -> c -> IO () pvp :: Communicator c => c -> c -> c -> IO ()
pvp comm1 comm2 comm3 = do pvp comm1 comm2 comm3 = do
cards <- shuffleCards
let ps = Players
(PL $ OnlineEnv Team Hand1 comm1)
(PL $ OnlineEnv Team Hand2 comm2)
(PL $ OnlineEnv Team Hand3 comm3)
env = SkatEnv (distribute cards) Nothing Spades ps Hand1
liftIO $ evalStateT (publishGameStart >> turn >>= publishGameResults) env

pvpWithBidding :: Communicator c => c -> c -> c -> IO ()
pvpWithBidding comm1 comm2 comm3 = do
cards <- shuffleCards cards <- shuffleCards
let ps = distribute cards let ps = distribute cards
h1 = map toCard $ handCards Hand1 ps h1 = map toCard $ handCards Hand1 ps
@@ -79,8 +80,4 @@ pvpWithBidding comm1 comm2 comm3 = do
(BD $ PrepOnline Hand2 comm2 $ h2) (BD $ PrepOnline Hand2 comm2 $ h2)
(BD $ PrepOnline Hand3 comm3 $ h3) (BD $ PrepOnline Hand3 comm3 $ h3)
env = PrepEnv ps bs env = PrepEnv ps bs
maySkatEnv <- liftIO $ runReaderT runPreperation env
case maySkatEnv of
Just skatEnv ->
liftIO $ evalStateT (publishGameStart >> turn >>= publishGameResults) skatEnv
Nothing -> putStrLn "No one wanted to play."
match env

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

@@ -1,6 +1,6 @@
module Skat.Operations ( module Skat.Operations (
turn, turnGeneric, play, playOpen, publishGameResults,
publishGameStart, play_, sortRender, undo_
turn, turnGeneric, play, playOpen,
play_, sortRender, undo_
) where ) where


import Control.Monad.State import Control.Monad.State
@@ -13,21 +13,13 @@ import Skat
import Skat.Card import Skat.Card
import Skat.Pile import Skat.Pile
import Skat.Player (chooseCard, Players(..), Player(..), PL(..), import Skat.Player (chooseCard, Players(..), Player(..), PL(..),
updatePlayer, playersToList, player, MonadPlayer, getSinglePlayer)
updatePlayer, playersToList, player, MonadPlayer, getSinglePlayer, trump)
import Skat.Utils (shuffle) import Skat.Utils (shuffle)


compareRender :: Card -> Card -> Ordering
compareRender (Card t1 c1) (Card t2 c2) = case compare c1 c2 of
EQ -> compare t1 t2
v -> v

sortRender :: [Card] -> [Card]
sortRender = sortBy compareRender

play_ :: HasCard c => c -> Skat () play_ :: HasCard c => c -> Skat ()
play_ card = do play_ card = do
hand <- gets currentHand hand <- gets currentHand
trCol <- gets trumpColour
trCol <- trump
modifyp $ playCard hand card modifyp $ playCard hand card
table <- getp tableCards table <- getp tableCards
case length table of case length table of
@@ -36,7 +28,7 @@ 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_ :: HasCard c => c -> Hand -> Maybe TurnColour -> Team -> Skat ()
undo_ card oldCurrent oldTurnCol oldWinner = do undo_ card oldCurrent oldTurnCol oldWinner = do
modify $ setCurrentHand oldCurrent modify $ setCurrentHand oldCurrent
modify $ setTurnColour oldTurnCol modify $ setTurnColour oldTurnCol
@@ -51,7 +43,7 @@ turnGeneric playFunc depth = do
ps <- gets players ps <- gets players
let p = player ps n let p = player ps n
over <- getp $ handEmpty n over <- getp $ handEmpty n
trCol <- gets trumpColour
trCol <- trump
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
1 -> do 1 -> do
@@ -72,7 +64,7 @@ turn = turnGeneric play 10


evaluateTable :: Skat Hand evaluateTable :: Skat Hand
evaluateTable = do evaluateTable = do
trumpCol <- gets trumpColour
trumpCol <- trump
turnCol <- gets turnColour turnCol <- gets turnColour
table <- getp tableCards table <- getp tableCards
ps <- gets players ps <- gets players
@@ -89,7 +81,7 @@ play :: (Show p, Player p) => p -> Skat Card
play p = do play p = do
table <- getp tableCards table <- getp tableCards
turnCol <- gets turnColour turnCol <- gets turnColour
trump <- gets trumpColour
trump <- trump
cards <- getp $ handCards (hand p) cards <- getp $ handCards (hand p)
fallen <- getp played fallen <- getp played
(card, p') <- chooseCard p table fallen cards (card, p') <- chooseCard p table fallen cards
@@ -107,14 +99,3 @@ playOpen p = do
card <- chooseCardOpen p card <- chooseCardOpen p
modifyp $ playCard (hand p) card modifyp $ playCard (hand p) card
return card return card

publishGameResults :: (Int, Int) -> Skat ()
publishGameResults res = do
pls <- gets players
mapM_ (\p -> onGameResults p res) (playersToList pls)

publishGameStart :: Skat ()
publishGameStart = do
pls <- gets players
let sglPlayer = getSinglePlayer pls
mapM_ (\p -> onGameStart p sglPlayer) (playersToList pls)

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

@@ -153,12 +153,12 @@ handCards Hand1 = _hand1
handCards Hand2 = _hand2 handCards Hand2 = _hand2
handCards Hand3 = _hand3 handCards Hand3 = _hand3


allowed :: Hand -> Colour -> Maybe Colour -> Piles -> [CardS Owner]
allowed hand trCol turnCol ps
allowed :: Hand -> Trump -> Maybe TurnColour -> Piles -> [CardS Owner]
allowed hand trump turnCol ps
| null sameColour = cards | null sameColour = cards
| otherwise = sameColour | otherwise = sameColour
where cards = handCards hand ps where cards = handCards hand ps
sameColour = filter (\ca -> effectiveColour trCol ca `equals` turnCol) cards
sameColour = filter (\ca -> effectiveColour trump ca `equals` turnCol) cards


skatCards :: Piles -> [Card] skatCards :: Piles -> [Card]
skatCards = map getCard . _skat skatCards = map getCard . _skat


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

@@ -8,8 +8,8 @@ import Skat.Card
import Skat.Pile import Skat.Pile


class (Monad m, MonadIO m) => MonadPlayer m where class (Monad m, MonadIO m) => MonadPlayer m where
trumpColour :: m Colour
turnColour :: m (Maybe Colour)
trump :: m Trump
turnColour :: m (Maybe TurnColour)
showSkat :: Player p => p -> m (Maybe [Card]) showSkat :: Player p => p -> m (Maybe [Card])


class (Monad m, MonadIO m, MonadPlayer m) => MonadPlayerOpen m where class (Monad m, MonadIO m, MonadPlayer m) => MonadPlayerOpen m where
@@ -38,16 +38,6 @@ class Player p where
fallen = played piles fallen = played piles
myCards = handCards (hand p) piles myCards = handCards (hand p) piles
fst <$> chooseCard p table fallen myCards fst <$> chooseCard p table fallen myCards
onGameResults :: MonadIO m
=> p
-> (Int, Int)
-> m ()
onGameResults _ _ = return ()
onGameStart :: MonadPlayer m
=> p
-> Hand
-> m ()
onGameStart _ _ = return ()


data PL = forall p. (Show p, Player p) => PL p data PL = forall p. (Show p, Player p) => PL p


@@ -64,8 +54,6 @@ instance Player PL where
v <- onCardPlayed p card v <- onCardPlayed p card
return $ PL v return $ PL v
chooseCardOpen (PL p) = chooseCardOpen p chooseCardOpen (PL p) = chooseCardOpen p
onGameResults (PL p) res = onGameResults p res
onGameStart (PL p) singlePlayer = onGameStart p singlePlayer


data Players = Players PL PL PL data Players = Players PL PL PL
deriving Show deriving Show


+ 4
- 4
src/Skat/Player/Utils.hs Просмотреть файл

@@ -8,11 +8,11 @@ import Skat.Card (Card, HasCard(..))


isAllowed :: (HasCard c, MonadPlayer m) => [c] -> c -> m Bool isAllowed :: (HasCard c, MonadPlayer m) => [c] -> c -> m Bool
isAllowed hand card = do isAllowed hand card = do
trCol <- trumpColour
tr <- trump
turnCol <- turnColour turnCol <- turnColour
return $ C.isAllowed trCol turnCol hand card
return $ C.isAllowed tr turnCol hand card


isTrump :: MonadPlayer m => Card -> m Bool isTrump :: MonadPlayer m => Card -> m Bool
isTrump card = do isTrump card = do
trCol <- trumpColour
return $ C.isTrump trCol card
tr <- trump
return $ C.isTrump tr card

+ 35
- 10
src/Skat/Preperation.hs Просмотреть файл

@@ -1,7 +1,9 @@
{-# LANGUAGE ExistentialQuantification #-} {-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE TupleSections #-}


module Skat.Preperation ( module Skat.Preperation (
Bidder(..), Bid, BD(..), Bidders(..), PrepEnv(..), runPreperation
Bidder(..), Bid, BD(..), Bidders(..), PrepEnv(..), runPreperation,
publishGameResults
) where ) where


import Control.Monad.IO.Class import Control.Monad.IO.Class
@@ -30,6 +32,10 @@ class Bidder a where
askHand :: MonadIO m => a -> Bid -> m Bool askHand :: MonadIO m => a -> Bid -> m Bool
askSkat :: MonadIO m => a -> Bid -> [Card] -> m [Card] askSkat :: MonadIO m => a -> Bid -> [Card] -> m [Card]
toPlayer :: a -> Team -> PL toPlayer :: a -> Team -> PL
onGame :: MonadIO m => a -> Game -> Hand -> m ()
onGame _ _ _ = return ()
onResult :: MonadIO m => a -> Result -> m ()
onResult _ _ = return ()


-- | trick to allow heterogenous bidder list -- | trick to allow heterogenous bidder list
data BD = forall b. (Show b, Bidder b) => BD b data BD = forall b. (Show b, Bidder b) => BD b
@@ -46,6 +52,8 @@ instance Bidder BD where
askResponse (BD b) = askResponse b askResponse (BD b) = askResponse b
toPlayer (BD b) = toPlayer b toPlayer (BD b) = toPlayer b
onStart (BD b) = onStart b onStart (BD b) = onStart b
onGame (BD b) = onGame b
onResult (BD b) = onResult b


data Bidders = Bidders BD BD BD data Bidders = Bidders BD BD BD
deriving Show deriving Show
@@ -61,29 +69,31 @@ toPlayers single (Bidders b1 b2 b3) =
(toPlayer b2 $ if single == Hand2 then Single else Team) (toPlayer b2 $ if single == Hand2 then Single else Team)
(toPlayer b3 $ if single == Hand3 then Single else Team) (toPlayer b3 $ if single == Hand3 then Single else Team)


runPreperation :: Preperation (Maybe SkatEnv)
runPreperation :: Preperation (Maybe (Hand, SkatEnv))
runPreperation = do runPreperation = do
bds <- asks bidders bds <- asks bidders
onStart (bidder bds Hand1) onStart (bidder bds Hand1)
onStart (bidder bds Hand2) onStart (bidder bds Hand2)
onStart (bidder bds Hand3) onStart (bidder bds Hand3)
(winner, bid) <- runBidding 0 (bidder bds Hand2) (bidder bds Hand1) (winner, bid) <- runBidding 0 (bidder bds Hand2) (bidder bds Hand1)
(finalWinner, finalBid) <- runBidding 0 (bidder bds Hand3) (bidder bds winner)
(finalWinner, finalBid) <- runBidding bid (bidder bds Hand3) (bidder bds winner)
if finalBid == 0 then do if finalBid == 0 then do
bid <- askBid (bidder bds finalWinner) finalWinner 0 bid <- askBid (bidder bds finalWinner) finalWinner 0
case bid of case bid of
Just val -> Just <$> initGame finalWinner val
Just val -> (Just . (finalWinner,)) <$> initGame finalWinner val
Nothing -> return Nothing Nothing -> return Nothing
else Just <$> initGame finalWinner finalBid
else (Just . (finalWinner,)) <$> initGame finalWinner finalBid


runBidding :: Bid -> BD -> BD -> Preperation (Hand, Bid) runBidding :: Bid -> BD -> BD -> Preperation (Hand, Bid)
runBidding startingBid reizer gereizter = do runBidding startingBid reizer gereizter = do
first <- askBid reizer (hand gereizter) startingBid first <- askBid reizer (hand gereizter) startingBid
case first of case first of
Just val -> do
response <- askResponse gereizter (hand reizer) val
if response then runBidding val reizer gereizter
else return (hand reizer, val)
Just val
| val > startingBid -> do
response <- askResponse gereizter (hand reizer) val
if response then runBidding val reizer gereizter
else return (hand reizer, val)
| otherwise -> return (hand gereizter, startingBid)
Nothing -> return (hand gereizter, startingBid) Nothing -> return (hand gereizter, startingBid)


initGame :: Hand -> Bid -> Preperation SkatEnv initGame :: Hand -> Bid -> Preperation SkatEnv
@@ -96,8 +106,10 @@ initGame single bid = do
ps' <- if noSkat then return ps else handleSkat (bidder bds single) bid ps ps' <- if noSkat then return ps else handleSkat (bidder bds single) bid ps
-- ask for game kind -- ask for game kind
game <- handleGame (bidder bds single) bid noSkat game <- handleGame (bidder bds single) bid noSkat
-- publish game start
publishGameStart game single
-- construct skat env -- construct skat env
return $ mkSkatEnv ps' Nothing Spades (toPlayers single bds) Hand1
return $ mkSkatEnv ps' Nothing game (toPlayers single bds) Hand1


handleGame :: BD -> Bid -> Bool -> Preperation Game handleGame :: BD -> Bid -> Bool -> Preperation Game
handleGame bd bid noSkat = do handleGame bd bid noSkat = do
@@ -119,3 +131,16 @@ handleSkat bd bid ps = do
case moveToSkat (hand bd) skat' ps of case moveToSkat (hand bd) skat' ps of
Just correct -> return correct Just correct -> return correct
Nothing -> handleSkat bd bid ps Nothing -> handleSkat bd bid ps

publishGameResults :: MonadIO m => Result -> Bidders -> m ()
publishGameResults res bidders = do
onResult (bidder bidders Hand1) res
onResult (bidder bidders Hand2) res
onResult (bidder bidders Hand3) res

publishGameStart :: Game -> Hand -> Preperation ()
publishGameStart game sglPlayer = do
bds <- asks bidders
onGame (bidder bds Hand1) game sglPlayer
onGame (bidder bds Hand2) game sglPlayer
onGame (bidder bds Hand3) game sglPlayer

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