@@ -9,7 +9,9 @@ import System.Random (randomRIO)
9
9
10
10
main :: IO ()
11
11
main = do
12
- putStrLn " hello world"
12
+ word <- randomWord'
13
+ let puzzle = freshPuzzle (fmap toLower word)
14
+ runGame puzzle
13
15
14
16
type WordList = [String ]
15
17
@@ -39,3 +41,83 @@ randomWord wl = do
39
41
40
42
randomWord' :: IO String
41
43
randomWord' = gameWords >>= randomWord
44
+
45
+ data Puzzle = Puzzle String [Maybe Char ] [Char ]
46
+ -- the word we're trying to guess
47
+ -- the characters we've filled in so far
48
+ -- the letters we've guessed so far
49
+
50
+ instance Show Puzzle where
51
+ show (Puzzle _ discovered guessed) =
52
+ (intersperse ' ' $ fmap renderPuzzleChar discovered)
53
+ ++ " Guessed so far: " ++ guessed
54
+
55
+ renderPuzzleChar :: Maybe Char -> Char
56
+ renderPuzzleChar = maybe ' _' id
57
+
58
+ freshPuzzle :: String -> Puzzle
59
+ freshPuzzle word = Puzzle word discovered []
60
+ where discovered = fmap (const Nothing ) word
61
+
62
+ charInWord :: Puzzle -> Char -> Bool
63
+ charInWord (Puzzle word _ _) c = elem c word
64
+
65
+ alreadyGuessed :: Puzzle -> Char -> Bool
66
+ alreadyGuessed (Puzzle _ _ guessed) c = elem c guessed
67
+
68
+ fillInCharacter :: Puzzle -> Char -> Puzzle
69
+ fillInCharacter (Puzzle word fillInSoFar s) c =
70
+ Puzzle word newFilledInSoFar (c : s)
71
+ where
72
+ zipper guessed wordChar guessChar =
73
+ if wordChar == guessed then Just wordChar else guessChar
74
+
75
+ newFilledInSoFar =
76
+ zipWith (zipper c) word fillInSoFar
77
+
78
+ -- For e.g. let c = 'h', word = "his", filledInSoFar = [Nothing, Just 'i', Nothing]
79
+ -- then zipper 'h' 'h' Nothing = Just 'h'
80
+ -- zipper 'h' 'i' Just 'i' = Just 'i'
81
+ -- zipper 'h' 's' Nothing = Nothing
82
+
83
+ handleGuess :: Puzzle -> Char -> IO Puzzle
84
+ handleGuess puzzle guess = do
85
+ putStrLn $ " Your guess was: " ++ [guess]
86
+ case (charInWord puzzle guess, alreadyGuessed puzzle guess) of
87
+ (_, True ) -> do
88
+ putStrLn " You already guessed that character, pick something else!"
89
+ return puzzle
90
+
91
+ (True , _) -> do
92
+ putStrLn " This character was in the word, filling in the word accordingly."
93
+ return (fillInCharacter puzzle guess)
94
+
95
+ (False , _) -> do
96
+ putStrLn " This character wasn't in the word, try again."
97
+ return (fillInCharacter puzzle guess)
98
+
99
+ gameOver :: Puzzle -> IO ()
100
+ gameOver (Puzzle wordToGuess _ guessed) =
101
+ if (length guessed) > 7 then
102
+ do putStrLn " You lose!"
103
+ putStrLn $ " The word was: " ++ wordToGuess
104
+ exitSuccess
105
+ else return ()
106
+
107
+ gameWin :: Puzzle -> IO ()
108
+ gameWin (Puzzle _ filledInSoFar _) =
109
+ if all isJust filledInSoFar then
110
+ do putStrLn " You win!"
111
+ exitSuccess
112
+ else return ()
113
+
114
+ runGame :: Puzzle -> IO ()
115
+ runGame puzzle = forever $ do
116
+ gameOver puzzle
117
+ gameWin puzzle
118
+ putStrLn $ " Current puzzle is: " ++ show puzzle
119
+ putStr " Guess a letter: "
120
+ guess <- getLine
121
+ case guess of
122
+ [c] -> handleGuess puzzle c >>= runGame
123
+ _ -> putStrLn " Your guess must be a single character."
0 commit comments