This is the old 1st edition. The new 2nd edition of "Invent Your Own Computer Games with Python" is located at http://inventwithpython.com

Chapter 9 - Hangman (Strings and Lists)

This game introduces many new concepts. But don't worry; we'll experiment with these programming concepts in the interactive shell first. Once you understand these concepts, it will be much easier to understand the game in this chapter: Hangman.

In case you don't know, Hangman is a game two people play with paper and pencil. One person thinks of a word, and then draws blanks for each letter in the secret word. The other person guesses letters that might be in the word. If they guess correctly, the first person writes the letter into the blank. If they guess wrong, the first person draws another body part of the hangman. If the second person can guess all the letters in the word before the hangman has completely been drawn, they win.

ASCII Art

The code for Hangman is about four times larger than our Dragon World game! But don't worry. Half of the lines of code aren't really code at all, but are strings that use keyboard characters to draw pictures. This type of graphics is called ASCII art (pronounced "ask-ee"), because keyboard characters (such as letters, numbers, and also all the other signs on the keyboard) are called ASCII characters. ASCII stands for American Standard Code for Information Interchange. Here are a couple cats done in ASCII art:

      ^___^
      |    )
      |. .  )
     (  v    )
      \____  |
       |      \
       |       |
       |        \
       | |       |
       | | |      \
       | | |      |--.
       | | | _____/  |
      ((((()(_______/
                         _____________________
                   _____/   xx      xxx       \_____
                 _/xxx       xx      xxx      xxx   \____
              __/     xxx     xxx     xx       xxx       \
             /xxxxx     xx      xx     xx       xxx      x\_
            /xxxxxxxxx   xx     xx      xx       xx      xxx\_
           /      xxxxx    x     x       x        xx      xxx \
          /          xx  /\                       xx       xx  \
         /              /  \                      x        xx   \
         |   .=\        |   \                             xx    x\
         |   |  \       |    \                           xx   xxx|
         |   |   \      |     \____                          xx   \
         |   |    \____/           \                       xxx    |
         |   |                      \                             |
         |  /                        \                             \
          \/                          \                     |       \
          /                 ____/      |                   /        |
  _______|        \____                |                __/      xxx|
 /       |               ___   ___--------           __/           x|
/        |              |   |   ________          __/               |
|    oooo\    --------   \_/        __/       ___/            xxx  /
|oooo     \      _____/          __/_________/                 xx_/
\          \__                __/                          xx   /
 \            \______________/                              x__/
  \_                                                 x      /
    \_                                               xx  __/
      \_                                      xx      x_/
        \____                                  x _____/
             \__________________________________/

So this program's code is only about twice the size of Dragon World (if you don't count the pictures). Go ahead and type in this code into the file editor, and save the file as hangman.py. Then run the program by pressing F5. It might be a good idea to save the file every once in a while as you type it, so that if something happens to your computer or IDLE crashes, you won't lose everything you have typed.

Sample Run

H A N G M A N


    +------+
    |      |
    |      |
           |
           |
           |
           |
           |
           |
           |
           |
==============

Missed letters:
_ _ _ _ _
Guess a letter.
e


    +------+
    |      |
    |      |
           |
           |
           |
           |
           |
           |
           |
           |
==============

Missed letters:
_ _ _ e _
Guess a letter.
a


    +------+
    |      |
    |      |
    O      |
           |
           |
           |
           |
           |
           |
           |
==============

Missed letters: a
_ _ _ e _
Guess a letter.
u


    +------+
    |      |
    |      |
    O      |
    |      |
    |      |
    |      |
           |
           |
==============

Missed letters: a u
_ _ _ e _
Guess a letter.
r


    +------+
    |      |
    |      |
    O      |
    |      |
    |      |
    |      |
           |
           |
==============

Missed letters: a u
_ _ _ e r
Guess a letter.
i



    +------+
    |      |
    |      |
    O      |
   /|      |
  / |      |
    |      |
           |
           |
           |
           |
==============

Missed letters: a u i
_ _ _ e r
Guess a letter.
o



    +------+
    |      |
    |      |
    O      |
   /|      |
  / |      |
    |      |
           |
           |
           |
           |
==============

Missed letters: a u i
o _ _ e r
Guess a letter.
t
Yes! The secret word is "otter"! You have won!
Do you want to play again? (yes or no)
no

The hangman game is fairly large, so it has been split up into two chapters. This chapter presents the first half of the source code, and the next chapter presents the second half.

Source Code

hangman.py
  1. import random
  2. HANGMANPICS = ['''
  3.     +------+
  4.     |      |
  5.     |      |
  6.            |
  7.            |
  8.            |
  9.            |
  10.            |
  11.            |
  12.            |
  13.            |
  14. ==============''', '''
  15.     +------+
  16.     |      |
  17.     |      |
  18.     O      |
  19.            |
  20.            |
  21.            |
  22.            |
  23.            |
  24.            |
  25.            |
  26. ==============''', '''
  27.     +------+
  28.     |      |
  29.     |      |
  30.     O      |
  31.     |      |
  32.     |      |
  33.     |      |
  34.            |
  35.            |
  36. ==============''', '''
  37.     +------+
  38.     |      |
  39.     |      |
  40.     O      |
  41.    /|      |
  42.   / |      |
  43.     |      |
  44.            |
  45.            |
  46.            |
  47.            |
  48. ==============''', '''
  49.     +------+
  50.     |      |
  51.     |      |
  52.     O      |
  53.    /|\     |
  54.   / | \    |
  55.     |      |
  56.            |
  57.            |
  58.            |
  59.            |
  60. ==============''', '''
  61.     +------+
  62.     |      |
  63.     |      |
  64.     O      |
  65.    /|\     |
  66.   / | \    |
  67.     |      |
  68.    /       |
  69.   /        |
  70.            |
  71.            |
  72. ==============''', '''
  73.     +------+
  74.     |      |
  75.     |      |
  76.     O      |
  77.    /|\     |
  78.   / | \    |
  79.     |      |
  80.    / \     |
  81.   /   \    |
  82.            |
  83.            |
  84. ==============''']

(Remember, the second half of the code is in the next chapter.)

After typing in the source code (don't forget to save!) you can run this game by pressing F5. If any errors come up, be sure you typed the source code in exactly as it appears here. Remember that the indentation is important, and that lines will have zero, four, eight, or even twelve spaces in front of them.

Code Explanation

  1. import random

The Hangman program is going to randomly select a secret word from a list of secret words. This means we will need the random module imported.

  1. HANGMANPICS = ['''
  2.     +------+
  3.     |      |
  4.     |      |
  5.            |
  6.            |
  7.            |
  8.            |
  9.            |
  10.            |
  11.            |
  12.            |
  13. ==============''', '''

...the rest of the code is too big to show here...

This "line" of code a simple variable assignment, but it actually stretches over several real lines in the source code. The actual "line" doesn't end until line 96. To help you understand what this code means, you should learn about multi-line strings and lists:

Multi-line Strings

Ordinarily when you write strings in your source code, the string has to be on one line. However, if you use three single-quotes instead of one single-quote to begin and end the string, the string can be on several lines:

If we didn't have multi-line strings, we would have to use the \n escape character to represent the new lines. But that can make the string hard to read in the source code:

Multi-line strings do not have to keep the same indentation to remain in the same block. Within the multi-line string, Python ignores the indentation rules it normally has for where blocks end.

def writeLetter():
    # inside the def-block
    print '''Dear Alice,
How are you? Write back to me soon.

Sincerely,
  Bob''' # end of the multi-line string and print statement
    print 'P.S. I miss you.' # still inside the def-block

writeLetter() # This is the first line outside the def-block.

Constant Variables

You may have noticed that HANGMANPICS's name is in all capitals. This is the programming convention for constant variables. Constants are variables whose values do not change throughout the program. Although we can change HANGMANPICS just like any other variable, the all-caps reminds the programmer to not write code that does so.

Constant variables are helpful for providing descriptions for values that have a special meaning. Since the multi-string value never changes, there is no reason we couldn't copy this multi-line string each time we needed that value. The HANGMANPICS variable never varies. But it is much shorter to type HANGMANPICS than it is to type that large multi-line string.

Also, there are cases where typing the value by itself may not be obvious. If we set a variable eggs = 72, we may forget why we were setting that variable to the integer 72. But if we define a constant variable DOZEN = 12, then we could set eggs = DOZEN * 6 and by just looking at the code know that the eggs variable was set to six dozen.

Like all conventions, we don't have to use constant variables, or even put the names of constant variables in all capitals. But doing it this way makes it easier for other programmers to understand how these variables are used. (It even can help you if you are looking at code you wrote a long time ago.)

Lists

I will now tell you about a new data type called a list. A list value can contain several other values in it. Try typing this into the shell: ['apples', 'oranges', 'HELLO WORLD']. This is a list value that contains three string values. Just like any other value, you can store this list in a variable. Try typing spam = ['apples', 'oranges', 'HELLO WORLD'], and then type spam to view the contents of spam.

Lists are a good way to store several different values into one variable. The individual values inside of a list are also called items. Try typing: animals = ['aardvark', 'anteater', 'antelope', 'albert'] to store various strings into the variable animals. The square brackets can also be used to get an item from a list. Try typing animals[0], or animals[1], or animals[2], or animals[3] into the shell to see what they evaluate to.

The number between the square brackets is the index. In Python, the first index is the number 0 instead of the number 1. So the first item in the list is at index 0, the second item is at index 1, the third item is at index 2, and so on. Lists are very good when we have to store lots and lots of values, but we don't want variables for each one. Otherwise we would have something like this:

This makes working with all the strings as a group very hard, especially if you have hundreds or thousands (or even millions) of different strings that you want stored in a list. Using the square brackets, you can treat items in the list just like any other value. Try typing animals[0] + animals[2] into the shell:

Because animals[0] evaluates to the string 'aardvark' and animals[2] evaluates to the string 'antelope', then the expression animals[0] + animals[2] is the same as 'aardvark' + 'antelope'. This string concatenation evaluates to 'aardvarkantelope'.

What happens if we enter an index that is larger than the list's largest index? Try typing animals[4] or animals[99] into the shell:

If you try accessing an index that is too large, you will get an index error.

Changing the Values of List Items with Index Assignment

You can also use the square brackets to change the value of an item in a list. Try typing animals[1] = 'ANTEATER', then type animals to view the list.

The second item in the animals list has been overwritten with a new string.

List Concatenation

You can join lists together into one list with the + operator, just like you can join strings. When joining lists, this is known as list concatenation. Try typing [1, 2, 3, 4] + ['apples', 'oranges'] + ['Alice', 'Bob'] into the shell:

Notice that lists do not have to store values of the same data types. The example above has a list with both integers and strings in it.

The in Operator

The in operator makes it easy to see if a value is inside a list or not. Expressions that use the in operator return a boolean value: True if the value is in the list and False if the value is not in the list. Try typing 'antelope' in animals into the shell:

The expression 'antelope' in animals returns True because the string 'antelope' can be found in the list, animals. (It is located at index 2.)

But if we type the expression 'ant' in animals, this will return False because the string 'ant' does not exist in the list. We can try the expression 'ant' in ['beetle', 'wasp', 'ant'], and see that it will return True.

The in operator also works for strings as well as lists. You can check if one string exists in another the same way you can check if a value exists in a list. Try typing 'hello' in 'Alice said hello to Bob.' into the shell. This expression will evaluate to True.

Removing Items from Lists with del Statements

You can remove items from a list with a del statement. ("del" is short for "delete.") Try creating a list of numbers by typing: spam = [2, 4, 6, 8, 10] and then del spam[1]. Type spam to view the list's contents:

Notice that when you deleted the item at index 1, the item that used to be at index 2 became the new index 1. The item that used to be at index 3 moved to be the new index 2. Everything above the item that we deleted moved down one index. We can type del spam[1] again and again to keep deleting items from the list:

Lists of Lists

Lists are a data type that can contain other values as items in the list. But these items can also be other lists. Let's say you have a list of groceries, a list of chores, and a list of your favorite pies. You can put all three of these lists into another list. Try typing this into the shell:


groceries = ['eggs', 'milk', 'soup', 'apples', 'bread']
chores = ['clean', 'mow the lawn', 'go grocery shopping']
favoritePies = ['apple', 'frumbleberry']
listOfLists = [groceries, chores, favoritePies]
listOfLists

You could also type the following and get the same values for all four variables:


listOfLists = [['eggs', 'milk', 'soup', 'apples', 'bread'], ['clean', 'mow the lawn', 'go grocery shopping'], ['apple', 'frumbleberry']]
groceries = listOfLists[0]
chores = listOfLists[1]
favoritePies = listOfLists[2]
listOfLists

To get an item inside the list of lists, you would use two sets of square brackets like this: listOfLists[1][2] which would evaluate to the string 'go grocery shopping'. This is because listOfLists[1] evaluates to the list ['clean', 'mow the lawn', 'go grocery shopping'][2]. That finally evaluates to 'go grocery shopping'.

Here is another example of a list of lists, along with some of the indexes that point to the items in the list of lists named x. The red arrows point to indexes of the inner lists themselves. The image is also flipped on its side to make it easier to read:

Things Covered In This Chapter: