module Numeric.Probability.Example.Collection where
import qualified Numeric.Probability.Distribution as Dist
import qualified Numeric.Probability.Random as Rnd
import Numeric.Probability.Distribution ((??), )
import Numeric.Probability.Simulation ((~.), )
import Numeric.Probability.Percentage (Dist)
import Numeric.Probability.Monad (doWhile, )
import Control.Monad.Trans.State (StateT(StateT, runStateT), evalStateT, )
import Control.Monad (liftM2, replicateM, )
import qualified Data.List.HT as ListHT
import System.Random (Random)
type Collection a = [a]
type Probability = Rational
selectOne :: (Fractional prob) =>
StateT (Collection a) (Dist.T prob) a
selectOne =
StateT $ Dist.uniform . ListHT.removeEach
select1 :: (Fractional prob) => Collection a -> Dist.T prob a
select1 = evalStateT selectOne
select2 :: (Fractional prob) => Collection a -> Dist.T prob (a,a)
select2 = evalStateT (liftM2 (,) selectOne selectOne)
select :: (Fractional prob) => Int -> Collection a -> Dist.T prob [a]
select n = evalStateT (replicateM n selectOne)
data Marble = R | G | B deriving (Eq,Ord,Show)
bucket :: Collection Marble
bucket = [R,R,R,R,R, G,G,G, B,B]
jar :: Collection Marble
jar = [R,R,G,G,B]
pRGB :: Probability
pRGB = Dist.just [R,G,B] ?? select 3 jar
pRG :: Probability
pRG = Dist.oneOf [[R,G],[G,R]] ?? select 2 jar
data Suit = Club | Spade | Heart | Diamond
deriving (Eq,Ord,Show,Enum)
data Rank = Plain Int | Jack | Queen | King | Ace
deriving (Eq,Ord,Show)
type Card = (Rank,Suit)
plains :: [Rank]
plains = map Plain [2..10]
faces :: [Rank]
faces = [Jack,Queen,King,Ace]
isFace :: Card -> Bool
isFace (r,_) = r `elem` faces
isPlain :: Card -> Bool
isPlain (r,_) = r `elem` plains
ranks :: [Rank]
ranks = plains ++ faces
suits :: [Suit]
suits = [Club,Spade,Heart,Diamond]
deck :: Collection Card
deck = liftM2 (,) ranks suits
value :: Card -> Int
value ((Plain n),_) = n
value (Ace,_) = 11
value _ = 10
totalValue :: Collection Card -> Int
totalValue cards = sum (map value cards)
draw :: (Fractional prob) =>
([Card], Collection Card) -> Dist.T prob ([Card], Collection Card)
draw (cards,cl) =
runStateT (fmap (:cards) selectOne) cl
drawF :: ([Card], Collection Card) -> Dist ([Card], Collection Card)
drawF = draw
drawTo16 :: Rnd.T ([Card], Collection Card)
drawTo16 =
doWhile
(\(cards,_) -> totalValue cards < 16)
(Rnd.change drawF) ([], deck)
win :: ([Card], b) -> Bool
win (cards,_) = totalValue cards <= 21
chanceWin :: (Fractional prob, Ord prob, Random prob) =>
Rnd.T (Dist.T prob Bool)
chanceWin = fmap (Dist.map win) ((100 ~. const drawTo16) undefined)