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

Hangman

elif ("Else If") Statements

Take a look at the following code:

if catName == 'Fuzzball':
print('Your cat is fuzzy.') else:
print('Your cat is not very fuzzy at all.')

We've seen code like this before and it's rather simple. If the catName variable is equal to the string 'Fuzzball', then the if statement's condition is True and we tell the user that her cat is fuzzy. If catName is anything else, then we tell the user her cat is not fuzzy.

But what if we wanted something else besides "fuzzy" and "not fuzzy"? We could put another if and else statement inside the first else block like this:

if catName == 'Fuzzball':
print('Your cat is fuzzy.') else:
if catName == 'Spots'
print('Your cat is spotted.') else:
print('Your cat is neither fuzzy nor spotted.')
But if we wanted more things, then the code starts to have a lot of indentation:
if catName == 'Fuzzball':
print('Your cat is fuzzy.') else:
if catName == 'Spots'
print('Your cat is spotted.') else:
if catName == 'FattyKitty'
print('Your cat is fat.') else:
if catName == 'Puff'
print('Your cat is puffy.') else:
print('Your cat is neither fuzzy nor spotted nor fat nor puffy.')

Typing all those spaces means you have more chances of making a mistake with the indentation. So Python has the elif keyword. Using elif, the above code looks like this:

if catName == 'Fuzzball':
print('Your cat is fuzzy.') elif catName == 'Spots'
print('Your cat is spotted.') elif catName == 'FattyKitty'
print('Your cat is fat.') elif catName == 'Puff'
print('Your cat is puffy.') else:
print('Your cat is neither fuzzy nor spotted nor fat nor puffy.')

