module Random (module Frequency, module Random) where
import Data.Ratio
import qualified System.Random as R
import Control.Monad.State
import Frequency
type Rnd a = State R.StdGen a
-- Written in a "portable" way because the implementation of
-- State changes between mtl versions 1 and 2.
randomR :: (R.Random a) => (a, a) -> Rnd a
randomR rng =
do
g <- get
let (x, ng) = R.randomR rng g
put ng
return x
binaryChoice :: a -> a -> Rnd a
binaryChoice p0 p1 =
do
b <- randomR (False,True)
return (if b then p0 else p1)
chance :: Rational -> Rnd Bool
chance r =
do
let n = numerator r
d = denominator r
k <- randomR (1,d)
return (k <= n)
-- | d for die/dice
d :: Int -> Rnd Int
d x = if x <= 0 then return 0 else randomR (1,x)
oneOf :: [a] -> Rnd a
oneOf xs =
do
r <- randomR (0, length xs - 1)
return (xs !! r)
frequency :: Frequency a -> Rnd a
frequency (Frequency xs) =
do
r <- randomR (1, sum (map fst xs))
return (frequency' r xs)
where
frequency' :: Int -> [(Int, a)] -> a
frequency' _ [(_, x)] = x
frequency' m ((n, x) : xs)
| m <= n = x
| otherwise = frequency' (m - n) xs
rndToIO :: Rnd a -> IO a
rndToIO r =
do
g <- R.getStdGen
let (x,g') = runState r g
R.setStdGen g'
return x
-- ** Arithmetic operations on Rnd.
infixl 7 *~
infixl 6 ~+~
(~+~) :: Num a => Rnd a -> Rnd a -> Rnd a
(~+~) = liftM2 (+)
(*~) :: Num a => Int -> Rnd a -> Rnd a
x *~ r = liftM sum (replicateM x r)