lib/src/Hanafuda/KoiKoi/Turn.hs

64 lines
2.4 KiB
Haskell
Raw Normal View History

{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE FlexibleContexts #-}
module Hanafuda.KoiKoi.Turn (
catch
, end
, next
, popNextCard
) where
import Hanafuda (Card, Pack, empty, match)
2018-03-19 12:28:15 +01:00
import Hanafuda.Player (Player(..), plays)
import qualified Hanafuda.Player as Player (get, next)
import Hanafuda.KoiKoi.Yaku (meldInto)
import Hanafuda.KoiKoi.Game (Action(..), Environment, Game, GameBlueprint(..), Source(..), Step(..), setPlayer)
import qualified Hanafuda.KoiKoi.Round as Round (next)
import Control.Monad.Except (MonadError(..))
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Reader (runReader)
import Control.Monad.Writer (MonadWriter(..))
import Prelude hiding (log)
log :: MonadWriter [Action] m => Source -> Card -> [Card] -> m ()
log source played cards = tell [
Action { source, played, captures = captures cards }
]
where
captures [_, captured] = Just captured
captures _ = Nothing
catch :: Environment m => Game -> Card -> (Pack, [Card]) -> m Game
2019-08-12 23:02:17 +02:00
catch game@(Game {players, playing}) card (river, trick) = do
log Hand card trick
2019-08-12 23:02:17 +02:00
(setPlayer (game {river, trick})) <$> played >>= popNextCard
where
played = (Player.get playing players) `plays` card
popNextCard :: Environment m => Game -> m Game
2019-08-12 23:02:17 +02:00
popNextCard (Game {deck = []}) = throwError "No more cards in the stack"
popNextCard game@(Game {river, deck = turned : others}) =
let pop = game {deck = others} in
2018-03-19 12:28:15 +01:00
case match turned river of
Right (newRiver, newCaptured) -> end pop turned (newRiver, newCaptured)
2019-08-12 23:02:17 +02:00
Left _ -> return $ pop {step = Turned turned}
end :: (MonadWriter [Action] m, MonadIO m) => Game -> Card -> (Pack, [Card]) -> m Game
2019-08-12 23:02:17 +02:00
end game@(Game {month, trick, playing, players}) card (river, newCaptured) = do
log Deck card newCaptured
2019-08-12 23:02:17 +02:00
let updatedGame = setPlayer (game {river, trick = []}) updatedPlayer
if null scored
then next updatedGame
2019-08-12 23:02:17 +02:00
else return $ updatedGame {step = Scored, winning = playing}
where
newTrick = newCaptured ++ trick
player = Player.get playing players
(scored, newMeld) = runReader (newTrick `meldInto` (meld player)) month
updatedPlayer = player {meld = newMeld, yakus = scored `mappend` (yakus player)}
next :: MonadIO m => Game -> m Game
2019-08-12 23:02:17 +02:00
next game@(Game {players, playing}) =
let newPlaying = Player.next players playing in
if hand (Player.get newPlaying players) == empty
2019-08-12 23:02:17 +02:00
then Round.next $ game
else return $ game {playing = newPlaying, step = ToPlay}