-
Notifications
You must be signed in to change notification settings - Fork 0
/
Ch23_RollYourOwn.hs
91 lines (77 loc) · 2.36 KB
/
Ch23_RollYourOwn.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
module Ch23_RollYourOwn where
import Control.Applicative (liftA3)
import Control.Monad (replicateM)
import Control.Monad.Trans.State
import System.Random
data Die =
DieOne
| DieTwo
| DieThree
| DieFour
| DieFive
| DieSix
deriving (Eq, Show)
intToDie :: Int -> Die
intToDie n = case n of
1 -> DieOne
2 -> DieTwo
3 -> DieThree
4 -> DieFour
5 -> DieFive
6 -> DieSix
-- Use 'error'
-- _extremely_ sparingly.
x -> error $ "intToDie got non 1-6 integer: " ++ show x
rollDie :: State StdGen Die
rollDie = state $ do
(n, s) <- randomR (1, 6)
return (intToDie n, s)
-- state :: Monad m => (s -> (a, s)) -> StateT s m a
rollDie' :: State StdGen Die
rollDie' = intToDie <$> state (randomR (1, 6))
rollDieThreeTimes :: (Die, Die, Die)
rollDieThreeTimes = do
let s = mkStdGen 0
(d1, s1) = randomR (1, 6) s
(d2, s2) = randomR (1, 6) s1
(d3, _) = randomR (1, 6) s2
(intToDie d1, intToDie d2, intToDie d3)
rollDieThreeTimes' :: State StdGen (Die, Die, Die)
rollDieThreeTimes' =
liftA3 (,,) rollDie rollDie rollDie
-- replicateM :: Monad m => Int -> m a -> m [a]
nDie :: Int -> State StdGen [Die]
nDie n = replicateM n rollDie
rollsToGetTwenty :: StdGen -> Int
rollsToGetTwenty = go 0 0 where
go :: Int -> Int -> StdGen -> Int
go sum count gen
| sum >= 20 = count
| otherwise =
let (die, nextGen) = randomR (1, 6) gen
in go (sum + die) (count + 1) nextGen
-- ex01 -> Refactor rollsToGetTwenty into having
-- the limit be a function argument.
type Count = Int
type LocalSum = Int
rollsToGetN :: Int -> StdGen -> Count
rollsToGetN n = recursive 0 0
where recursive :: LocalSum -> Count -> StdGen -> Count
recursive sum count gen
| sum >= n = count
| otherwise =
let (die, nextGen) = randomR (1, 6) gen
in recursive (sum + die) (count + 1) nextGen
-- ex02 -> Change rollsToGetN to recording the series
-- of die that occurred in addition to the count.
rollsCountLogged :: Int -> StdGen -> (Int, [Die])
rollsCountLogged n = recursive 0 0 []
where
recursive :: Int -> Int -> [Die]
-> StdGen -> (Int, [Die])
recursive sum count xs gen
| sum >= n = (count, xs)
| otherwise =
let (x, nextGen) = randomR (1, 6) gen
die = intToDie x
in recursive (sum + x) (count + 1) (die : xs) nextGen