If the condition for the if statement is False, then the program will check the condition for the first elif statement (which is catName == 'Spots'. If that condition is False, then the program will check the condition of the next elif statement. If all of the conditions for the if and elif statements are False, then the code in the else block executes.

But if one of the elif conditions are True, the elif-block code is executed and then execution jumps down to the first line past the else-block. So only one of the blocks in this if-elif-else statement will be executed. You can also leave off the else-block if you don't need one, and just have an if-elif statement.

Making Sure the Player Entered a Valid Guess

91.         if len(guess) != 1:
92.            print('Please enter a single letter.')
93.        elif guess in alreadyGuessed:
94.            print('You have already guessed that letter. Choose again.')
95.        elif guess not in 'abcdefghijklmnopqrstuvwxyz':
96.            print('Please enter a LETTER.')
97.        else:
98 .                                    return guess

The guess variable contains the text the player typed in for their guess. We need to make sure they typed in a single lowercase letter. If they didn't, we should loop back and ask them again. The if statement's condition checks that the text is one and only letter. If it is not, then we execute the if-block code, and then execution jumps down past the else-block. But since there is no more code after this if-elif-else statement, execution loops back to line 87.

If the condition for the if statement is False, we check the elif statement's condition on line 93. This condition is True if the letter exists inside the alreadyGuessed variable (remember, this is a string that has every letter the player has already guessed). If this condition is True, then we display the error message to the player, and jump down past the else-block. But then we would be at the end of the while-block, so execution jumps back up to line 87.

If the condition for the if statement and the elif statement are both False, then we check the second elif statement's condition on line 95. If the player typed in a number or a funny character (making guess have a value like '5' or '!'), then guess would not exist in the string 'abcdefghijklmnopqrstuvwxyz'. If this is the case, the elif statement's condition is True.

Figure 9.3 is an example of elif statements.

Unless these three conditions are all False, the player will keep looping and keep being asked for a letter. But when all three of the conditions are False, then the else-block's return statement will run and we will exit this loop and function.

The elif statement.

Рис. 9.3. The elif statement.

Asking the Player to Play Again

100. def playAgain() :
101.     # This function returns True if the player wants to play again, otherwise it returns False.
102.     print('Do you want to play again? (yes or no)')
103.     return input().lower().startswith('y')

The playAgain() function has just a print() function call and a return statement. The return statement has an expression that looks complicated, but we can break it down. Once we evaluate this expression to a value, that value will be returned from this function.

The expression on line 103 doesn't have any operators, but it does have a function call and two method calls. The function call is input() and the method calls are lower() and startswith('y'). Remember that method calls are function calls that are attached by a period to the value on their left. lower() is attached to the return value of input () .

input() returns a string of the text that the user typed in. Here's a step by step look at how Python evaluates this expression if the user types in YES.

return input().lower().startswith('y')                              
return 'YES'.lower().startswith('y')                                   
return 'yes'.startswith('y') 
return True

The point of the playAgain() function is to let the player type in yes or no to tell our program if they want to play another round of Hangman. If the player types in YES, then the return value of input() is the string 'YES'. And 'YES'.lower() returns the lowercase version of the attached string. So the return value of 'YES'.lower() is

'yes'.

But there's the second method call, startswith('y'). This function returns True if the associated string begins with the string parameter between the parentheses, and False if it doesn't. The return value of 'yes'.startswith('y') is True.

Now we have evaluated this expression! We can see that what this does is let the player type in a response, we lowercase the response, check if it begins with the letter 'y' or 'Y', and then return True if it does and False if it doesn't. Whew!

On a side note, there is also a endswith(someString) string method that will return True if the string ends with the string in someString and False if it doesn't.

Review of the Functions We Defined

That's all the functions we are creating for this game!

  • getRandomWord(wordList) will take a list of strings passed to it as a parameter, and return one string from it. That is how we will choose a word for the player to guess.
  • displayBoard(HANGMANPICS, missedLetters, correctLetters, secretWord) will show the current state of the board, including how much of the secret word the player has guessed so far and the wrong letters the player has guessed. This function needs four parameters passed to work correctly. HANGMANPICS is a list of strings that hold the ASCII art for each possible hangman board. correctLetters and missedLetters are strings made up of the letters that the player has guessed that are in and not in the secret word. And secretWord is the secret word the player is trying to guess. This function has no return value.
  • getGuess(alreadyGuessed) takes a string of letters the player has already guessed and will keep asking the player for a letter that is a letter that he hasn't already guessed. (That is, a letter that is not in alreadyGuessed. This function returns the string of the acceptable letter the player guessed.
  • playAgain() is a function that asks if the player wants to play another round of Hangman. This function returns True if the player does and False if the player doesn't.

We'll now start the code for the main part of the game, which will call the above functions as needed. Look back at our flow chart.

The complete flow chart of Hangman.

Рис. 9.4. The complete flow chart of Hangman.

The Main Code for Hangman

We need to write code that does everything in this flow chart, and does it in order. The main part of the code starts at line 106. Everything previous was just function definitions and a very large variable assignment for HANGMANPICS.

Setting Up the Variables

106. print('H A N G M A N')
107.  missedLetters = ''
108.  correctLetters = ''
109.    secretWord = getRandomWord(words)
110.   gameIsDone = False

Line 106 is the first actual line that executes in our game. We start by assigning a blank string for missedLetters and correctLetters, because the player has not guessed any missed or correct letters yet. Then we call getRandomWord(words), where words is a variable with the huge list of possible secret words we assigned on line 59. The return value of getRandomWord(words) is one of these words, and we save it to the secretWord variable. Then we also set a variable named gameIsDone to False. We will set gameIsDone to True when we want to signal that the game is over and the program should ask the player if they want to play again.

Setting the values of these variables is what we do before the player starts guessing letters.

Displaying the Board to the Player

112.  while True:
113.      displayBoard(HANGMANPICS, missedLetters, correctLetters, secretWord)

The while loop's condition is always True, which means we will always loop forever until a break statement is encountered. We will execute a break statement when the game is over (either because the player won or the player lost).

Line 113 calls our displayBoard() function, passing it the list of hangman ASCII art pictures and the three variables we set on lines 107, 108, and 109. Program execution moves to the start of displayBoard() at line 66. Based on how many letters the player has correctly guessed and missed, this function displays the appropriate hangman board to the player.

Letting the Player Enter Their Guess

115.      # Let the player type in a letter.
116.      guess = getGuess(missedLetters + correctLetters)

If you look at our flow chart, you see only one arrow going from the "Show the board and the blanks to the player." box to the "Ask a player to guess a letter." box. Since we have already written a function to get the guess from the player, let's call that function. Remember that the function needs all the letters in missedLetters and correctLetters combined, so we will pass as an argument a string that is a concatenation of both of those strings. This argument is needed by getGuess() because the function has code to check if the player types in a letter that they have already guessed.

Checking if the Letter is in the Secret Word

118.      if guess in secretWord:
119.         correctLetters = correctLetters + guess

Now let's see if the single letter in the guess string exists in secretWord. If it does exist, then we should concatenate the letter in guess to the correctLetters string. Next we can check if we have guessed all of the letters and won.

Checking if the Player has Won

121.         # Check if the player has won
122.          f oundAllLetters = True
123.          for i in range(len(secretWord)):
124.              if secretWord[i] not in correctLetters:
125.                  f oundAllLetters = False
126.                 break

How do we know if the player has guessed every single letter in the secret word? Well, correctLetters has each letter that the player correctly guessed and secretWord is the secret word itself. We can't just check if correctLetters == secretWord because consider this situation: if secretWord was the string 'otter' and correctLetters was the string 'orte', then correctLetters == secretWord would be False even though the player has guessed each letter in the secret word.

The player simply guessed the letters out of order and they still win, but our program would incorrectly think the player hasn't won yet. Even if they did guess the letters in order, correctLetters would be the string 'oter' because the player can't guess the letter t more than once. The expression 'otter' == 'oter' would evaluate to False even though the player won.

The only way we can be sure the player won is to go through each letter in secretWord and see if it exists in correctLetters. If, and only if, every single letter in secretWord exists in correctLetters will the player have won.

Note that this is different than checking if every letter in correctLetters is in secretWord. If correctLetters was the string 'ot' and secretWord was 'otter', it would be true that every letter in 'ot' is in 'otter', but that doesn't mean the player has guessed the secret word and won.

So how can we do this? We can loop through each letter in secretWord and if we find a letter that does not exist in correctLetters, we know that the player has not guessed all the letters. This is why we create a new variable named foundAllLetters and set it to the Boolean value True. We start out assuming that we have found all the letters, but will change foundAllLetters to False when we find a letter in secretWord that is not in correctLetters.

The for loop will go through the numbers 0 up to (but not including) the length of the word. Remember that range(5) will evaluate to the list [0, 1, 2, 3, 4]. So on line 123, the program executes all the code inside the for-block with the variable i will be set to 0, then 1, then 2, then 3, then 4.

We use range(len(secretWord)) so that i can be used to access each letter in the secret word. So if the first letter in secretWord (which is located at secretWord[0]) is not in correctLetters, we know we can set foundAllLetters to False. Also, because we don't have to check the rest of the letters in secretWord, we can just break out of this loop. Otherwise, we loop back to line 123 and check the next letter.

If foundAllLetters manages to survive every single letter without being turned to False, then it will keep the original True value we gave it. Either way, the value in foundAllLetters is accurate by the time we get past this for loop and run line 127.

129.                       if foundAllLetters :
130.                                print('Yes! The secret word is "' +
secretWord + '"! You have won!') 
131.                                gameIsDone = True

This is a simple check to see if we found all the letters. If we have found every letter in the secret word, we should tell the player that they have won. We will also set the gameIsDone variable to True. We will check this variable to see if we should let the player guess again or if the player is done guessing.