@ -3,21 +3,23 @@
module Hanafuda.Player where
import Hanafuda ( Card , Pack , contains , packOfCards , remove )
import qualified Hanafuda.ID as Hanafuda ( ID )
import Data.Map ( ( ! ) , Map , adjust , elemAt , empty , findMin , fromList , insert , keys , singleton , size )
import qualified Data.Map as Map ( filter )
import Control.Monad.IO.Class ( MonadIO ( .. ) )
import Control.Monad.Except ( MonadError ( .. ) )
import System.Random ( Random ( .. ) )
data Player key yakus = Player {
type ID yakus = Hanafuda . ID ( Player yakus )
data Player yakus = Player {
hand :: Pack
, meld :: Pack
, nextPlayer :: ke y
, nextPlayer :: ID yakus
, yakus :: yakus
} deriving ( Show )
newtype Players key yakus = Players ( Map key ( Player key yakus ) ) deriving ( Show )
newtype Players yakus = Players ( Map ( ID yakus ) ( Player yakus ) ) deriving ( Show )
new :: Monoid yakus => key -> Player key yakus
new :: Monoid yakus => ( ID yakus ) -> Player yakus
new nextPlayer = Player {
hand = packOfCards []
, meld = packOfCards []
@ -25,49 +27,51 @@ new nextPlayer = Player {
, yakus = mempty
}
players :: ( Ord key , Monoid yakus ) => [ key ] -> Players key yakus
players :: Monoid yakus => [ ID yakus ] -> Players 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
let Players playersByID = players others in
let ( before , _ ) = findMin $ Map . filter ( ( == bob ) . nextPlayer ) playersByID in
Players $ insert alice ( new bob ) $ adjust ( setNextPlayer alice ) before playersByID
where
setNextPlayer nextPlayer player = player { nextPlayer }
next :: Ord key => Players key yakus -> key -> key
next ( Players playersByKey ) = nextPlayer . ( playersByKey ! )
next :: Players yakus -> ( ID yakus ) -> ( ID yakus )
next ( Players playersByID ) = nextPlayer . ( playersByID ! )
random :: MonadIO m => Players key yakus -> m key
random ( Players playersByKey ) =
fst . ( $ playersByKey ) . elemAt <$> randomIndex
random :: MonadIO m => Players yakus -> m ( ID yakus )
random ( Players playersByID ) =
fst . ( $ playersByID ) . elemAt <$> randomIndex
where
randomIndex = liftIO $ randomRIO ( 0 , size playersByKey - 1 )
randomIndex = liftIO $ randomRIO ( 0 , size playersByID - 1 )
get :: Ord key => key -> Players key yakus -> Player key yakus
get key ( Players playersByKey ) = playersByKey ! key
get :: ( ID yakus ) -> Players yakus -> Player yakus
get playerID ( Players playersByID ) = playersByID ! playerID
set :: Ord key => key -> Player key yakus -> Players key yakus -> Players key yakus
set key player ( Players playersByKey ) = Players $ insert key player playersByKey
set :: ( ID yakus ) -> Player yakus -> Players yakus -> Players yakus
set playerID player ( Players playersByID ) = Players $ insert playerID player playersByID
deal :: ( Ord key , Monoid yakus ) => Players key yakus -> [ [ Card ] ] -> Players key yakus
deal ( Players playersByKey ) hands =
Players $ snd $ foldl dealTo ( fst $ findMin playersByKey , playersByKey ) hands
deal :: Monoid yakus => Players yakus -> [ [ Card ] ] -> Players yakus
deal ( Players playersByID ) hands =
Players $ snd $ foldl dealTo ( fst $ findMin playersByID , playersByID ) hands
where
setHand cards ( Player { nextPlayer } ) = ( new nextPlayer ) { hand = packOfCards cards }
dealTo ( key , m ) hand = ( nextPlayer $ m ! key , adjust ( setHand hand ) key m )
setHand cards ( Player { nextPlayer } ) =
( new nextPlayer ) { hand = packOfCards cards }
dealTo ( playerID , m ) hand =
( nextPlayer $ m ! playerID , adjust ( setHand hand ) playerID m )
plays :: MonadError String m => Player key yakus -> Card -> m ( Player key yakus )
plays :: MonadError String m => Player yakus -> Card -> m ( Player yakus )
plays player @ ( Player { hand } ) card =
if hand ` contains ` card
then return $ player { hand = remove hand card }
else throwError " You don't have this card "
type Points = Int
type Scores ke y = Map key Points
type Scores yakus = Map ( ID yakus ) Points
score :: ( yakus -> Points ) -> Player key yakus -> Points
score :: ( yakus -> Points ) -> Player yakus -> Points
score rater = rater . yakus
scores :: Ord key => Players key yakus -> [ Points ] -> Scores ke y
scores :: Players yakus -> [ Points ] -> Scores yakus
scores ( Players playersByKey ) = fromList . zip ( keys playersByKey )