packages feed

Hangman-0.1.0.2: Hangman.hs

module Hangman where

import Control.Monad.Trans.State.Lazy
import Control.Monad.IO.Class

-- | Represents if a character is discovered.
data Letter = Hidden Char | Guessed Char

-- | Represents a word made up of letters.
type AWord = [Letter]

-- | The state of the Hangman game. 
data HangmanState = HangmanState AWord (Int,Int) [Char]

-- | The start of the game.
hangman :: String -> Int -> IO ()
hangman word guesses = do
  let word' = fmap (\x -> Hidden x) word
  (hs, s) <- evalStateT looper (HangmanState word' (0, guesses) [])
  showState hs
  case s of
   True -> putStrLn "You've won!"
   False -> putStrLn "You've lost!"

-- | An iteration of the game.
looper ::  StateT HangmanState IO (HangmanState, Bool)
looper = do
  hs@(HangmanState word (guess,guesses) guessed) <- get
  liftIO $ showState hs
  userChar <- liftIO getChar
  let word' = fmap (checkGuess userChar) word
  let hs' = (HangmanState word' (guess+1,guesses) (userChar:guessed))
  case complete word' of
   True -> return (hs', True)
   False -> case guess == guesses of
     True -> return (hs', False)
     False -> do
       put hs'
       looper

-- | Print the state of the game.
showState :: HangmanState -> IO()
showState (HangmanState word (guess, guesses) guessed) = do
  putStrLn $
    wordToString word ++
    " " ++
    (show guess) ++ "/" ++ (show guesses)
  putStrLn $
    "Guessed:" ++ (show guessed)

wordToString :: AWord -> String
wordToString = (fmap letterToChar)

letterToChar :: Letter -> Char
letterToChar l = case l of
  Hidden x -> '_'
  Guessed x -> x

-- | Transform a Hidden character into a Guessed character.
checkGuess :: Char -> Letter -> Letter
checkGuess c (Hidden x)
  | x == c = Guessed x
checkGuess c x = x

-- | Determine if we've reached the end of the game.
endGame :: AWord -> (Int,Int) -> Bool
endGame word (guess,guesses)
  | complete word = True
  | guess == guesses = True
  | otherwise = False


-- | Determine if the word is completely guessed.
complete :: AWord -> Bool
complete = all isGuessed

isGuessed :: Letter -> Bool
isGuessed l = case l of
                 Hidden x -> False
                 Guessed x -> True