Hangman Part 2

This lesson will teach you how to finish the hangman game.

For Loops


    Back in our display_board function, we want to display the letters that the player has incorrectly guessed.

    First we print the string 'Missed letters:' with a space character at the end instead of a newline.

    By default, python puts a newline after a print statement. However we can replace the newline with a space using end = ' '.

    def get_random_word(word_list):
      return random.choice(word_list)
    			
    def display_board(hangman_pics, missed_letters, correct_letters, secret_word):
      print(hangman_pics[len(missed_letters)])
      print()
    
      print('Missed letters:', end = ' ')
    
    print('HANGMAN')
      
    missed_letters = ''
    correct_letters = ''
    

    We will then create a new type of loop, called a for loop.

    With the for loop we can step through a list we have made and repeat code for each element inside of the list.

    Unlike a while loop, a for loop does not have a condition next to it.

    We say For an element in something, do this.

    Example:
    names = ["Matt", "Emily", "Steven", "Mary"]
    
    for x in names:
      print(x)
    

    This code will print out each name inside of the list.

    Where the code says x we could have put anything because it is a placeholder variable. However it is common to use x, y, i or j.

    In our display_board function, the for loop will loop through each letter in the missed_letters string and display them to the screen with a space between each one.

    def display_board(hangman_pics, missed_letters, correct_letters, secret_word):
      print(hangman_pics[len(missed_letters)])
      print()
    
      print('Missed letters:', end = ' ')
    
      for letter in missed_letters:
        print(letter, end = ' ')
      print()
      print()
      
    print('HANGMAN')
    

    We end with two print() statements so there is extra space underneath the missed_letters display line.

Range Function



    Sometimes we need to loop through a specific sequence of numbers. We can do this with the range() function.

    When called with one argument, range() will return a range object of integers from 0 up to (but not including) the argument. This range object can be converted to a list with the list() function we've seen before.

    Example:
    range_list = list(range(10))
    
    print(range_list)
    
    # Output:
    # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    

    If you pass two integer arguments to range(), the range object it returns is from the first integer argument up to (but not including), the second argument.

    Example:
    range_list = list(range(5,10))
    
    print(range_list)
    
    # Output:
    # [5, 6, 7, 8, 9]
    

    We can also loop though a range object.

    for i in range(5):
      print(i)
    
    # Output:
    # 0
    # 1
    # 2
    # 3
    # 4
    

List Slicing



    Our game will need to update the list of letters guessed by the player to show blanks and guessed letters. We can do this with list slicing.

    List slicing creates a new list value with a subset of another list's items. To slice a list we specify two indexes (the beginning and end) with a colon in the sqauare brackets after a list.

    Example:
    food = ['apples', 'bananas', 'carrots', 'grapes']
    
    food_sliced = food[1:3]
    
    print(food_sliced)
    
    # Output:
    # ['bananas', 'carrots']
    

    The expression food[1:3] evaluates to a list with items from index 1 up to (but not including) index 3 in food.

    If you leave out the first index, python will automatically think you want index 0 for the first index.

    Example:
    food = ['apples', 'bananas', 'carrots', 'grapes']
    
    food_sliced = food[:3]
    
    print(food_sliced)
    
    # Output:
    # ['apples', 'bananas', 'carrots']
    

    If you leave out the second index, python will automatically think you want the rest of the list.

    Example:
    food = ['apples', 'bananas', 'carrots', 'grapes']
    
    food_sliced = food[2:]
    
    print(food_sliced)
    
    # Output:
    # ['carrots', 'grapes']
    

    Slicing is a simple way to get a subset of the items in a list.

    We will use slicing in the same way but with strings, where each character in the string is like an item in the list.

Displaying Blanks



    To display the secret word we need to show blank lines for the letters that haven't been guessed as well as show letters they have correctly guessed.

    We can use _ (called the underscore character) to represent blank lines.

    For example, if the secret word is bear then the blanked out string would be ____ (four underscores). If correct_letters was the the string ba you would change the guessed string to b_a_.

    def display_board(hangman_pics, missed_letters, correct_letters, secret_word):
      print(hangman_pics[len(missed_letters)])
      print()
    
      print('Missed letters:', end = ' ')
    
      for letter in missed_letters:
        print(letter, end = ' ')
      print()
      print()
    
      blanks = '_' * len(secret_word)
    
    print('HANGMAN')
    
    This line of code creates the blanks variable full of underscores using string replication. The * operator can also be used on a string and an integer, so the expression '_' * 5 evaluates to _____ (5 underscores).

    The len() function returns the length of an object. So len(secret_word) returns the length of the secret_word (the number of letters it has).

    This will make sure the blanks has the same number of underscores as the secret_word has letters.

    def display_board(hangman_pics, missed_letters, correct_letters, secret_word):
      print(hangman_pics[len(missed_letters)])
      print()
      
      print('Missed letters:', end = ' ')
    
      for letter in missed_letters:
        print(letter, end = ' ')
      print()
      print()
    
      blanks = '_' * len(secret_word)
    
      for i in range(len(secret_word)):
        if secret_word[i] in correct_letters:
          blanks = blanks[:i] + secret_word[i] + blanks[i + 1:]
    
    print('HANGMAN')
    

    We now create a for loop to go through each letter in secret_word and replace the underscore with the actual letter if it exists in correct_letters.

    If you are confused about what the value of secret_word[i] is or blanks[i + 1:] then go back through the other sections to make sure you understand lists, indexing, range and splicing.

    Finally we can display the secret word (with blanks) to the screen. Again we end with two print() statements to seperate this line and the next thing we display.

    def display_board(hangman_pics, missed_letters, correct_letters, secret_word):
      print(hangman_pics[len(missed_letters)])
      print()
      
      print('Missed letters:', end = ' ')
    
      for letter in missed_letters:
        print(letter, end = ' ')
      print()
      print()
    
      blanks = '_' * len(secret_word)
    
      for i in range(len(secret_word)):
        if secret_word[i] in correct_letters:
          blanks = blanks[:i] + secret_word[i] + blanks[i + 1:]
    
      print('Secret Word:', end = ' ')
    
      for letter in blanks:
        print(letter, end = ' ')
      print()
      print()
      
    print('HANGMAN')
    

    Now run the program again and the blanks should print to the screen.



