content: import qualified Data.List as L
  import System.IO
  import System.Random
  
  data CoinToss = H | T deriving (Read, Show, Eq)
  
  parseToss :: String -> [CoinToss]
  parseToss [] = []
  parseToss (s:sx)
    | s == 'h' || s == 'H' = H : parseToss sx
    | s == 't' || s == 'T' = T : parseToss sx
    | otherwise = parseToss sx
  
  notToss :: CoinToss -> CoinToss
  notToss H = T
  notToss T = H
  
  instance Random CoinToss where
    random g = let (b, gb) = random g in (if b then H else T, gb)
    randomR = undefined
  
  prompt :: (Read a) => String -> String -> (String -> Maybe a) -> IO a
  prompt msg err parse = do
    putStrLn msg
    line <- getLine
    let ans = parse line
    case ans of
      Nothing   -> do
        putStrLn err
        prompt msg err parse
      Just ansB -> return ansB
  
  showCat :: (Show a) => [a] -> String
  showCat = concatMap show
  
  data Winner = Player | CPU
  
  -- This may never terminate.
  runToss :: (RandomGen g) => [CoinToss] -> [CoinToss] -> g -> ([CoinToss], Winner)
  runToss player cpu gen =
    let stream = randoms gen
        run ss@(s:sx)
          | L.isPrefixOf player ss = player
          | L.isPrefixOf cpu ss    = cpu
          | otherwise              = s : run sx
        winner = run stream
    in if L.isSuffixOf player winner
       then (winner, Player)
       else (winner, CPU)
  
  game :: (RandomGen g, Num a, Show a) => Bool -> a -> a -> g -> IO ()
  game cpuTurn playerScore cpuScore gen = do
    putStrLn $ "\nThe current score is CPU: " ++ show cpuScore
      ++ ", You: " ++ show playerScore
  
    let (genA, genB) = split gen
        promptPlayer check =
          prompt "Pick 3 coin sides: " "Invalid input." $ \s ->
            let tosses = parseToss s in
            if check tosses then Just tosses else Nothing
        promptCpu x  = putStrLn $ "I have chosen: " ++ showCat x
  
    (tosses, winner) <-
      if cpuTurn
      then do
        let cpuChoice = take 3 $ randoms gen
        promptCpu cpuChoice
        playerChoice <- promptPlayer $ \n -> n /= cpuChoice && 3 == length n
        return $ runToss playerChoice cpuChoice genA
      else do
        playerChoice <- promptPlayer $ \n -> 3 == length n
        let cpuChoice = case playerChoice of [a,b,_] -> [notToss b, a, b]
        promptCpu cpuChoice
        return $ runToss playerChoice cpuChoice genA
  
    putStrLn $ "The sequence tossed was: " ++ showCat tosses
  
    case winner of
      Player -> do
        putStrLn "You win!"
        game (not cpuTurn) (playerScore + 1) cpuScore genB
      CPU -> do
        putStrLn "I win!"
        game (not cpuTurn) playerScore (cpuScore + 1) genB
  
  main :: IO ()
  main = do
    hSetBuffering stdin LineBuffering
    stdgen <- getStdGen
    let (cpuFirst, genA) = random stdgen
    game cpuFirst 0 0 genA
  