Building a Console Word Game with Python

olumidenwosu

Olumide Nwosu

Posted on May 4, 2021

Building a Console Word Game with Python

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:
...........................................
Enter fullscreen mode Exit fullscreen mode

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!')
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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}.')
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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()

Enter fullscreen mode Exit fullscreen mode

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.

💖 💪 🙅 🚩
olumidenwosu
Olumide Nwosu

Posted on May 4, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related