-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHangmanState.hs
83 lines (69 loc) · 2.87 KB
/
HangmanState.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
{-# LANGUAGE FlexibleContexts #-}
-- File: Hangman.hs
-- Author: Patrick MacArthur
{- A simple interactive hangman game. -}
module HangmanState
( HangmanResult(..)
, HangmanState()
, newGame
, guessLetter
, showPartialWord
, guessList
, returnBadGuesses
, maxBadGuesses
) where
import Control.Monad.State
import Data.Char
import Data.List
data HangmanResult = Solved String | Lost String | GoodGuess | BadGuess | RepeatGuess
data HangmanState = HangmanState { word :: String
, guesses :: [Char]
, badGuessCount :: Int
}
{- Maximum number of bad guesses before we end the game. -}
maxBadGuesses = 7
{- An initial state for a hangman game, given a word. -}
newGame :: String -> HangmanState
newGame w = HangmanState { word = w, guesses = [], badGuessCount = 0 }
{- Return the list of guesses so far. -}
guessList :: (MonadState HangmanState m) => m [Char]
guessList = get >>= \state -> return $ guesses state
{- Takes the human's guess and checks it. Returns an appropriate result and a
- new game state. -}
guessLetter :: (MonadState HangmanState m) => Char -> m HangmanResult
guessLetter guess = get >>= helper
where helper state
| guess `elem` (guesses state) = return RepeatGuess
| otherwise = addGuess guess >> get >>= helper'
helper' state
| guess `elem` word state =
solved >>= \x -> return $
if x then Solved $ word state else GoodGuess
| otherwise = incrementBadGuesses >> get >>= helper''
helper'' state
| badGuessCount state < maxBadGuesses = return BadGuess
| otherwise = return $ Lost $ word state
{- Adds the guess to the list of guesses. -}
addGuess :: (MonadState HangmanState m) => Char -> m ()
addGuess guess = modify $ \state ->
state { guesses = sort $ guess:(guesses state) }
{- Increments the bad guess count. -}
incrementBadGuesses :: (MonadState HangmanState m) => m ()
incrementBadGuesses = modify $ \state ->
state { badGuessCount = succ (badGuessCount state) }
{- Returns the number of bad guesses given. -}
returnBadGuesses :: (MonadState HangmanState m) => m Int
returnBadGuesses = get >>= \state -> return $ badGuessCount state
{- True if the word has been solved with the given guesses. -}
solved :: (MonadState HangmanState m) => m Bool
solved = get >>= \state -> return $
foldr (helper $ guesses state) True (word state)
where helper _ _ False = False
helper guesses x True = x `elem` guesses
{- The word with all non-guessed characters as underscores. -}
showPartialWord :: (MonadState HangmanState m) => m String
showPartialWord = get >>= \state -> return $
map (helper $ guesses state) (word state)
where helper guesses x
| x `elem` guesses = x
| otherwise = '_'