October 13, 2021
Post questions to the Moodle Forum!
In this lab you will practice your debugging skills by tracking down and fixing problems with an implementation of the word guessing game Hangman. You will need to following files:
hangman.py: it doesn’t crash immediately, but this Python code for Hangman has many logical errors. It will be the starting point for your debugging task.
wordlist.txt: a text file with one word per line. Used to choose a random word for the user to try and guess.
The Hangman section describes the Hangman game in more detail and lists the features we want our Hangman program to have. The Bug Detective section guides you through tracking down the various errors in the starting code. Make sure to read the Advice section for a bit of background information.
Hangman is a word guessing game where the player tries to guess a word by guessing the letters in that word. The player is allowed a limited number of wrong guesses–they win if they can guess all the correct letters before they run out of guesses. For example, assume the secret word is banana
. At the start of the game, the player might see
10 guesses left _ _ _ _ _ _ Letters you've already guessed:
Each _
represents a letter in the secret word. Let’s say the player guesses a
. They would then see
10 guesses left _ a _ a _ a Letters you've already guessed: a
Note that every matching letter in the word was filled in. Also note that the player was not charged a guess–they only lose a guess for an incorrect letter. If the player next guessed the letter s
, they would see
9 guesses left _ a _ a _ a Letters you've already guessed: a s
We want our Hangman program to have the following features:
To track down the bugs in hangman.py
you’ll be running the program and observing where it deviates from the desired behavior. In its current state, it doesn’t crash immediately, but neither does it correctly play Hangman. Producing a fully working version of hangman.py
should require around six changes, where a change consists of adding, modifying, or removing one or two lines to address a particular issue. These six changes do not include any print
s or other lines you add to help in identifying the source of problems.
get_guess
If you run hangman.py
in VS Code and try and play it, you’ll quickly discover something is definitely wrong with how it’s processing user input. A good place to start your debugging is the function that handles this, get_guess
. There are three properties it tries to enforce about user input:
guess.isalpha()
returns True
when the string guess
has only letters and nothing else)From trying it out, we observe something is probably wrong with how the function is handling property 2 since if we guess a
, we get a message That's not a letter
. Try thinking through the Boolean logic (i.e., when things will be True
and False
) to identify what needs to be changed.
The next thing to consider is that this function is supposed to repeatedly prompt the user for input until they enter something valid. Test out the program—does it do this? It seems it accepts whatever the user inputs the second time no matter what. If get_guess
is going to repeat something until a condition is met it should use a loop. What should be turned into a loop and what kind of loop should it be?
play
For this part you might find it useful to print out word
(the variable for the word the player is trying to guess) in the play
function, so you can know when you are making a correct and incorrect guess.
Now that we’ve fixed the glaring problems with get_guess
, we can turn to the logic of the game itself in the play
function. Look through the function and read the comments to get an idea of what the different variables represent. Run hangman.py
and input a couple of correct guesses–what happens? The previous correct guess goes away! Find the place in the code where it handles a correct guess (the comments may be useful here). Try and find the line in this part where it would overwrite previously guessed letters. Think about what value current
has at the start. Does it make sense to assign "_"
to locations in that list?
When you were fixing get_guess
you saw that it used its parameter guessed
to check if the user’s input has been guessed before. Try running hangman.py
and entering the same wrong guess multiple times. For some reason, our program accepts this. You might have also suspected a problem here since it never prints anything after Letters you've already guessed:
. Look at where we call get_guess
in the play
function. We’re passing it the variable guessed
, which seems like the right thing to do. Reading the comments higher up in the play
function, we see guessed
is described as # list of previously guessed letters
. Can you find anywhere in the play
function that we update guessed
with previously guessed letters? We probably want to add each letter the player guesses to the list guessed
.
At this point we’re getting down to the final details of a fully correct Hangman game. Try playing a game where you run out of guesses–what happens? Before we get an IndexError
, it prints out -1 guesses left
. That seems fishy. Why doesn’t the game end before guesses
goes negative? There’s code at the end of the play
function that prints out a winning or losing message to the user. What controls whether our program gets to this code? We need to change the logic that controls when the game ends to account for running out of guesses.
Now try playing a game where you guess all the letters. There seems to be one left over! Some invisible character at the end of every word we pick from wordlist.txt
. Recall that wordlist.txt
has one word per line and that there’s a particular character that represents a new line. It might be helpful to consult the documentation for string methods to see if there’s one that would be useful here.
A really good rule of thumb when debugging is to only change one thing at a time. That way if the behavior of the program changes (or stays the same) you know exactly what change is responsible. The rest of the advice section is background on a new thing that comes up in hangman.py
. You don’t need to use it yourself to get it working, but understanding it may help you understand what the code is doing.
Various places in hangmany.py
use the string method join
for convenience. This function takes a list of strings as its argument and returns those strings concatenated together. The useful thing is that it puts the string it’s called with in between each concatenated string. For example
= ["hangman", "is", "fun"]
strings = "".join(strings)
nothing_in_between = " ".join(strings)
space_in_between print(nothing_in_between)
print(space_in_between)
prints out hangmanisfun
then hangman is fun
. Whatever string comes before .join
is what gets inserted between each element of the list. You could replicate " ".join(strings)
like this (you can see why join
is convenient)
= ["hangman", "is", "fun"]
strings = ""
space_in_between = " "
separator for i in range(len(strings) - 1):
= space_in_between + strings[i] + separator
space_in_between = space_in_between + strings[-1]
space_in_between print(space_in_between)
Submit the following files via the Lab 4 Moodle page. You do not need to submit wordlist.txt
.
hangman.py
. Make sure it has all the features listed in the Hangman section.This assignment is graded out of 15 points as follows:
We will evaluate your submission by playing the Hangman game and checking that it has all the required working features. We will also read your code to assess the stylistic aspects of your fixes.