Hangman project

<< Previous: Practical challenges 8

Decomposition

It can be tempting to make a game like this without using subroutines, and while it is possible, the point of this challenge is to use all the skills you have used up to now. The first step is to decompose the problem. Make a list of the seoarate tasks you can break a game of hangman down into then check below for the list we will be using this time.



The subroutines we will create in this instance will be: get_word(); make_mask(); get_letter(); check_letter(); check_winner()


get_word()

Read the list of possible words in from a text file and select one at random and return it to the main program.





def get_word():
    file = open("words.txt")
    words = eval(file.read())
    file.close()
    word = random.choice(words)
    return word

NOTE: Requires random to have been imported in the main program.

make_mask()

For this we are going to make a string of asterisks as long as the chosen word and return that mask to the main program.





def make_mask(word):
    mask = "*" * len(word)
    return mask

get_letter()

I think its important to consider the users when making games and so we will include a check that the user is not choosing a letter they have already chosen before. To do this pass a list of chosen letters to the subroutine and if the user enters a letter they have already selected then make them choose again. This will stop players losing a life for re-guessing the same letter. At the end of this subroutine return the chosen letter and the updated used letters list





def get_letter(guessed):
    letter = input("Guess one of the missing letters: ")
    while letter in guessed:
        print("You already guessed that letter.")
        letter = input("Guess one of the missing letters: ")
    guessed.append(letter)
    return letter, guessed

check_letter()

This process reuires a number of elements from the main game to be passed in: the chosen letter, the word, the current mask and the number of lives the player has. The subroutine needs to update the mask if the letter matches the character in the same position in the word e.g. if the word is "hello" and the current mask is "h****" and the user guesses l so the returned mask is "h*ll*". The subroutine also has to reduce the players lives by 1 if no letter in the word matches the chosen letter. When finished the subroutine should return the updated mask and lives.





def check_letter(letter, mask, word, lives):
    new_mask = ""
    change = False
    for i in range(len(word)):
        if word[i] == letter:
            new_mask += letter
            change = True
        else:
            new_mask += mask[i]
    if change == False:
         lives -= 1
    return new_mask, lives

check_win()

Check win will run when the main game loop finishes. You need to check whether the main game loop stopped because of no more lives or no more letters left to guess in the word.



def check_win(lives, word):
    if lives == 0
        print(f"You lost! The word was {word}")
    else:
        print(f"You won! You had {lives} lives remaining")

Main program

Now we can combine all our tried and tested subroutines to make the overall main program.





lives = 7
guessed = []
word = get_word()
mask = make_mask(word)
while lives > 0 and mask != word:
    print(f"{mask}")
    letter, guessed = get_letter(guessed)
    mask, lives = check_letter(letter, mask, word, lives)
    show_state{lives}
check_win(lives, word)

Extensions

My favourite way to extend this project is by adding ascii art. Here is a link to some ASCII art and a wordbank of animals. Future improvements you might consider include offering a choice of topics that load different lists from different text files or a separate textfile of used words to avoid repeats.


<< Next: Practical challenges 8

© All materials created by and copyright S.Goff