Опубликован: 12.07.2013 | Доступ: свободный | Студентов: 735 / 20 | Длительность: 37:41:00
Лекция 9:

Hangman

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
[['eggs', 'milk', 'soup', 'apples', 'bread'],
['clean', 'mow the lawn', 'go grocery shopping'],
['apple', 'frumbleberry']]
>>>

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]
>>> groceries
['eggs', 'milk', 'soup', 'apples', 'bread']
>>> chores
['clean', 'mow the lawn', 'go grocery shopping']
>>> favoritePies
['apple', 'frumbleberry']
>>>

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:

The indexes of a list of lists.

Рис. 9.1. The indexes of a list of lists.

Methods

Methods are just like functions, but they are always attached to a value. For example, all string values have a lower() method, which returns a copy of the string value in lowercase. You cannot just call lower() by itself and you do not pass a string argument to lower() by itself (as in lower('Hello')). You must attach the method call to a specific string value using a period.

The lower() and upper() String Methods

Try entering 'Hello world!'.lower() into the interactive shell to see an example of this method:

>>> 'Hello world'.lower()
'hello world!'
>>>

There is also an upper() method for strings, which changes all the characters in a string to uppercase. Try entering 'Hello world'.upper() into the shell:

>>> 'Hello world'.upper()
'HELLO WORLD! '
>>>

Because the upper() method returns a string, you can call a method on that string as well. Try typing 'Hello world!'.upper().lower() into the shell:

>>> 'Hello world'.upper().lower()
'hello world!'
>>>

'Hello world!'.upper() evaluates to the string 'HELLO WORLD!', and then we call that string's lower() method. This returns the string 'hello world!', which is the final value in the evaluation. The order is important. 'Hello world!'.lower ().upper() is not the same as 'Hello world!'.upper().lower():

>>> 'Hello world'.lower().upper()
'HELLO WORLD!'
>>>

Remember, if a string is stored in a variable, you can call a string method on that variable. Look at this example:

>>> fizz = 'Hello world' 
>>> fizz.upper() 
'HELLO WORLD' 
>>>

The reverse() and append() List Methods

The list data type also has methods. The reverse() method will reverse the order of the items in the list. Try entering spam = [1, 2, 3, 4, 5, 6, 'meow', 'woof'], and then spam.reverse() to reverse the list. Then enter spam to view the contents of the variable.

>>> spam = [1, 2, 3, 4, 5, 6, 'meow', 'woof']
>>> spam.reverse()
>>> spam
['woof', 'meow', 6, 5, 4, 3, 2, 1]
>>>

The most common list method you will use is append(). This method will add the value you pass as an argument to the end of the list. Try typing the following into the shell:

>>> eggs = []
>>> eggs.append('hovercraft')
>>> eggs
['hovercraft']
>>> eggs.append('eels')
>>> eggs
['hovercraft', 'eels']
>>> eggs.append(42)
>>> eggs
['hovercraft', 'eels', 42]
>>>

Though string and list data types have methods, integers do not happen to have any methods.

The Difference Between Methods and Functions

You may be wondering why Python has methods, since they seem to act just like functions. Some data types have methods. Methods are functions associated with values of that data type. For example, string methods are functions that can be called on any string. If you have the string value 'Hello', you could call the string method upper() like this: 'Hello'.upper(). Or if the string 'Hello' were stored in a variable named spam, it would look like this: spam.upper()

You cannot call string methods on values of other data types. For example, [1, 2, 'apple'].upper() would cause an error because [1, 2, 'apple'] is a list and upper() is a string method.

The values of data types that have methods are also called objects. Object-oriented programming is a bit advanced for this book, and you don't need to completely understand it to make games. Just understand that objects are another name for a values of data types that have methods.

The split() List Method

Line 59 is a very long line of code, but it is really just a simple assignment statement. This line also uses the split() method, which is a method for the string data type (just like the lower() and upper() methods).

59. words = 'ant baboon badger bat bear beaver camel cat clam cobra cougar coyote crow deer 
    dog donkey duck eagle ferret fox frog goat goose hawk lion lizard llama mole monkey 
    moose mouse mule newt otter owl panda parrot pigeon python rabbit ram rat raven rhino 
    salmon seal shark sheep skunk sloth snake spider stork swan tiger toad trout turkey 
    turtle weasel whale wolf wombat zebra'.split()

