Olumide Nwosu
Posted on May 4, 2021
A while back, during the time I started learning to code with Python, I wrote a program for a game that is quite similar to Hangman. A particular number of guesses is given and then the user tries to guess the letters of the secret word. The user loses one guess for each incorrect try and the game ends either when the user has guessed all the letters of the word completely or when they run out of guesses.
Getting into it
There are probably a million ways to go about writing this game but since this is my article, we will be doing it my way😁.
We want our game to look like what we have below:
You've chosen a/an 9-letter word!
Guess a letter: e
Good guess!
Guesses left: 9
Available letters: a b c d f g h i j k l m n o p q r s t u v w x y z
---E--E--
Guess a letter: l
Good guess!
Guesses left: 9
Available letters: a b c d f g h i j k m n o p q r s t u v w x y z
---E-LE--
Guess a letter: l
You have already guessed this letter!
Guess a letter:
...........................................
So now let's think about the structure.
- We need a secret word which the user tries to guess. We could easily do this by picking a random word from a list of words.
- The user has 9 guesses or tries which only decrease when a user guesses wrongly.
- When a user enters a guess, we have to check if the letter is in our secret word. If the letter has been guessed already, we let the user know, and as the kind developers that we are, we don't reduce their guesses😉.
- After each guess, the user is told how many guesses they have left and the letters that haven't been tried yet. They're also shown the word with the letters that have been guessed correctly and the rest of the letters are replaced with dashes i.e. if the word is BANANA and only 'A' has been guessed correctly,
-A-A-A
is shown. - We should also always check if the user has run out of guesses so that the guesses don't start counting in negatives😅.
- The game ends either when the user has been able to successfully guess the secret word, or when they run out of guesses.
- Some edge cases to consider are; when a user enters an invalid guess, e.g. a number, or when they enter more than one character at once.
Having considered all these, the code for our game will be split into five separate functions/methods.
play_game
check_guess
can_be_formed_from
display_info
format_word
play_game
This is the entry point of our game. This is where the user is prompted for their guess. The necessary checks are then carried out. To ensure that our game is bug-less.
import random as r
guesses = 9
letters = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
def format_word(guessed_letters, word):
pass
def display_info(guessed_letters, word):
pass
def check_guess(guess, word, guessed_letters):
pass
def can_be_formed_from(letters, word):
pass
def play_game():
word_list = ['programmer', 'python', 'defenestrate']
secret_word = r.choice(word_list)
word_length = len(secret_word)
guessed = []
print(f'You have chosen a/an {word_length}-letter word.')
while guesses > 0:
guess = input('Enter a letter: ')
guess = guess.upper()
check_guess(guess, secret_word, guessed)
if can_be_formed_from(guessed, secret_word):
return print('YOU WON!')
print('You ran out of guesses.\nYOU LOST!')
As we can see from above, a random word is chosen from a list of words(you can extend your list or fetch a bunch of words online), and then we do the user the courtesy of telling them how long it is. Then as long as the number of guesses is greater than zero, we keep prompting the user for a guess. The check_guess
function(which we'll get to in a moment) is then called to validate our guess and add it to guessed
which contains all the letters that have been tried. The can_be_formed_from
function is also called to check if the secret_word
can be formed from all the guessed letters. If it can, the user wins🎉. On the other hand, if the user runs out of guesses the game is ended. It would mean the user has lost, sadly😔. But as Nelson Mandela once said:
You never lose, you either win or learn.
check_guess
This function takes in the guessed letters, the
secret word and the new guess. It checks if the
guess is valid and prints the appropriate message if it's not. The display_info
function is then called.
def check_guess(guess, word, guessed_letters):
global guesses
if guess in letters and len(guess) == 1 and guess not in guessed_letters:
guessed_letters.append(guess)
if guess in word:
print('Good guess!')
else:
print('Bad guess!')
guesses -= 1
else:
if len(guess) != 1:
print('You must enter one letter, no more, no less!')
elif guess.upper() not in letters:
print('Your guess has to be a letter!')
elif guess in guessed_letters:
print('This letter has been tried already!')
display_info(guessed_letters, word)
A seen above, the following checks are performed:
- If the guess is valid i.e. a letter of the English alphabet(This game can be tweaked to work with any language).
- If the guess contains exactly one letter.
- If the guess is present in our secret word.
- If the letter entered has been tried already.
can_be_formed_from
As the name implies, this function accepts two strings and returns True
if the second string can be formed from the letters of the first else False
.
def can_be_formed_from(letters, word):
for letter in word:
if letter not in letters:
return False
return True
display_info
This function takes in the guessed letters and the secret word and generates the required data i.e. the number of guesses left, the letters that haven't been
tried yet etc. from the provided data.
def display_info(guessed_letters, word):
available_letters = ' '.join([
letter for letter in letters if letter not in guessed_letters
])
print(format_word(guessed_letters, word))
print(f'Guesses left: {guesses}.')
print(f'Available letters: {available_letters}.')
format_word
This function helps to format our secret word with the letters that have been guessed correctly. For example, if the secret word is PYTHON and only 'n', 'o' and 'p' have been guessed correctly, P---ON is displayed.
def format_word(guessed_letters, word):
formatted_string = ''
for letter in word:
if letter in guessed_letters:
formatted_string += letter
else:
formatted_string += '-'
return formatted_string
Putting all this together, we have:
word_game.py
import random as r
guesses = 9
letters = list('ABCDEFGHIJKLMNOPQRSTUVWXYZ')
def format_word(guessed_letters, word):
formatted_string = ''
for letter in word:
if letter in guessed_letters:
formatted_string += letter
else:
formatted_string += '-'
return formatted_string
def display_info(guessed_letters, word):
available_letters = ' '.join([
letter for letter in letters if letter not in guessed_letters
])
print(format_word(guessed_letters, word))
print(f'Guesses left: {guesses}.')
print(f'Available letters: {available_letters}.')
def check_guess(guess, word, guessed_letters):
global guesses
if guess in letters and len(guess) == 1 and guess not in guessed_letters:
guessed_letters.append(guess)
if guess in word:
print('Good guess!')
else:
print('Bad guess!')
guesses -= 1
else:
if len(guess) != 1:
print('You must enter one letter, no more, no less!')
elif guess.upper() not in letters:
print('Your guess has to be a letter!')
elif guess in guessed_letters:
print('This letter has been tried already!')
display_info(guessed_letters, word)
def can_be_formed_from(letters, word):
for letter in word:
if letter not in letters:
return False
return True
def play_game():
word_list = ['programmer', 'python', 'defenestrate']
secret_word = r.choice(word_list).upper()
word_length = len(secret_word)
guessed = []
print(f'You have chosen a/an {word_length}-letter word.')
while guesses > 0:
guess = input('Enter a letter: ')
guess = guess.upper()
check_guess(guess, secret_word, guessed)
if can_be_formed_from(guessed, secret_word):
return print('YOU WON!')
print('You ran out of guesses.\nYOU LOST!')
if __name__ == '__main__':
play_game()
Conclusion
By separating our code into small functions, it made building our game feel like a walk in the park. I hope this read was helpful to you😊. The full source code can be found here. Also, the OOP approach for our game can be found here. Feel free to ask questions here or reach on Twitter @OlumideNwosu.
Posted on May 4, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.