Files
skat/src/Skat/Preperation.hs
T
2020-04-07 01:34:38 +02:00

174 lines
6.1 KiB
Haskell

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE TupleSections #-}
module Skat.Preperation (
Bidder(..), Bid, BD(..), Bidders(..), PrepEnv(..), runPreperation,
publishGameResults, bidder, makePrep
) where
import Control.Monad.IO.Class
import Control.Monad.State
import Skat.Pile
import Skat.Card
import Skat.Player (PL, Players(..))
import Skat.Bidding
import Skat (SkatEnv, mkSkatEnv)
data PrepEnv = PrepEnv { piles :: Piles
, bidders :: Bidders
, current :: Bid }
deriving Show
makePrep :: Piles -> Bidders -> PrepEnv
makePrep ps bd = PrepEnv ps bd 0
type Preperation = StateT PrepEnv IO
class Bidder a where
hand :: a -> Hand
onStart :: MonadIO m => a -> m ()
askBid :: MonadIO m => a -> Hand -> Bid -> m (Maybe Bid)
askResponse :: MonadIO m => a -> Hand -> Bid -> m Bool
askGame :: MonadIO m => a -> Bid -> m Game
askHand :: MonadIO m => a -> Bid -> m Bool
askSkat :: MonadIO m => a -> Bid -> [Card] -> m [Card]
toPlayer :: a -> Team -> PL
onBid :: MonadIO m => a -> Maybe Bid -> Hand -> Hand -> m ()
onBid _ _ _ _ = return ()
onResponse :: MonadIO m => a -> Bool -> Hand -> Hand -> m ()
onResponse _ _ _ _ = return ()
onGame :: MonadIO m => a -> HideGame -> Hand -> m ()
onGame _ _ _ = return ()
onResult :: MonadIO m => a -> Result -> m ()
onResult _ _ = return ()
onNoGame :: MonadIO m => a -> m ()
onNoGame _ = return ()
-- | trick to allow heterogenous bidder list
data BD = forall b. (Show b, Bidder b) => BD b
instance Show BD where
show (BD b) = show b
instance Bidder BD where
hand (BD b) = hand b
askBid (BD b) = askBid b
askGame (BD b) = askGame b
askHand (BD b) = askHand b
askSkat (BD b) = askSkat b
askResponse (BD b) = askResponse b
toPlayer (BD b) = toPlayer b
onStart (BD b) = onStart b
onGame (BD b) = onGame b
onResult (BD b) = onResult b
onBid (BD b) = onBid b
onResponse (BD b) = onResponse b
onNoGame (BD b) = onNoGame b
data Bidders = Bidders BD BD BD
deriving Show
bidder :: Bidders -> Hand -> BD
bidder (Bidders b _ _) Hand1 = b
bidder (Bidders _ b _) Hand2 = b
bidder (Bidders _ _ b) Hand3 = b
toPlayers :: Hand -> Bidders -> Players
toPlayers single (Bidders b1 b2 b3) =
Players (toPlayer b1 $ if single == Hand1 then Single else Team)
(toPlayer b2 $ if single == Hand2 then Single else Team)
(toPlayer b3 $ if single == Hand3 then Single else Team)
runPreperation :: Preperation (Maybe SkatEnv)
runPreperation = do
bds <- gets bidders
onStart (bidder bds Hand1)
onStart (bidder bds Hand2)
onStart (bidder bds Hand3)
(winner, bid) <- runBidding 0 (bidder bds Hand2) (bidder bds Hand1)
(finalWinner, finalBid) <- runBidding bid (bidder bds Hand3) (bidder bds winner)
if finalBid == 0 then do
bid <- askBid (bidder bds finalWinner) finalWinner 0
publishBid bid finalWinner finalWinner
case bid of
Just val -> Just <$> initGame finalWinner val
Nothing -> publishNoGame >> return Nothing
else Just <$> initGame finalWinner finalBid
runBidding :: Bid -> BD -> BD -> Preperation (Hand, Bid)
runBidding startingBid reizer gereizter = do
first <- askBid reizer (hand gereizter) startingBid
case first of
Just val
| val > startingBid -> do
publishBid first (hand reizer) (hand gereizter)
modify $ \env -> env { current = val }
response <- askResponse gereizter (hand reizer) val
publishResponse response (hand reizer) (hand gereizter)
if response then runBidding val reizer gereizter
else return (hand reizer, val)
| otherwise -> do
publishBid Nothing (hand reizer) (hand gereizter)
return (hand gereizter, startingBid)
Nothing -> do
publishBid Nothing (hand reizer) (hand gereizter)
return (hand gereizter, startingBid)
initGame :: Hand -> Bid -> Preperation SkatEnv
initGame single bid = do
ps <- gets piles
bds <- gets bidders
-- ask if player wants to play hand
noSkat <- askHand (bidder bds single) bid
-- either return piles or ask for skat cards and modify piles
ps' <- if noSkat then return ps else handleSkat (bidder bds single) bid ps
-- ask for game kind
game <- handleGame (bidder bds single) bid noSkat
-- publish game start
publishGameStart game single
-- construct skat env
return $ mkSkatEnv ps' Nothing game (toPlayers single bds) Hand1 single
handleGame :: BD -> Bid -> Bool -> Preperation Game
handleGame bd bid noSkat = do
cards <- (\ps -> map toCard (handCards (hand bd) ps) ++ skatCards ps) <$> gets piles
-- ask bidder for game
proposal <- askGame bd bid
-- check if proposal is allowed
if isHand proposal == noSkat then return proposal else handleGame bd bid noSkat
handleSkat :: BD -> Bid -> Piles -> Preperation Piles
handleSkat bd bid ps = do
let skat = skatCards ps
skat' <- askSkat bd bid skat
liftIO $ putStrLn $ "received skat " ++ show skat'
case moveToSkat (hand bd) skat' ps of
Just correct -> return correct
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 = mapBidders (\b -> onGame b (HideGame game) sglPlayer)
publishBid :: Maybe Bid -> Hand -> Hand -> Preperation ()
publishBid bid reizer gereizter = mapBidders (\b -> onBid b bid reizer gereizter)
publishResponse :: Bool -> Hand -> Hand -> Preperation ()
publishResponse response reizer gereizter = mapBidders (\b -> onResponse b response reizer gereizter)
publishNoGame :: Preperation ()
publishNoGame = mapBidders onNoGame
mapBidders :: (BD -> Preperation ()) -> Preperation ()
mapBidders f = do
bds <- gets bidders
f (bidder bds Hand1)
f (bidder bds Hand2)
f (bidder bds Hand3)