import Random

data Move = Rock | Paper | Scissors deriving (Eq, Show)
data Strategy g = S (g -> (g, Move, Move -> Strategy g))

pureRock :: Strategy g
pureRock = S (\s -> (s, Rock, const pureRock))

rockOrPaper :: (RandomGen g) => Strategy g
rockOrPaper = S (\s -> let (r,s') = random s
                       in (s',
                           case r of True -> Rock
                                     False -> Paper,
                           const rockOrPaper))

play :: g -> Strategy g -> Strategy g -> Int -> (Int,Int,g)
play s s1 s2 0 = (0,0,s)
play s (S s1) (S s2) n = let (s',  m1, s1') = s1 s
                             (s'', m2, s2') = s2 s'
                             (n1, n2, s''') = play s'' (s1' m2) (s2' m1) (n-1)
                         in case (m1,m2) of
                            (Rock    , Scissors) -> (n1+1, n2, s''')
                            (Scissors, Paper   ) -> (n1+1, n2, s''')
                            (Paper   , Rock    ) -> (n1+1, n2, s''')
                            (Scissors, Rock    ) -> (n1, n2+1, s''')
                            (Paper   , Scissors) -> (n1, n2+1, s''')
                            (Rock    , Paper   ) -> (n1, n2+1, s''')
                            _                    -> (n1, n2  , s''')
