CS 111 Lab 4

Aaron Bauer

October 13, 2021

CS 111 f21 — Lab 4: Fixing Hangman

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:

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

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:

Bug Detective

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 prints 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:

  1. The new guess has not already been guessed
  2. The new guess is only letters (guess.isalpha() returns True when the string guess has only letters and nothing else)
  3. The new guess is only a single character

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.

The nitty-gritty

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.

Advice

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

strings = ["hangman", "is", "fun"]
nothing_in_between = "".join(strings)
space_in_between = " ".join(strings)
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)

strings = ["hangman", "is", "fun"]
space_in_between = ""
separator = " "
for i in range(len(strings) - 1):
  space_in_between = space_in_between + strings[i] + separator
space_in_between = space_in_between + strings[-1]
print(space_in_between)

What to Turn In

Submit the following files via the Lab 4 Moodle page. You do not need to submit wordlist.txt.

Grading

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.