2018-03-10 23:25:44 +01:00
|
|
|
{-# LANGUAGE NamedFieldPuns #-}
|
|
|
|
module Hanafuda.Player where
|
|
|
|
|
|
|
|
import Hanafuda (Card, Pack, contains, packOfCards, remove)
|
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)
|
2018-03-15 22:32:24 +01:00
|
|
|
import System.Random (Random(..))
|
2018-03-10 23:25:44 +01:00
|
|
|
|
2018-07-24 22:19:04 +02:00
|
|
|
data Player key yakus = Player {
|
2018-03-10 23:25:44 +01:00
|
|
|
hand :: Pack
|
|
|
|
, meld :: Pack
|
2018-07-24 22:19:04 +02:00
|
|
|
, nextPlayer :: key
|
|
|
|
, yakus :: yakus
|
2018-03-10 23:25:44 +01:00
|
|
|
} deriving (Show)
|
2018-07-24 22:19:04 +02:00
|
|
|
newtype Players key yakus = Players (Map key (Player key yakus)) deriving (Show)
|
2018-03-10 23:25:44 +01:00
|
|
|
|
2018-07-24 22:19:04 +02:00
|
|
|
new :: Monoid yakus => key -> Player key yakus
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2018-07-24 22:19:04 +02:00
|
|
|
players :: (Ord key, Monoid yakus) => [key] -> Players key yakus
|
|
|
|
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}
|
|
|
|
|
|
|
|
next :: Ord key => Players key yakus -> key -> key
|
|
|
|
next (Players playersByKey) = nextPlayer . (playersByKey !)
|
|
|
|
|
|
|
|
random :: Players key yakus -> IO key
|
|
|
|
random (Players playersByKey) =
|
|
|
|
fst . ($ playersByKey) . elemAt <$> randomRIO (0, size playersByKey - 1)
|
|
|
|
|
|
|
|
get :: Ord key => key -> Players key yakus -> Player key yakus
|
|
|
|
get key (Players playersByKey) = playersByKey ! key
|
|
|
|
|
|
|
|
set :: Ord key => key -> Player key yakus -> Players key yakus -> Players key yakus
|
|
|
|
set key player (Players playersByKey) = Players $ insert key player playersByKey
|
|
|
|
|
2018-07-28 19:23:16 +02:00
|
|
|
deal :: (Ord key, Monoid yakus) => Players key yakus -> [[Card]] -> Players key 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)
|
|
|
|
|
|
|
|
plays :: Player key yakus -> Card -> Either String (Player key 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
|
|
|
|
then Right $ player {hand = remove hand card}
|
|
|
|
else Left "You don't have this card"
|
|
|
|
|
|
|
|
type Points = Int
|
2018-07-24 22:19:04 +02:00
|
|
|
type Scores key = Map key Points
|
2018-03-10 23:25:44 +01:00
|
|
|
|
2018-07-24 22:19:04 +02:00
|
|
|
score :: (yakus -> Points) -> Player key yakus -> Points
|
2018-03-10 23:25:44 +01:00
|
|
|
score rater = rater . yakus
|
|
|
|
|
2018-07-24 22:19:04 +02:00
|
|
|
scores :: Ord key => Players key yakus -> [Points] -> Scores key
|
|
|
|
scores (Players playersByKey) = fromList . zip (keys playersByKey)
|