2018-03-10 23:25:44 +01:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
2019-01-08 22:34:29 +01:00
|
|
|
{-# LANGUAGE FlexibleContexts #-}
|
2018-03-10 23:25:44 +01:00
|
|
|
module Hanafuda.Player where
|
|
|
|
|
|
|
|
import Hanafuda (Card, Pack, contains, packOfCards, remove)
|
2019-08-15 23:34:59 +02:00
|
|
|
import qualified Hanafuda.Key as Hanafuda (Key)
|
2018-07-24 22:19:04 +02:00
|
|
|
import Data.Map ((!), Map, adjust, elemAt, empty, findMin, fromList, insert, keys, singleton, size)
|
|
|
|
import qualified Data.Map as Map (filter)
|
2019-01-08 22:34:29 +01:00
|
|
|
import Control.Monad.IO.Class (MonadIO(..))
|
|
|
|
import Control.Monad.Except (MonadError(..))
|
2018-03-15 22:32:24 +01:00
|
|
|
import System.Random (Random(..))
|
2018-03-10 23:25:44 +01:00
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
type Key yakus = Hanafuda.Key (Player yakus)
|
|
|
|
data Player yakus = Player {
|
2018-03-10 23:25:44 +01:00
|
|
|
hand :: Pack
|
|
|
|
, meld :: Pack
|
2019-08-15 23:34:59 +02:00
|
|
|
, nextPlayer :: Key yakus
|
2018-07-24 22:19:04 +02:00
|
|
|
, yakus :: yakus
|
2018-03-10 23:25:44 +01:00
|
|
|
} deriving (Show)
|
2019-08-15 23:34:59 +02:00
|
|
|
newtype Players yakus = Players (Map (Key yakus) (Player yakus)) deriving (Show)
|
2018-03-10 23:25:44 +01:00
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
new :: Monoid yakus => (Key yakus) -> Player yakus
|
2018-07-24 22:19:04 +02:00
|
|
|
new nextPlayer = Player {
|
|
|
|
hand = packOfCards []
|
2018-03-10 23:25:44 +01:00
|
|
|
, meld = packOfCards []
|
2018-07-24 22:19:04 +02:00
|
|
|
, nextPlayer
|
2018-03-10 23:25:44 +01:00
|
|
|
, yakus = mempty
|
|
|
|
}
|
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
players :: Monoid yakus => [Key yakus] -> Players yakus
|
2018-07-24 22:19:04 +02:00
|
|
|
players [] = Players empty
|
|
|
|
players [player] = Players $ singleton player $ new player
|
|
|
|
players (alice:others@(bob:_)) =
|
|
|
|
let Players playersByKey = players others in
|
|
|
|
let (before, _) = findMin $ Map.filter ((== bob) . nextPlayer) playersByKey in
|
|
|
|
Players $ insert alice (new bob) $ adjust (setNextPlayer alice) before playersByKey
|
|
|
|
where
|
|
|
|
setNextPlayer nextPlayer player = player {nextPlayer}
|
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
next :: Players yakus -> (Key yakus) -> (Key yakus)
|
2018-07-24 22:19:04 +02:00
|
|
|
next (Players playersByKey) = nextPlayer . (playersByKey !)
|
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
random :: MonadIO m => Players yakus -> m (Key yakus)
|
2018-07-24 22:19:04 +02:00
|
|
|
random (Players playersByKey) =
|
2019-01-08 22:34:29 +01:00
|
|
|
fst . ($ playersByKey) . elemAt <$> randomIndex
|
|
|
|
where
|
|
|
|
randomIndex = liftIO $ randomRIO (0, size playersByKey - 1)
|
2018-07-24 22:19:04 +02:00
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
get :: (Key yakus) -> Players yakus -> Player yakus
|
2018-07-24 22:19:04 +02:00
|
|
|
get key (Players playersByKey) = playersByKey ! key
|
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
set :: (Key yakus) -> Player yakus -> Players yakus -> Players yakus
|
2018-07-24 22:19:04 +02:00
|
|
|
set key player (Players playersByKey) = Players $ insert key player playersByKey
|
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
deal :: Monoid yakus => Players yakus -> [[Card]] -> Players yakus
|
2018-07-24 22:19:04 +02:00
|
|
|
deal (Players playersByKey) hands =
|
|
|
|
Players $ snd $ foldl dealTo (fst $ findMin playersByKey, playersByKey) hands
|
|
|
|
where
|
2018-07-28 19:23:16 +02:00
|
|
|
setHand cards (Player {nextPlayer}) = (new nextPlayer) {hand = packOfCards cards}
|
2018-07-24 22:19:04 +02:00
|
|
|
dealTo (key, m) hand = (nextPlayer $ m ! key, adjust (setHand hand) key m)
|
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
plays :: MonadError String m => Player yakus -> Card -> m (Player yakus)
|
2018-03-15 22:32:24 +01:00
|
|
|
plays player@(Player {hand}) card =
|
2018-03-10 23:25:44 +01:00
|
|
|
if hand `contains` card
|
2019-01-08 22:34:29 +01:00
|
|
|
then return $ player {hand = remove hand card}
|
|
|
|
else throwError "You don't have this card"
|
2018-03-10 23:25:44 +01:00
|
|
|
|
|
|
|
type Points = Int
|
2019-08-15 23:34:59 +02:00
|
|
|
type Scores yakus = Map (Key yakus) Points
|
2018-03-10 23:25:44 +01:00
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
score :: (yakus -> Points) -> Player yakus -> Points
|
2018-03-10 23:25:44 +01:00
|
|
|
score rater = rater . yakus
|
|
|
|
|
2019-08-15 23:34:59 +02:00
|
|
|
scores :: Players yakus -> [Points] -> Scores yakus
|
2018-07-24 22:19:04 +02:00
|
|
|
scores (Players playersByKey) = fromList . zip (keys playersByKey)
|