As you can see, this line is just one very long string, full of words separated by spaces. And at the end of the string, we call the split() method. The split() method changes this long string into a list, with each word making up a single list item. The "split" occurs wherever a space occurs in the string. The reason we do it this way, instead of just writing out the list, is that it is easier for us to type as one long string. If we created it as a list to begin with, we would have to type: ['ant', 'baboon', 'badger',... and so on, with quotes and commas for every single word.

For an example of how the split() string method works, try typing this into the shell:

>>> 'My very energetic mother just served us nine
pies'.split()
['My', 'very', 'energetic', 'mother', 'just',
'served', 'us', 'nine', 'pies']
>>>

The result is a list of nine strings, one string for each of the words in the original string. The spaces are dropped from the items in the list. Once we've called split(), the words list will contain all the possible secret words that can be chosen by the computer for our Hangman game. You can also add your own words to the string, or remove any you don't want to be in the game. Just make sure that the words are separated by spaces.

How the Code Works

Starting on line 61, we define a new function called getRandomWord(), which has a single parameter named wordList. We will call this function when we want to pick a single secret word from a list of secret words.

61. def getRandomWord(wordList):
62.     # This function returns a random string from the passed list of strings.
63.     wordIndex = random.randint(0, len(wordList) - 1)
64.     return wordList[wordIndex] 

The function getRandomWord() is passed a list of strings as the argument for the wordList parameter. On line 63, we will store a random index in this list in the wordIndex variable. We do this by calling randint() with two arguments. Remember that arguments in a function call are separated by commas, so the first argument is 0 and the second argument is len(wordList) - 1. The second argument is an expression that is first evaluated. len(wordList) will return the integer size of the list passed to getRandomWord(), minus one.

The reason we need the - 1 is because the indexes for list start at 0, not 1. If we have a list of three items, the index of the first item is 0, the index of the second item is 1, the index of the third item is 2. The length of this list is 3, but the index 3 is after the last index. This is why we subtract 1 from the length.

For example, if we passed ['apple', 'orange', grape'] as an argument to getRandomWord (), then len(wordList) would return the integer 3 and the expression 3 - 1 would evaluate to the integer 2.

That means that wordIndex would contain the return value of randint(0, 2), which means wordIndex would equal 0, 1, or 2. On line 64, we would return the element in wordList at the integer index stored in wordIndex.

Let's pretend we did send ['apple', 'orange', grape'] as the argument to getRandomWord() and that randint(0, 2) returned the integer 2. That would mean that line 64 would become return wordList[2], which would evaluate to return 'grape'. This is how the getRandomWord() returns a random string in the wordList list. The following code entered into the interactive shell demonstrates this:

>>> import random
>>> print(wordIndex)
2
>>> print(['apple', 'orange', 'grape'][wordIndex])
grape
>>>

And remember, we can pass any list of strings we want to the getRandomWord() function, which is what makes it so useful for our Hangman game.

Displaying the Board to the Player

Next we need to create another function which will print the hangman board on the screen, along with how many letters the player has correctly (and incorrectly) guessed.

66. def displayBoard(HANGMANPICS, missedLetters, correctLetters, secretWord):
67.     print(HANGMANPICS[len(missedLetters)])
68.     print()

This code defines a new function named displayBoard(). This function has four parameters. This function will implement the code for the "Show the board and blanks to the player" box in our flow chart. Here is what each parameter means:

  • HANGMANPICS - This is a list of multi-line strings that will display the board as ASCII art. We will always pass the global HANGMANPICS variable as the argument for this parameter.
  • missedLetters - This is a string made up of the letters the player has guessed that are not in the secret word.
  • correctLetters - This is a string made up of the letters the player has guessed that are in the secret word.
  • secretWord - This string is the secret word that the player is trying to guess..

The first print() function call will display the board. HANGMANPICS will be a list of strings for each possible board. HANGMANPICS[0] shows an empty gallows, HANGMANPICS[1] shows the head (this happens when the player misses one letter), HANGMANPICS[2] shows a head and body (this happens when the player misses two letters), and so on until HANGMANPICS[6] when the full hangman is shown and the player loses.

The number of letters in missedLetters will tell us how many incorrect guesses the player has made. We can call len(missedLetters) to find out this number. This number can also be used as the index to the HANGMANPICS list, which will allow us to print the correct board for the number of incorrect guesses. So, if missedLetters is 'aetr' then len('aetr') will return 4 and we will display the string HANGMANPICS[4] . This is what HANGMANPICS[len(missedLetters)] evaluates to. This line shows the correct hangman board to the player.

70.     print('Missed letters:', end=' ')
71.      for letter in missedLetters:
72.            print(letter, end=' ') 
73.              print()

Line 71 is a new type of loop, called a for loop. A for loop is kind of like a while loop. Line 72 is the entire body of the for loop. The range() function is often used with for loops. I will explain both in the next two sections.

Remember that the keyword argument end=' ' uses only one = sign, not two.