2018-03-10 23:25:44 +01:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
2018-03-15 22:32:24 +01:00
|
|
|
module Hanafuda.KoiKoi.Turn (
|
|
|
|
catch
|
|
|
|
, end
|
|
|
|
, next
|
|
|
|
, popNextCard
|
|
|
|
) where
|
2018-03-10 23:25:44 +01:00
|
|
|
|
2018-03-15 22:32:24 +01:00
|
|
|
import Hanafuda (Card, Pack, empty, match)
|
2018-03-19 12:28:15 +01:00
|
|
|
import Hanafuda.Player (Player(..), plays)
|
2018-07-24 22:19:04 +02:00
|
|
|
import qualified Hanafuda.Player as Player (get, next)
|
2018-03-15 22:32:24 +01:00
|
|
|
import Hanafuda.KoiKoi.Yaku (meldInto)
|
|
|
|
import Hanafuda.KoiKoi.Game (Game, On(..), Step(..), raise, setPlayer, stop)
|
|
|
|
import qualified Hanafuda.KoiKoi.Round as Round (next)
|
2018-03-10 23:25:44 +01:00
|
|
|
import Control.Monad.Reader (runReader)
|
|
|
|
|
2018-07-24 22:19:04 +02:00
|
|
|
catch :: Ord player => On player -> Card -> (Pack, [Card]) -> IO (Game player)
|
2018-03-15 22:32:24 +01:00
|
|
|
catch on@(On_ {players, playing}) card (river, trick) =
|
|
|
|
either raise (popNextCard . setPlayer (on {river, trick})) played
|
2018-03-10 23:25:44 +01:00
|
|
|
where
|
2018-07-24 22:19:04 +02:00
|
|
|
played = (Player.get playing players) `plays` card
|
2018-03-10 23:25:44 +01:00
|
|
|
|
2018-07-24 22:19:04 +02:00
|
|
|
popNextCard :: Ord player => On player -> IO (Game player)
|
|
|
|
popNextCard (On_ {deck = []}) = raise "No more cards in the stack"
|
|
|
|
popNextCard on@(On_ {river, deck = turned : others}) =
|
|
|
|
let pop = on {deck = others} in
|
2018-03-19 12:28:15 +01:00
|
|
|
case match turned river of
|
2018-03-15 22:32:24 +01:00
|
|
|
Right (newRiver, newCaptured) -> end pop (newRiver, newCaptured)
|
2018-03-19 12:28:15 +01:00
|
|
|
Left _ -> stop $ pop {step = Turned turned}
|
2018-03-15 22:32:24 +01:00
|
|
|
|
2018-07-24 22:19:04 +02:00
|
|
|
end :: Ord player => On player -> (Pack, [Card]) -> IO (Game player)
|
2018-03-15 22:32:24 +01:00
|
|
|
end on@(On_ {month, trick, playing, players}) (river, newCaptured) = do
|
|
|
|
let updatedGame = setPlayer (on {river, trick = []}) updatedPlayer
|
|
|
|
if null scored
|
|
|
|
then next updatedGame
|
|
|
|
else stop $ updatedGame {step = Scored, winning = playing}
|
|
|
|
where
|
|
|
|
newTrick = newCaptured ++ trick
|
2018-07-24 22:19:04 +02:00
|
|
|
player = Player.get playing players
|
2018-03-15 22:32:24 +01:00
|
|
|
(scored, newMeld) = runReader (newTrick `meldInto` (meld player)) month
|
|
|
|
updatedPlayer = player {meld = newMeld, yakus = scored `mappend` (yakus player)}
|
2018-03-10 23:25:44 +01:00
|
|
|
|
2018-07-24 22:19:04 +02:00
|
|
|
next :: Ord player => On player -> IO (Game player)
|
2018-03-15 22:32:24 +01:00
|
|
|
next on@(On_ {players, playing}) =
|
2018-07-24 22:19:04 +02:00
|
|
|
let newPlaying = Player.next players playing in
|
|
|
|
if hand (Player.get newPlaying players) == empty
|
2018-03-15 22:32:24 +01:00
|
|
|
then Round.next $ on
|
|
|
|
else stop $ on {playing = newPlaying, step = ToPlay}
|