Hangman
December 20, 2011
In today’s exercise we implement the classic Unix V7 game hangman for guessing words. The player is given a series of blanks, one per letter of a word to be guessed. At each turn the player guesses a letter; if it is in the word, all occurrences of the letter are filled in the appropriate blank, but if the guess is wrong, another body part — traditionally, the head, torso, two arms and two legs, for a total of six — is added to the gibbet. The player wins by guessing all the letters of the word before the hangman adds all the pieces of his body.
Your task is to implement the interactive game of hangman. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
Not much to see here.
(define hangman-database ;; size of db, db. Real game would read /usr/share/dict... '(5 ("hello" "ectoplasm" "mauger" "subterfuge" "lucent"))) (define (select-word #!optional (db hangman-database)) (list-ref (cadr db) (random-integer (car db)))) (define (game) (let* ((w (select-word)) (l (string-length w)) (str (make-string l #\_)) (letters (nub (string->list w) test: char=?)) (hangman '(head torso left-arm right-arm left-leg right-leg))) (let loop ((h hangman) (letters letters)) (cond ((null? h) (pretty-print "Hang on your head Tom Dooley!") (pretty-print (list "The word was:" w))) ((null? letters) (pretty-print w) (pretty-print "Lucky guy!")) (else (pretty-print str) (let ((c (read-char))) (cond ((eof-object? c) (pretty-print "Bye")) ((char=? c #\newline) (loop h letters)) (else (if (member c letters) (begin (for-each (lambda (i) (when (char=? c (string-ref w i)) (string-set! str i c))) (iota 0 (1- l))) (loop h (filter (lambda (d) (not (char=? c d))) letters))) (begin (pretty-print (car h)) (loop (cdr h) letters)))))))))))C++ solution, slightly less interactive and rather longer. Procedural, nothing more fancy than a string.
#include <iostream> #include <string> #include <cstdlib> #include <ctime> const int LEVELS = 6; //#define TEST #ifdef TEST char getCh() { static int k = 0; char inputs[]= "EAEHMSTROGB_HNGMNA."; return inputs[k++]; } std::string getNextWord() { return "HANGMAN"; } #else char getCh() { std::string s; std::cin >> s; if (s.length() > 0) { return s[0]; } return ' '; } std::string getNextWord() { char words[][20] = { "THE", "QUICK", "BROWN", "FOX", "JUMPS", "OVER", "LAZY", "DOG", "RED", "GREEN", "GROSS", "GRAAL" }; unsigned int sz = sizeof(words) / sizeof(words[0]); return words[rand() % sz]; } #endif void display(const std::string& word_with_blanks, int level) { // 012345678901 char pict[6][13] = { "+-------- \n", "|/ | \n", "| o \n", "| /#\\ \n", "| / \\ \n", "| \n" }; int blank_line_pos[LEVELS * 2] = { 2, 8, 3, 8, 3, 7, 3, 9, 4, 7, 4, 9}; for (int i = level; i < LEVELS; ++i) { pict[blank_line_pos[2 * i]][blank_line_pos[2 * i + 1]] = ' '; } for (unsigned int i = 0; i < sizeof(pict) / sizeof(pict[0]); ++i) { std::cout << pict[i]; } for (unsigned int i = 0; i < word_with_blanks.length(); ++i) { std::cout << word_with_blanks[i] << ' '; } std::cout << std::endl; } int blankWord(std::string& word, const char blank_char, const std::string& uncover) { std::string::size_type i = 0; int changes = 0; while (i != std::string::npos) { i = word.find_first_not_of(uncover, i); if (i == std::string::npos) { break; } word[i++] = blank_char; ++changes; } return changes; } bool endGame(const std::string& word, const std::string& message, const int level) { display(word, level); std::cout << message << std::endl; std::cout << "Enter . to quit, other input to continue" << std::endl; return (getCh() == '.'); } int main(int argc, char** argv) { time_t tm; std::time(&tm); std::srand(static_cast<unsigned int>(tm)); bool quit = false; do { int level = 0; std::string word = getNextWord(); std::string blanked = word; std::string used = ""; blankWord(blanked, '_', used); while (level < LEVELS) { display(blanked, level); std::cout << "Enter a letter, . to quit." << std::endl; char ch = getCh(); std::cout << "Your input was: " << ch << std::endl; if (ch == '.') { quit = true; break; } if (ch >= 'A' && ch <= 'Z') { if (used.find_first_of(ch) != std::string::npos) { std::cout << "You have already used that letter" << std::endl; continue; } used += ch; if (word.find_first_of(ch) != std::string::npos) { blanked = word; if (!blankWord(blanked, '_', used)) { quit = endGame(blanked, "You won! Congratulations!", level); break; } } else { if (++level == LEVELS) { quit = endGame(word, "You lost!", level); break; } } } } } while (!quit); return 0; }[…] today a task that was more practical engineering than theoretical science. Write a game of Hangman. The language is C++ although, for the sake of simplicity, I avoided classes and algorithms. […]
Python 3 version with ascii graphics.
Uses wordlist from 12dicts, which can be found at http://wordlist.sourceforge.net/
from operator import methodcaller from random import randrange from string import ascii_lowercase def random_word(): with open("12dicts/2of12inf.txt", "rt") as wordlist: for n, word in enumerate(wordlist, 1): if not randrange(n): pick = word return pick.strip(' %\n') def game(): game_word = random_word() letters = set(game_word) word_display = ' '.join(map('{{{}}}'.format, game_word)) game_display = ''' +--+ used: {a} {b} {c} {d} {e} {f} {g} {h} {i} | | {j} {k} {l} {m} {n} {o} {p} {q} {r} | {hd} {s} {t} {u} {v} {w} {x} {y} {z} | {la}{bd}{ra} | {ll} {rl} word: ''' + word_display + ''' | ======== ''' bodyparts = [('hd', 'O'), ('bd', '|'), ('la', '/'), ('ra', '\\'), ('ll', '/'), ('rl', '\\')] status = {c:'_' for c in ascii_lowercase} status.update((p,' ') for p,_ in bodyparts) while letters and bodyparts: print(game_display.format(**status)) guess = input('\nEnter a letter: ').strip() status[guess] = guess if guess in letters: letters.remove(guess) else: part,char = bodyparts.pop(0) status[part] = char else: print(game_display.format(**status)) if bodyparts: print("You win!") else: print("Sorry, you lose! The word was", game_word) play = 'y' while play == 'y': game() play = input('\nPlay again? ')[0].strip().lower() print('Thanks for playing!')My attempt using python. It uses the description of the exercise as a source of words, but this can be easily changed.
from random import randint import re cad = """ The player is given a series of blanks, one per letter of a word to be guessed. At each turn the player guesses a letter; if it is in the word, all occurrences of the letter are filled in the appropriate blank, but if the guess is wrong, another body part - traditionally, the head, torso, two arms and two legs, for a total of six - is added to the gibbet. The player wins by guessing all the letters of the word before the hangman adds all the pieces of his body. """ def printLine(word,letters): cad = "" for i in range(len(word)): cad += (word[i] + "." ) if word[i] in letters else "_." print cad def printGibbet(n): gibbet = ["head","torso","left Arm","right Arm","left leg","right leg"] print ",".join(gibbet[:n]) def addLetters(word,letters,c): for i in range(len(word)): if (word[i] == c): letters.insert(i,c) return letters def game(): # We take a list of words from the first line of text to have something to play with, # we could change this to load from a file or hardcode a list of words pattern = "^(\w{0,20})([;|,|.]*)$" word_list = [re.search(pattern,c).group(1) for c in cad.split() if ((len(c) >= 5) & (re.search(pattern,c) != None ))] word = word_list[randint(0,len(word_list) - 1 ) ] n = 0 letters = [] while True: printLine(word,letters) c = raw_input("Guess a letter: ") if (re.match("^[a-zA-Z]$",c)== None): continue if ((c in word) and ( not c in letters)): letters = addLetters(word,letters,c) else: n +=1 printGibbet(n) if (n == 6) : print "You loose the word was %s" % word return False print "".join(letters) if ("".join(letters)== word ): print "You win! the word was %s " % word return TrueI have hardcoded the
class HangMan(object):
“””
“””
def __init__(self):
“””
“””
self.hangman = [‘head’, ‘torso’, ‘leftarm’, ‘rightarm’, ‘leftleg’, ‘rightleg’]
self.wordsList = [‘head’, ‘torso’, ‘leftarm’, ‘rightarm’, ‘leftleg’, ‘rightleg’]
def GetNextHangManPart(self):
“””
“””
for word in self.hangman:
ostr = “Wrong guess! you got %s Try Again!” %(word)
yield ostr
def PlayGame(self):
“””
“””
for word in self.wordsList:
letterCount = 0
GuessCount = 0
hangmanGenerator = self.GetNextHangManPart()
print “New word with %d characters” %(len(word))
try:
while(letterCount < len(word)):
input = raw_input("Guess the %d letter: " %(letterCount+1))
if word[letterCount] == input:
print "Good Work"
letterCount +=1
else:
print hangmanGenerator.next()
except:
print "You lost! better luck next time"
print "Game Completed!"
if __name__ == '__main__':
hm = HangMan()
hm.PlayGame()