Skip to content

Commit b3c33b2

Browse files
committed
Update the Hangman game from ch13
1 parent 96b04c3 commit b3c33b2

File tree

5 files changed

+74
-53
lines changed

5 files changed

+74
-53
lines changed

ch13/hangman/LICENSE

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright Author name here (c) 2016
1+
Copyright Dwayne Crooks (c) 2017
22

33
All rights reserved.
44

@@ -13,7 +13,7 @@ modification, are permitted provided that the following conditions are met:
1313
disclaimer in the documentation and/or other materials provided
1414
with the distribution.
1515

16-
* Neither the name of Author name here nor the names of other
16+
* Neither the name of Dwayne Crooks nor the names of other
1717
contributors may be used to endorse or promote products derived
1818
from this software without specific prior written permission.
1919

ch13/hangman/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# hangman

ch13/hangman/hangman.cabal

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
name: hangman
22
version: 0.1.0.0
33
synopsis: Playing Hangman
4-
description: Please see README.md
5-
homepage: https://github.com/dwayne/hangman
4+
homepage: https://github.com/dwayne/hangman#readme
65
license: BSD3
76
license-file: LICENSE
87
author: Dwayne Crooks
98
maintainer: me@dwaynecrooks.com
10-
copyright: 2016 Dwayne Crooks
9+
copyright: 2017 Dwayne Crooks
1110
category: Game
1211
build-type: Simple
13-
extra-source-files: data/dict.txt
1412
cabal-version: >=1.10
13+
extra-source-files: README.md
14+
, data/dict.txt
1515

1616
executable hangman
1717
hs-source-dirs: src
1818
main-is: Main.hs
1919
default-language: Haskell2010
2020
build-depends: base >= 4.7 && < 5
21-
, random == 1.1
22-
, split == 0.2.3
21+
, random
22+
, split

ch13/hangman/src/Main.hs

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,80 +5,87 @@ import Data.Char (toLower)
55
import Data.Maybe (isJust)
66
import Data.List (intersperse)
77
import System.Exit (exitSuccess)
8+
import System.IO
9+
810
import System.Random (randomRIO)
911

10-
main :: IO ()
11-
main = do
12-
word <- randomWord'
13-
let puzzle = freshPuzzle (fmap toLower word)
14-
runGame puzzle
1512

1613
type WordList = [String]
1714

15+
1816
allWords :: IO WordList
1917
allWords = do
2018
dict <- readFile "data/dict.txt"
2119
return (lines dict)
2220

21+
2322
minWordLength :: Int
2423
minWordLength = 5
2524

25+
2626
maxWordLength :: Int
2727
maxWordLength = 9
2828

29+
2930
gameWords :: IO WordList
3031
gameWords = do
3132
aw <- allWords
32-
return $ filter gameLength aw
33-
where gameLength w =
34-
let l = length (w :: String)
35-
in l > minWordLength && l < maxWordLength
33+
return (filter gameLength aw)
34+
where
35+
gameLength w =
36+
let
37+
l = length (w :: String)
38+
in
39+
l > minWordLength && l < maxWordLength
40+
3641

3742
randomWord :: WordList -> IO String
3843
randomWord wl = do
3944
randomIndex <- randomRIO (0, length wl - 1)
4045
return $ wl !! randomIndex
4146

47+
4248
randomWord' :: IO String
4349
randomWord' = gameWords >>= randomWord
4450

51+
4552
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
53+
4954

5055
instance Show Puzzle where
5156
show (Puzzle _ discovered guessed) =
5257
(intersperse ' ' $ fmap renderPuzzleChar discovered)
5358
++ " Guessed so far: " ++ guessed
5459

55-
renderPuzzleChar :: Maybe Char -> Char
56-
renderPuzzleChar = maybe '_' id
5760

5861
freshPuzzle :: String -> Puzzle
59-
freshPuzzle word = Puzzle word discovered []
60-
where discovered = fmap (const Nothing) word
62+
freshPuzzle w = Puzzle w (map (const Nothing) w) []
63+
6164

6265
charInWord :: Puzzle -> Char -> Bool
6366
charInWord (Puzzle word _ _) c = elem c word
6467

68+
6569
alreadyGuessed :: Puzzle -> Char -> Bool
6670
alreadyGuessed (Puzzle _ _ guessed) c = elem c guessed
6771

72+
73+
renderPuzzleChar :: Maybe Char -> Char
74+
renderPuzzleChar Nothing = '_'
75+
renderPuzzleChar (Just c) = c
76+
77+
6878
fillInCharacter :: Puzzle -> Char -> Puzzle
69-
fillInCharacter (Puzzle word fillInSoFar s) c =
79+
fillInCharacter (Puzzle word filledInSoFar s) c =
7080
Puzzle word newFilledInSoFar (c : s)
7181
where
7282
zipper guessed wordChar guessChar =
73-
if wordChar == guessed then Just wordChar else guessChar
83+
if wordChar == guessed
84+
then Just wordChar
85+
else guessChar
7486

