{- |
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 = Dist.uniform [1..6]

roll :: Fractional prob => Trans.T prob (Maybe Score)
roll =
   maybe
     (return Nothing)
     (\score -> flip fmap die $
         \spots ->
            -- where is my beloved 'toMaybe' ?
            if spots == 3
              then Nothing
              else Just (score + spots))

continue :: Score -> Bool
continue scoreInt =
   let score = fromIntegral scoreInt :: Rational
   in  Dist.expected
          (Dist.uniform (0 : map (score+) [1,2,4,5,6])) > score

-- | optimal strategy
strategy :: Fractional prob => Trans.T prob (Maybe Score)
strategy s0 =
   maybe
     (return Nothing)
     (\score ->
         if continue score
           then roll s0
           else return s0) s0

-- | distribution of the scores that are achieved with the optimal strategy
game :: Fractional prob => Dist.T prob (Maybe Score)
game =
   Trans.compose (replicate 18 strategy) (Just 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 n =
   Rnd.run $
   MonadExt.walk n
      (Rnd.change (roll :: Trans.T Double (Maybe Score)))
      (Just 0)