{- |
Given a row of n (~50) dice,
two players start with a random dice within the first m (~5) dice.
Every player moves along the row, according to the pips on the dice.
They stop if a move would exceed the row.
What is the probability that they stop at the same die?
(It is close to one.)
Kruskal's trick:
<http://faculty.uml.edu/rmontenegro/research/kruskal_count/kruskal.html>
Wuerfelschlange (german):
<http://www.math.de/exponate/wuerfelschlange.html/>
-}moduleNumeric.Probability.Example.KruskalwhereimportqualifiedNumeric.Probability.Distribution asDistimportqualifiedNumeric.Probability.Transition asTransimportqualifiedNumeric.Probability.Random asRandomimportqualifiedNumeric.Probability.Object asObjimportqualifiedSystem.RandomasRndimportqualifiedText.PrintfasPimportqualifiedData.ListasListimportControl.Monad(replicateM,)importData.Function.HT(nest,compose2,)importData.Tuple.HT(mapSnd,)importData.Bool.HT(if',)typeDie =InttypeProbability =RationaltypeDist =Dist.T Probability die ::(Obj.C prob experiment ,Fractionalprob )=>Score ->experiment Die die :: forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips =forall prob (obj :: * -> *) a.
(C prob obj, Fractional prob) =>
Spread obj a
Obj.uniform [Score
1..Score
maxPips ]typeScore =Int{- |
We reformulate the problem to the following game:
There are two players, both of them collect a number of points.
In every round the player with the smaller score throws a die
and adds the pips to his score.
If the two players somewhen get the same score, then the game ends
and the score is the result of the game (@Just score@).
If one of the players exceeds the maximum score n,
then the game stops and players lose (@Nothing@).
-}game ::(Obj.C prob experiment ,Fractionalprob )=>Score ->Score ->(Score ,Score )->experiment (MaybeScore )game :: forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> Score -> (Score, Score) -> experiment (Maybe Score)
game Score
maxPips Score
maxScore =letgo :: (Score, Score) -> m (Maybe Score)
go (Score
x ,Score
y )=ifScore
maxScore forall a. Ord a => a -> a -> Bool
<forall a. Ord a => a -> a -> a
maxScore
x Score
y thenforall (m :: * -> *) a. Monad m => a -> m a
returnforall a. Maybe a
Nothingelsecaseforall a. Ord a => a -> a -> Ordering
compareScore
x Score
y ofOrdering
EQ->forall (m :: * -> *) a. Monad m => a -> m a
return(forall a. a -> Maybe a
JustScore
x )Ordering
LT->doScore
d <-forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips (Score, Score) -> m (Maybe Score)
go (Score
x forall a. Num a => a -> a -> a
+Score
d ,Score
y )Ordering
GT->doScore
d <-forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips (Score, Score) -> m (Maybe Score)
go (Score
x ,Score
y forall a. Num a => a -> a -> a
+Score
d )inforall {prob} {m :: * -> *}.
(C prob m, Fractional prob) =>
(Score, Score) -> m (Maybe Score)
go gameRound ::Score ->Score ->Dist (Either(MaybeScore )(Score ,Score ))->Dist (Either(MaybeScore )(Score ,Score ))gameRound :: Score
-> Score
-> Dist (Either (Maybe Score) (Score, Score))
-> Dist (Either (Maybe Score) (Score, Score))
gameRound Score
maxPips Score
maxScore Dist (Either (Maybe Score) (Score, Score))
current =forall prob a. (Num prob, Ord a) => T prob a -> T prob a
Dist.norm forall a b. (a -> b) -> a -> b
$doEither (Maybe Score) (Score, Score)
e <-Dist (Either (Maybe Score) (Score, Score))
current caseEither (Maybe Score) (Score, Score)
e ofLeftMaybe Score
end ->forall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a b. a -> Either a b
LeftMaybe Score
end Right(Score
x ,Score
y )->ifScore
maxScore forall a. Ord a => a -> a -> Bool
<forall a. Ord a => a -> a -> a
maxScore
x Score
y thenforall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a b. a -> Either a b
Leftforall a. Maybe a
Nothingelsecaseforall a. Ord a => a -> a -> Ordering
compareScore
x Score
y ofOrdering
EQ->forall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a b. a -> Either a b
Left(forall a. a -> Maybe a
JustScore
x )Ordering
LT->doScore
d <-forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips forall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a b. b -> Either a b
Right(Score
x forall a. Num a => a -> a -> a
+Score
d ,Score
y )Ordering
GT->doScore
d <-forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips forall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a b. b -> Either a b
Right(Score
x ,Score
y forall a. Num a => a -> a -> a
+Score
d )gameFast ::Score ->Score ->Dist (Score ,Score )->Dist (MaybeScore )gameFast :: Score -> Score -> Dist (Score, Score) -> Dist (Maybe Score)
gameFast Score
maxPips Score
maxScore Dist (Score, Score)
start =forall prob a b.
Fractional prob =>
(a -> Maybe b) -> T prob a -> T prob b
Dist.mapMaybe (forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
eitherforall a. a -> Maybe a
Just(forall a. HasCallStack => String -> a
errorString
"the game must be finished after maxScore moves"))forall a b. (a -> b) -> a -> b
$forall a. Score -> (a -> a) -> a -> a
nest(Score
maxScore forall a. Num a => a -> a -> a
+Score
1)(Score
-> Score
-> Dist (Either (Maybe Score) (Score, Score))
-> Dist (Either (Maybe Score) (Score, Score))
gameRound Score
maxPips Score
maxScore )(forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmapforall a b. b -> Either a b
RightDist (Score, Score)
start )gameFastEither ::Score ->Score ->Dist (Score ,Score )->Dist (MaybeScore )gameFastEither :: Score -> Score -> Dist (Score, Score) -> Dist (Maybe Score)
gameFastEither Score
maxPips Score
maxScore =forall prob a b.
(Num prob, Ord a, Ord b) =>
(a -> T prob (Either b a)) -> T prob a -> T prob b
Trans.untilLeft forall a b. (a -> b) -> a -> b
$\(Score
x ,Score
y )->ifScore
maxScore forall a. Ord a => a -> a -> Bool
<forall a. Ord a => a -> a -> a
maxScore
x Score
y thenforall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a b. a -> Either a b
Leftforall a. Maybe a
Nothingelsecaseforall a. Ord a => a -> a -> Ordering
compareScore
x Score
y ofOrdering
EQ->forall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a b. a -> Either a b
Left(forall a. a -> Maybe a
JustScore
x )Ordering
LT->doScore
d <-forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips forall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a b. b -> Either a b
Right(Score
x forall a. Num a => a -> a -> a
+Score
d ,Score
y )Ordering
GT->doScore
d <-forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips forall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a b. b -> Either a b
Right(Score
x ,Score
y forall a. Num a => a -> a -> a
+Score
d ){- |
This version could be generalized
to both Random and Distribution monad
while remaining efficient.
-}gameFastFix ::Score ->Score ->Dist (Score ,Score )->Dist (MaybeScore )gameFastFix :: Score -> Score -> Dist (Score, Score) -> Dist (Maybe Score)
gameFastFix Score
maxPips Score
maxScore =forall prob a b.
(Num prob, Ord a, Ord b) =>
((a -> ExceptT a (T prob) b) -> a -> ExceptT a (T prob) b)
-> T prob a -> T prob b
Trans.fix forall a b. (a -> b) -> a -> b
$\(Score, Score)
-> ExceptT (Score, Score) (T Probability) (Maybe Score)
go (Score
x ,Score
y )->ifScore
maxScore forall a. Ord a => a -> a -> Bool
<forall a. Ord a => a -> a -> a
maxScore
x Score
y thenforall (m :: * -> *) a. Monad m => a -> m a
returnforall a. Maybe a
Nothingelsecaseforall a. Ord a => a -> a -> Ordering
compareScore
x Score
y ofOrdering
EQ->forall (m :: * -> *) a. Monad m => a -> m a
return(forall a. a -> Maybe a
JustScore
x )Ordering
LT->doScore
d <-forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips (Score, Score)
-> ExceptT (Score, Score) (T Probability) (Maybe Score)
go (Score
x forall a. Num a => a -> a -> a
+Score
d ,Score
y )Ordering
GT->doScore
d <-forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips (Score, Score)
-> ExceptT (Score, Score) (T Probability) (Maybe Score)
go (Score
x ,Score
y forall a. Num a => a -> a -> a
+Score
d ){- |
In 'gameFastFix' we group the scores by rounds.
This leads to a growing probability distribution,
but we do not need the round number.
We could process the game in a different way:
We only consider the game states
where the lower score matches the round number.
-}gameLeastScore ::Score ->Score ->Dist (Score ,Score )->Dist (MaybeScore )gameLeastScore :: Score -> Score -> Dist (Score, Score) -> Dist (Maybe Score)
gameLeastScore Score
maxPips Score
maxScore =(forall prob a b.
(Num prob, Ord a, Ord b) =>
((a -> ExceptT a (T prob) b) -> a -> ExceptT a (T prob) b)
-> T prob a -> T prob b
Trans.fix forall a b. (a -> b) -> a -> b
$\(Score, (Score, Score))
-> ExceptT (Score, (Score, Score)) (T Probability) (Maybe Score)
go (Score
n ,(Score
x ,Score
y ))->ifScore
n forall a. Ord a => a -> a -> Bool
>Score
maxScore thenforall (m :: * -> *) a. Monad m => a -> m a
returnforall a. Maybe a
Nothingelseletnext :: (Score, Score)
-> ExceptT (Score, (Score, Score)) (T Probability) (Maybe Score)
next =(Score, (Score, Score))
-> ExceptT (Score, (Score, Score)) (T Probability) (Maybe Score)
go forall b c a. (b -> c) -> (a -> b) -> a -> c
.(,)(forall a. Enum a => a -> a
succScore
n )incase(Score
x forall a. Eq a => a -> a -> Bool
==Score
n ,Score
y forall a. Eq a => a -> a -> Bool
==Score
n )of(Bool
False,Bool
False)->(Score, Score)
-> ExceptT (Score, (Score, Score)) (T Probability) (Maybe Score)
next (Score
x ,Score
y )(Bool
True,Bool
False)->doScore
d <-forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips (Score, Score)
-> ExceptT (Score, (Score, Score)) (T Probability) (Maybe Score)
next (Score
x forall a. Num a => a -> a -> a
+Score
d ,Score
y )(Bool
False,Bool
True)->doScore
d <-forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips (Score, Score)
-> ExceptT (Score, (Score, Score)) (T Probability) (Maybe Score)
next (Score
x ,Score
y forall a. Num a => a -> a -> a
+Score
d )(Bool
True,Bool
True)->forall (m :: * -> *) a. Monad m => a -> m a
return(forall a. a -> Maybe a
JustScore
x ))forall b c a. (b -> c) -> (a -> b) -> a -> c
.forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap((,)Score
0){- |
'gameLeastScore' can be written in terms of a matrix power.
For n pips we need a n² × n² matrix.
Using symmetries, we reduce it to a square matrix with size n·(n+1)/2.
/ p[n+1,(n+1,n+1)] \ / p[n,(n+0,n+0)] \
| p[n+1,(n+1,n+2)] | | p[n,(n+0,n+1)] |
| p[n+1,(n+1,n+3)] | | p[n,(n+0,n+2)] |
| ... | | ... |
| p[n+1,(n+1,n+6)] | = M/6 · | p[n,(n+0,n+5)] |
| p[n+1,(n+2,n+2)] | | p[n,(n+1,n+1)] |
| ... | | ... |
| p[n+1,(n+2,n+6)] | | p[n,(n+1,n+5)] |
| ... | | ... |
\ p[n+1,(n+6,n+6)] / \ p[n,(n+5,n+5)] /
M[(n+1,(x,y)),(n,(x,y))] = 6
M[(n+1,(min y (n+d), max y (n+d))), (n,(n,y))] = 1
M[(n+1,(x1,y1)),(n,(x0,y0))] = 0
-}flattenedMatrix ::Score ->[Int]flattenedMatrix :: Score -> [Score]
flattenedMatrix Score
maxPips =doScore
x1 <-[Score
1..Score
maxPips ]Score
y1 <-[Score
x1 ..Score
maxPips ]Score
x0 <-[Score
0..Score
maxPips forall a. Num a => a -> a -> a
-Score
1]Score
y0 <-[Score
x0 ..Score
maxPips forall a. Num a => a -> a -> a
-Score
1]forall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a. Bool -> a -> a -> a
if'((Score
x0 ,Score
y0 )forall a. Eq a => a -> a -> Bool
==(Score
x1 ,Score
y1 ))Score
maxPips forall a b. (a -> b) -> a -> b
$forall a. Bool -> a -> a -> a
if'(Score
x0 forall a. Eq a => a -> a -> Bool
==Score
0Bool -> Bool -> Bool
&&(Score
y0 forall a. Eq a => a -> a -> Bool
==Score
x1 Bool -> Bool -> Bool
||Score
y0 forall a. Eq a => a -> a -> Bool
==Score
y1 ))Score
1Score
0{-
let e0 = [1,0,0,...,0]
The cumulated probability is
e0 * (I + M + M^2 + ... + M^(n-1)) * startVector
and with M = V*D*V^-1 we get
e0 * V * (I + D + D^2 + ... + D^(n-1)) * V^-1 * startVector
e0 * (I - M^n) * (I-M)^(-1) * startVector
-}startVector ::Score ->[Int]startVector :: Score -> [Score]
startVector Score
maxPips =doScore
x <-[Score
0..Score
maxPips forall a. Num a => a -> a -> a
-Score
1]Score
y <-[Score
x ..Score
maxPips forall a. Num a => a -> a -> a
-Score
1]forall (m :: * -> *) a. Monad m => a -> m a
returnforall a b. (a -> b) -> a -> b
$forall a. Bool -> a -> a -> a
if'(Score
x forall a. Eq a => a -> a -> Bool
==Score
y )Score
1Score
2compareMaybe ::(Orda )=>Maybea ->Maybea ->OrderingcompareMaybe :: forall a. Ord a => Maybe a -> Maybe a -> Ordering
compareMaybe Maybe a
NothingMaybe a
_=Ordering
GTcompareMaybe Maybe a
_Maybe a
Nothing=Ordering
LTcompareMaybe (Justa
a )(Justa
b )=forall a. Ord a => a -> a -> Ordering
comparea
a a
b cumulate ::(Orda )=>Dist (Maybea )->[(Maybea ,Probability )]cumulate :: forall a. Ord a => Dist (Maybe a) -> [(Maybe a, Probability)]
cumulate =forall a b c. (a -> b -> c) -> (a, b) -> c
uncurryforall a b. [a] -> [b] -> [(a, b)]
zipforall b c a. (b -> c) -> (a -> b) -> a -> c
.forall b c a. (b -> c) -> (a, b) -> (a, c)
mapSnd(forall a. (a -> a -> a) -> [a] -> [a]
scanl1forall a. Num a => a -> a -> a
(+))forall b c a. (b -> c) -> (a -> b) -> a -> c
.forall a b. [(a, b)] -> ([a], [b])
unzipforall b c a. (b -> c) -> (a -> b) -> a -> c
.forall a. (a -> a -> Ordering) -> [a] -> [a]
List.sortBy(forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
compose2forall a. Ord a => Maybe a -> Maybe a -> Ordering
compareMaybe forall a b. (a, b) -> a
fst)forall b c a. (b -> c) -> (a -> b) -> a -> c
.forall prob a. T prob a -> [(a, prob)]
Dist.decons runExact ::Score ->IO()runExact :: Score -> IO ()
runExact Score
maxPips =forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_(\(Maybe Score
m ,Probability
p )->caseMaybe Score
m ofJustScore
n ->forall r. PrintfType r => String -> r
P.printfString
"%4d %7.2f %s\n"Score
n (forall a. Fractional a => Probability -> a
fromRational(Probability
100forall a. Num a => a -> a -> a
*Probability
p )::Double)(forall a. Show a => a -> String
showProbability
p )Maybe Score
Nothing->String -> IO ()
putStrLnforall a b. (a -> b) -> a -> b
$String
"total: "forall a. [a] -> [a] -> [a]
++forall a. Show a => a -> String
showProbability
p )forall a b. (a -> b) -> a -> b
$forall a. Ord a => Dist (Maybe a) -> [(Maybe a, Probability)]
cumulate forall a b. (a -> b) -> a -> b
$Score -> Score -> Dist (Score, Score) -> Dist (Maybe Score)
gameFastFix Score
maxPips Score
120forall a b. (a -> b) -> a -> b
$forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap((,)Score
0)forall a b. (a -> b) -> a -> b
$forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips trace ::Score ->[Score ]->[Score ]trace :: Score -> [Score] -> [Score]
trace Score
s xs :: [Score]
xs @(Score
x :[Score]
_)=Score
s forall a. a -> [a] -> [a]
:Score -> [Score] -> [Score]
trace (Score
s forall a. Num a => a -> a -> a
+Score
x )(forall a. Score -> [a] -> [a]
dropScore
x [Score]
xs )trace Score
s []=[Score
s ]chop ::[Score ]->[[Score ]]chop :: [Score] -> [[Score]]
chop []=[]chop xs :: [Score]
xs @(Score
x :[Score]
_)=forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry(:)forall a b. (a -> b) -> a -> b
$forall b c a. (b -> c) -> (a, b) -> (a, c)
mapSnd[Score] -> [[Score]]
chop forall a b. (a -> b) -> a -> b
$forall a. Score -> [a] -> ([a], [a])
splitAtScore
x [Score]
xs meeting ::[Score ]->[Score ]->MaybeScore meeting :: [Score] -> [Score] -> Maybe Score
meeting xt :: [Score]
xt @(Score
x :[Score]
xs )yt :: [Score]
yt @(Score
y :[Score]
ys )=caseforall a. Ord a => a -> a -> Ordering
compareScore
x Score
y ofOrdering
LT->[Score] -> [Score] -> Maybe Score
meeting [Score]
xs [Score]
yt Ordering
GT->[Score] -> [Score] -> Maybe Score
meeting [Score]
xt [Score]
ys Ordering
EQ->forall a. a -> Maybe a
JustScore
x meeting [Score]
_[Score]
_=forall a. Maybe a
Nothing{- |
This is a bruteforce implementation of the original game:
We just roll the die @maxScore@ times
and then jump from die to die according to the number of pips.
-}bruteforce ::Score ->Score ->(Score ,Score )->Random.T (MaybeScore )bruteforce :: Score -> Score -> (Score, Score) -> T (Maybe Score)
bruteforce Score
maxPips Score
maxScore (Score
x ,Score
y )=do[Score]
points <-forall (m :: * -> *) a. Applicative m => Score -> m a -> m [a]
replicateMScore
maxScore forall a b. (a -> b) -> a -> b
$forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips letrun :: Score -> [Score]
run Score
s =Score -> [Score] -> [Score]
trace Score
s (forall a. Score -> [a] -> [a]
dropScore
s [Score]
points )forall (m :: * -> *) a. Monad m => a -> m a
return([Score] -> [Score] -> Maybe Score
meeting (Score -> [Score]
run Score
x )(Score -> [Score]
run Score
y ))runSimulation ::Score ->IO()runSimulation :: Score -> IO ()
runSimulation Score
maxPips =forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_(\(Maybe Score
m ,Probability
p )->caseMaybe Score
m ofJustScore
n ->forall r. PrintfType r => String -> r
P.printfString
"%4d %7.2f\n"Score
n (forall a. Fractional a => Probability -> a
fromRational(Probability
100forall a. Num a => a -> a -> a
*Probability
p )::Double)Maybe Score
Nothing->String -> IO ()
putStrLnforall a b. (a -> b) -> a -> b
$String
"total: "forall a. [a] -> [a] -> [a]
++forall a. Show a => a -> String
showProbability
p )forall a b. (a -> b) -> a -> b
$forall a. Ord a => Dist (Maybe a) -> [(Maybe a, Probability)]
cumulate forall a b. (a -> b) -> a -> b
$forall a. StdGen -> T a -> a
Random.runSeed (Score -> StdGen
Rnd.mkStdGenScore
42)forall a b. (a -> b) -> a -> b
$forall prob a.
(Fractional prob, Ord a) =>
[T a] -> Distribution prob a
Random.dist forall a b. (a -> b) -> a -> b
$forall a. Score -> a -> [a]
replicateScore
100000forall a b. (a -> b) -> a -> b
$Score -> Score -> (Score, Score) -> T (Maybe Score)
bruteforce Score
maxPips Score
120forall b c a. (b -> c) -> (a -> b) -> a -> c
.(,)Score
0forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
maxPips latexDie ::Score ->StringlatexDie :: Score -> String
latexDie Score
pips =String
"\\epsdice{"forall a. [a] -> [a] -> [a]
++forall a. Show a => a -> String
showScore
pips forall a. [a] -> [a] -> [a]
++String
"}"latexMarkedDie ::Score ->StringlatexMarkedDie :: Score -> String
latexMarkedDie Score
pips =String
"\\epsdice[black]{"forall a. [a] -> [a] -> [a]
++forall a. Show a => a -> String
showScore
pips forall a. [a] -> [a] -> [a]
++String
"}"latexFromChain ::[Score ]->StringlatexFromChain :: [Score] -> String
latexFromChain =[String] -> String
unlinesforall b c a. (b -> c) -> (a -> b) -> a -> c
.forall a b. (a -> b) -> [a] -> [b]
mapScore -> String
latexDie latexChoppedFromChain ::[Score ]->StringlatexChoppedFromChain :: [Score] -> String
latexChoppedFromChain =[String] -> String
unlinesforall b c a. (b -> c) -> (a -> b) -> a -> c
.forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap(\(Score
p :[Score]
ps )->Score -> String
latexMarkedDie Score
p forall a. a -> [a] -> [a]
:forall a b. (a -> b) -> [a] -> [b]
mapScore -> String
latexDie [Score]
ps )forall b c a. (b -> c) -> (a -> b) -> a -> c
.[Score] -> [[Score]]
chop makeChains ::IO()makeChains :: IO ()
makeChains =doletchains :: [[Score]]
chains =forall a b. (a -> b) -> [a] -> [b]
map(\Score
seed ->forall a. StdGen -> T a -> a
Random.runSeed (Score -> StdGen
Rnd.mkStdGenScore
seed )forall a b. (a -> b) -> a -> b
$forall (m :: * -> *) a. Applicative m => Score -> m a -> m [a]
replicateMScore
42forall a b. (a -> b) -> a -> b
$forall prob (experiment :: * -> *).
(C prob experiment, Fractional prob) =>
Score -> experiment Score
die Score
6)[Score
30..Score
42]String -> String -> IO ()
writeFileString
"KruskalDice.tex"forall a b. (a -> b) -> a -> b
$String
"\\noindent\n"forall a. [a] -> [a] -> [a]
++(forall a. [a] -> [[a]] -> [a]
List.intercalateString
"\\\\[4ex]\n"forall a b. (a -> b) -> a -> b
$forall a b. (a -> b) -> [a] -> [b]
map((String
"$\\rightarrow$"forall a. [a] -> [a] -> [a]
++)forall b c a. (b -> c) -> (a -> b) -> a -> c
.[Score] -> String
latexFromChain )[[Score]]
chains )forall a. [a] -> [a] -> [a]
++String
"\\newpage\n"forall a. [a] -> [a] -> [a]
++String
"\\noindent\n"forall a. [a] -> [a] -> [a]
++(forall a. [a] -> [[a]] -> [a]
List.intercalateString
"\\\\[4ex]\n"forall a b. (a -> b) -> a -> b
$forall a b. (a -> b) -> [a] -> [b]
map((String
"$\\rightarrow$"forall a. [a] -> [a] -> [a]
++)forall b c a. (b -> c) -> (a -> b) -> a -> c
.[Score] -> String
latexChoppedFromChain )[[Score]]
chains )

AltStyle によって変換されたページ (->オリジナル) /