First and foremost - the code:

import System.IO
import Data.List
import Data.Char

display :: String -> String
display word = intersperse ' ' [if c `elem` ['a'..'z'] then '_' else c | c <- word]

makeGuess :: String -> Char -> Int -> IO ()
makeGuess word letter guesses
	| letter `elem` word = play [if letter == c then toUpper letter else c | c <- word] guesses
	| otherwise = play word (guesses - 1)

play :: String -> Int -> IO ()
play word guesses
	| word == map toUpper word = do
		putStrLn $ display word
		putStrLn "You Win!"
	| guesses == 0 = do
		putStrLn $ display word
		putStrLn "You Lose..."
	| otherwise = do
		putStrLn $ "You have " ++ show guesses ++ " guesses left."
		putStrLn $ display word
		putStr "Guess a letter: "
		hFlush stdout
		userGuess <- getLine
		case userGuess of
			c:_ -> makeGuess word (toLower $ head userGuess) guesses
			_ -> putStrLn "Please enter a letter a-z" >> play word guesses

main :: IO ()
main = do
	putStrLn "Welcome to Haskell Hangman!"
	putStr "Enter a word (or sentence) to guess: "
	hFlush stdout
	userInput <- getLine -- Get a string from user and store it in userInput
	case userInput of
		c:_ -> play (map toLower userInput) 6 -- This last int is the amount of wrong guesses the player will have
		_ -> putStrLn "Please input at least one character!" >> main
	putStrLn "Thanks for playing!"

Back when I was attempting to learn Haskell for the first time I decided that writing hangman should be a fun task to experiment with. I had written a simple hangman game in NASM (x86) assembly about a year ago at the time, and because I had spent the time to really understand the mechanics of hangman, I felt that it would be a suitable first project to make my time learning Haskell more interesting.

It ended up taking quite a bit longer than I would have expected! After all, wrapping your head around functional programming is no easy task. I also received quite a bit of help from the kind folks at r/haskell towards the end in terms of polishing and condensing the script to something pictureseque I would argue!

Functional programming is something I intend to return to at some point, once it’s fully matured. Whether or not that fully matured language is Haskell at the time or not is yet to be seen. In the meantime, however, imperative languages are still “where it’s at” if you’re trying to get things done in a reasonable time frame - At least for us mortal beings.

Return to Last Page