## 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.

Pages: 1 2

### 6 Responses to “Hangman”

1. Axio said

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 (list "The word was:" w)))
((null? letters)
(pretty-print w)
(pretty-print "Lucky guy!"))
(else
(pretty-print str)
(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)))))))))))
```
2. 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;
}
return ' ';
}

std::string getNextWord()
{
char words[] = { "THE", "QUICK", "BROWN", "FOX", "JUMPS", "OVER", "LAZY", "DOG", "RED", "GREEN", "GROSS", "GRAAL" };
unsigned int sz = sizeof(words) / sizeof(words);
return words[rand() % sz];
}

#endif

void display(const std::string& word_with_blanks, int level)
{
//                    012345678901
char pict = { "+--------  \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); ++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;
}

```
3. […] 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. […]

4. Mike said

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? ').strip().lower()

print('Thanks for playing!')

```
5. Diego Giuliani said

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

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):
for i in range(len(word)):
cad += (word[i] + "." ) if word[i] in letters else "_."

def printGibbet(n):
gibbet = ["head","torso","left Arm","right Arm","left leg","right leg"]
print ",".join(gibbet[:n])

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)):
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 True
```
6. Mahesh said

I 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()