{- |
We play the following game:
We roll a die until we stop or we get three spots.
In the first case we own all spots obtained so far,
in the latter case we own nothing.

What is the strategy for maximizing the expected score?
-}
module Numeric.Probability.Example.DiceAccum where

import qualified Numeric.Probability.Random as Rnd
import qualified Numeric.Probability.Distribution as Dist
import qualified Numeric.Probability.Transition as Trans
import qualified Numeric.Probability.Monad as MonadExt
import Numeric.Probability.Trace (Trace)

import Numeric.Probability.Example.Dice (Die, )


type Score = Int


die :: Fractional prob => Dist.T prob Die
die :: forall prob. Fractional prob => T prob Score
die = forall prob a. Fractional prob => Spread prob a
Dist.uniform [Score
1..Score
6]

roll :: Fractional prob => Trans.T prob (Maybe Score)
roll :: forall prob. Fractional prob => T prob (Maybe Score)
roll =
   forall b a. b -> (a -> b) -> Maybe a -> b
maybe
     (forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing)
     (\Score
score -> forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall prob. Fractional prob => T prob Score
die forall a b. (a -> b) -> a -> b
$
         \Score
spots ->
            -- where is my beloved 'toMaybe' ?
            if Score
spots forall a. Eq a => a -> a -> Bool
== Score
3
              then forall a. Maybe a
Nothing
              else forall a. a -> Maybe a
Just (Score
score forall a. Num a => a -> a -> a
+ Score
spots))

continue :: Score -> Bool
continue :: Score -> Bool
continue Score
scoreInt =
   let score :: Rational
score = forall a b. (Integral a, Num b) => a -> b
fromIntegral Score
scoreInt :: Rational
   in  forall a. Num a => T a a -> a
Dist.expected
          (forall prob a. Fractional prob => Spread prob a
Dist.uniform (Rational
0 forall a. a -> [a] -> [a]
: forall a b. (a -> b) -> [a] -> [b]
map (Rational
scoreforall a. Num a => a -> a -> a
+) [Rational
1,Rational
2,Rational
4,Rational
5,Rational
6])) forall a. Ord a => a -> a -> Bool
> Rational
score

-- | optimal strategy
strategy :: Fractional prob => Trans.T prob (Maybe Score)
strategy :: forall prob. Fractional prob => T prob (Maybe Score)
strategy Maybe Score
s0 =
   forall b a. b -> (a -> b) -> Maybe a -> b
maybe
     (forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing)
     (\Score
score ->
         if Score -> Bool
continue Score
score
           then forall prob. Fractional prob => T prob (Maybe Score)
roll Maybe Score
s0
           else forall (m :: * -> *) a. Monad m => a -> m a
return Maybe Score
s0) Maybe Score
s0

-- | distribution of the scores that are achieved with the optimal strategy
game :: Fractional prob => Dist.T prob (Maybe Score)
game :: forall prob. Fractional prob => T prob (Maybe Score)
game =
   forall prob a. (Num prob, Ord a) => [T prob a] -> T prob a
Trans.compose (forall a. Score -> a -> [a]
replicate Score
18 forall prob. Fractional prob => T prob (Maybe Score)
strategy) (forall a. a -> Maybe a
Just Score
0)
   -- MonadExt.compose (replicate 8 turn) (Just 0)


{- too inefficient
game :: Fractional prob => Dist.T prob Score
game =
   let turn score =
          if continue score
            then roll score >>= \s -> if s==0 then return 0 else turn s
            else return score
   in  turn 0
-}


walk :: Int -> IO (Trace (Maybe Score))
walk :: Score -> IO (Trace (Maybe Score))
walk Score
n =
   forall a. T a -> IO a
Rnd.run forall a b. (a -> b) -> a -> b
$
   forall (m :: * -> *) a.
Monad m =>
Score -> (a -> m a) -> a -> m [a]
MonadExt.walk Score
n
      (forall prob a.
(Num prob, Ord prob, Random prob) =>
T prob a -> Change a
Rnd.change (forall prob. Fractional prob => T prob (Maybe Score)
roll :: Trans.T Double (Maybe Score)))
      (forall a. a -> Maybe a
Just Score
0)