75-
newFilledInSoFar =
76-
zipWith (zipper c) word fillInSoFar
87+
newFilledInSoFar = zipWith (zipper c) word filledInSoFar
7788

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
8289

8390
handleGuess :: Puzzle -> Char -> IO Puzzle
8491
handleGuess puzzle guess = do
@@ -87,29 +94,34 @@ handleGuess puzzle guess = do
8794
(_, True) -> do
8895
putStrLn "You already guessed that character, pick something else!"
8996
return puzzle
90-
9197
(True, _) -> do
9298
putStrLn "This character was in the word, filling in the word accordingly."
9399
return (fillInCharacter puzzle guess)
94-
95100
(False, _) -> do
96101
putStrLn "This character wasn't in the word, try again."
97102
return (fillInCharacter puzzle guess)
98103

104+
99105
gameOver :: Puzzle -> IO ()
100106
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 ()
107+
if (length guessed) > 7
108+
then do
109+
putStrLn "You lose!"
110+
putStrLn $ "The word was: " ++ wordToGuess
111+
exitSuccess
112+
else
113+
return ()
114+
106115

107116
gameWin :: Puzzle -> IO ()
108117
gameWin (Puzzle _ filledInSoFar _) =
109-
if all isJust filledInSoFar then
110-
do putStrLn "You win!"
111-
exitSuccess
112-
else return ()
118+
if all isJust filledInSoFar
119+
then do
120+
putStrLn "You win!"
121+
exitSuccess
122+
else
123+
return ()
124+
113125

114126
runGame :: Puzzle -> IO ()
115127
runGame puzzle = forever $ do
@@ -121,3 +133,11 @@ runGame puzzle = forever $ do
121133
case guess of
122134
[c] -> handleGuess puzzle c >>= runGame
123135
_ -> putStrLn "Your guess must be a single character."
136+
137+
138+
main :: IO ()
139+
main = do
140+
hSetBuffering stdout NoBuffering
141+
word <- randomWord'
142+
let puzzle = freshPuzzle (fmap toLower word)
143+
runGame puzzle

ch13/hangman/stack.yaml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
# This file was automatically generated by 'stack init'
2-
#
2+
#
33
# Some commonly used options have been documented as comments in this file.
44
# For advanced use and comprehensive documentation of the format, please see:
55
# http://docs.haskellstack.org/en/stable/yaml_configuration/
66

77
# Resolver to choose a 'specific' stackage snapshot or a compiler version.
88
# A snapshot resolver dictates the compiler version and the set of packages
99
# to be used for project dependencies. For example:
10-
#
10+
#
1111
# resolver: lts-3.5
1212
# resolver: nightly-2015-09-21
1313
# resolver: ghc-7.10.2
1414
# resolver: ghcjs-0.1.0_ghc-7.10.2
1515
# resolver:
1616
# name: custom-snapshot
1717
# location: "./custom-snapshot.yaml"
18-
resolver: lts-5.15
18+
resolver: lts-8.2
1919

2020
# User packages to be built.
2121
# Various formats can be used as shown in the example below.
22-
#
22+
#
2323
# packages:
2424
# - some-directory
2525
# - https://example.com/foo/bar/baz-0.0.2.tar.gz
@@ -31,7 +31,7 @@ resolver: lts-5.15
3131
# subdirs:
3232
# - auto-update
3333
# - wai
34-
#
34+
#
3535
# A package marked 'extra-dep: true' will only be built if demanded by a
3636
# non-dependency (i.e. a user package), and its test suites and benchmarks
3737
# will not be run. This is useful for tweaking upstream packages.
@@ -49,18 +49,18 @@ extra-package-dbs: []
4949

5050
# Control whether we use the GHC we find on the path
5151
# system-ghc: true
52-
#
52+
#
5353
# Require a specific version of stack, using version ranges
5454
# require-stack-version: -any # Default
55-
# require-stack-version: ">=1.1"
56-
#
55+
# require-stack-version: ">=1.3"
56+
#
5757
# Override the architecture used by stack, especially useful on Windows
5858
# arch: i386
5959
# arch: x86_64
60-
#
60+
#
6161
# Extra directories used by stack for building
6262
# extra-include-dirs: [/path/to/dir]
6363
# extra-lib-dirs: [/path/to/dir]
64-
#
64+
#
6565
# Allow a newer minor version of GHC than the snapshot specifies
6666
# compiler-check: newer-minor

0 commit comments

Comments
 (0)