Taking Guesses



    We need to make a function that asks the player to guess a single letter of the secret word.

    We will ask the player for input then convert the input to all lowercase so we don't have to check both cases.

    The function will take in a string of all the letters that have already been guessed.

    def display_board(hangman_pics, missed_letters, correct_letters, secret_word):
      print(hangman_pics[len(missed_letters)])
      print()
      
      print('Missed letters:', end = ' ')
    
      for letter in missed_letters:
        print(letter, end = ' ')
      print()
      print()
    
      blanks = '_' * len(secret_word)
    
      for i in range(len(secret_word)):
        if secret_word[i] in correct_letters:
          blanks = blanks[:i] + secret_word[i] + blanks[i + 1:]
    
      print('Secret Word:', end = ' ')
    
      for letter in blanks:
        print(letter, end = ' ')
      print()
      print()
    
    def get_guess(already_guessed):
      while True:
        print('Guess a letter:', end = ' ')
        guess = input()
        guess = guess.lower()
        
    print('HANGMAN')
     
    missed_letters = ''
    correct_letters = ''
    

    We use a while loop to keep asking for a guess if the input given is not valid.

    We will check if the input is valid with if statements.

    These will check if the input is a single letter that hasn't already been guessed.

    def get_guess(already_guessed):
      while True:
        print('Guess a letter')
        guess = input()
        guess = guess.lower()
    
        if len(guess) != 1:
          print('Please enter a single letter.')
        elif guess in already_guessed:
          print('You have already guessed that letter. Please choose again.')
        elif guess not in 'abcdefghijklmnopqrstuvwxyz':
          print('Please enter a letter.')
        else:
          return guess
          
    print('HANGMAN')
    

    if len(guess) != 1 checks if the length of the input is not 1 (not a single letter).

    elif guess in already_guessed checks if the letter guessed is inside the string of the already_guessed variable.

    elif guess not in 'abcdefghijklmnopqrstuvwxyz' checks if the input is a not letter in the string 'abcdefghijklmnopqrstuvwxyz' (not in the english alphabet).

    Now we've made the function, we can use it in our main game loop.

    print('HANGMAN')
     
    missed_letters = ''
    correct_letters = ''
    secret_word = get_random_word(words)
    game_is_done = False
    
    while True:
      display_board(HANGMANPICS, missed_letters, correct_letters, secret_word)
    
      guess = get_guess(missed_letters + correct_letters)
    
    

    Here we use the function to get a guess from the user. missed_letters + correct_letters represents the letters that have already been guessed.

    Now we have a guess, we can check if it is in the secret_word and either add it to the correct_letters string or the missed_letters string.

    while True:
      display_board(HANGMANPICS, missed_letters, correct_letters, secret_word)
    
      guess = get_guess(missed_letters + correct_letters)
    
      if guess in secret_word:
        correct_letters = correct_letters + guess
      else:
        missed_letters = missed_letters + guess
    
    

    Test the game to make sure that you can make a guess. Missed Letters should be displayed and correct letters should replace the blanks in the secret word.

    We will remove the break statement for now so we can repeatedly make guesses.



Winning and Losing



    Currently we can guess forever and the game will crash if we make too many wrong guesses.

    We need to check if the player has won or lost after each guess.

    After making a correct guess, we will check if the game is won.

    while True:
      display_board(HANGMANPICS, missed_letters, correct_letters, secret_word)
    
      guess = get_guess(missed_letters + correct_letters)
      
      if guess in secret_word:
        correct_letters = correct_letters + guess
    
        found_all_letters = True
        for letter in secret_word:
          if letter not in correct_letters:
            found_all_letters = False
            break
        if found_all_letters:
          print('You have won!!! The secret word is ' + secret_word)
          game_is_done = True
      else:
        missed_letters = missed_letters + guess
    
    

    A new boolean variable found_all_letters is created and starts as True.

    We then loop through all the letters in secret_word and check if any are not in correct_letters.

    This means we haven't won so we set found_all_letters to False and break from the loop.

    If all the letters are in correct_letters then we have won the game. We print this to the screen and set game_is_done to True.



    Now we must check if the player has guessed too many times and lost

    We check if the length of missed_letters is equal to the length of hangman_pics - 1.

    If it is, then the player loses so we display the board one more time, and set game_is_done to True.

    while True:
      display_board(HANGMANPICS, missed_letters, correct_letters, secret_word)
    
      guess = get_guess(missed_letters + correct_letters)
      
      if guess in secret_word:
        correct_letters = correct_letters + guess
    
        found_all_letters = True
        for letter in secret_word:
          if letter not in correct_letters:
            found_all_letters = False
            break
        if found_all_letters:
          print('You have won!!! The secret word is ' + secret_word)
          game_is_done = True
      else:
        missed_letters = missed_letters + guess
    
        if len(missed_letters) == len(HANGMANPICS) - 1:
          display_board(HANGMANPICS, missed_letters, correct_letters, secret_word)
          print('You have run out of guesses and lose! The secret word was: ' + secret_word)
          game_is_done = True
    
    

    We use -1 because hangman_pics has a length of 7 (7 pictures). 1 starting picture and 6 for missed guesses.

    So we only need to count to 6 which is len(hangman_pics) - 1.



Ending and Replaying



    We have a win and lose condition but the game still doesn't end.

    We need to use the game_is_done variable to check if the game is over.

    We can then ask the player to play again or just end the game.

    We will write a new function underneath our get_guess function.

    def get_guess(already_guessed):
        while True:
            print('Guess a letter:', end = ' ')
            guess = input()
            guess = guess.lower()
    
            if len(guess) != 1:
                print('Please enter a single letter.')
            elif guess in already_guessed:
                print('You have already guessed that letter. Please choose again.')
            elif guess not in 'abcdefghijklmnopqrstuvwxy':
                print('Please enter a letter.')
            else:
                return guess
    
    def playAgain():
      print('Do you want to play again? (yes or no)')
      return input().lower().startswith('y')
    
    print('HANGMAN')
     
    missed_letters = ''
    correct_letters = ''
    

    The function asks the player if they want to play again and to enter their answer as yes or no.

    We then get input and change it to lowercase.

    The startswith() function at the end returns true if the string starts with the letter in the parameter or false otherwise.

    So if the player enters yes, the function returns true, otherwise it returns false.

    Now back in the main game loop, we can use the function.

    while True:
      display_board(HANGMANPICS, missed_letters, correct_letters, secret_word)
    
      guess = get_guess(missed_letters + correct_letters)
      
      if guess in secret_word:
        correct_letters = correct_letters + guess
    
        found_all_letters = True
        for letter in secret_word:
          if letter not in correct_letters:
            found_all_letters = False
            break
        if found_all_letters:
          print('You have won!!! The secret word is ' + secret_word)
          game_is_done = True
      else:
        missed_letters = missed_letters + guess
    
        if len(missed_letters) == len(HANGMANPICS) - 1:
          display_board(HANGMANPICS, missed_letters, correct_letters, secret_word)
          print('You have run out of guesses and lose! The secret word was: ' + secret_word)
          game_is_done = True
    
      if game_is_done:
        if playAgain():
          missed_letters = ''
          correct_letters = ''
          game_is_done = False
          secret_word = get_random_word(words)
        else:
          break
    

    If game_is_done is true then we ask the player to play again.

    If playAgain() returns true then we reset the variables and get a new secret word.

    If playAgain returns false then we break from the main game loop and the program ends.



    Congratulations! You now have a complete hangman game. Test it to make everything works correctly.

    You've learned a lot of new concepts that can be used for other games too!

Additional Challenges



    Scoring System

    Use a variable to keep track of the player's score. Every time they win a game, they should get a point. That way, the player can see how many points they can get in a row.


    Additional Words

    You can add more words manually to your list if you want to make the game more interesting for the player. But that's a slow and manual process. What if you wanted to add a whole bunch of words at once with code?

    You can use the nltk module to download a whole giant dictionary of words at once to your computer.

    First, use Pip to install the nltk package. If you are not familiar with using Pip, you can review the setup guide.

    Then, inside the python shell, type the following two lines:
    import nltk
    nltk.download('words')
    


    This is a one-time download of the dictionary, which is why these lines are done inside of the shell.

    Then, in your code, you can use these lines of code to access your giant word list.
    from nltk.corpus import words
    giant_word_list = words.words()
    print(len(giant_word_list))
    
    # Output
    # 236736
    

    This is a list of words just like the one in the variable that you made...only there are 236736 words in the list! Replace your current word list with this one...and see if you're up for the challenge!


    Phrases

    Instead of just words, how about you add phrases to the list of things that players will have to guess? For example, you could say have the phrase The tallest mountain and the player will have to guess all the letters in the phrase.

    For this challenge, you will need to think about how to handle the spaces in the phrases. You could choose to make the phrase a list of individual words, or find a way to parse the string and not include the spaces in the characters the player has to guess.