Build Your Own Wordle Game in Python

Adina Socaci
12 min readJul 30, 2024

--

A Step-by-Step Guide

In this tutorial, we’ll learn how to build our own Wordle-like game in Python. 🐍

If you don’t know, Wordle is a popular word-guessing game where you have six attempts to guess a five-letter word. Each guess receives feedback, indicating which letters are correct and in the right position, which letters are in the word but in the wrong position, and which letters are not in the word at all. 🤓

Prerequisites

  • Basic understanding of Python syntax.
  • Python installed on your computer.

Step 1: Setting Up Your Environment And Import Necessary Libraries

Create a new Python file called wordle.py.

We will use the random library to select a random word from our list.

import random

Step 2: Create a List of Words

We’ll start with a simple list of 5-letter words. You can expand this list or load words from a file for more variety.

def load_words():
return ["audio", "track", "bleed", , "index", "cards", "ghost", "apple", "bread", "crane", "eagle", "flame", "grape", "honey", "joker"]

This function returns a list of words that the game can choose from.

Step 3: Define the Feedback Function

This function will compare the guessed word with the secret word and provide feedback on each letter.

def get_feedback(secret, guess):
feedback = []
for i, letter in enumerate(guess):
if letter == secret[i]:
feedback.append(f"{letter} is correct!")
elif letter in secret:
feedback.append(f"{letter} is in the word but in the wrong position.")
else:
feedback.append(f"{letter} is not in the word.")
return feedback

This function iterates through each letter in the guessed word and compares it with the secret word, providing specific feedback.

Step 4: Implement the Main Game Function

This function controls the game flow: selecting a random word, taking guesses from the player, and providing feedback.

def play_wordle():
words = load_words()
secret_word = random.choice(words)
attempts = 6
print("Welcome to Wordle!")
print("Guess the 5-letter word. You have 6 attempts.")
for attempt in range(attempts):
guess = input(f"Attempt {attempt + 1}/{attempts}: ").lower()

if len(guess) != 5:
print("Please enter a 5-letter word.")
continue
if guess == secret_word:
print(f"Congratulations! You've guessed the word '{secret_word}' correctly!")
break
feedback = get_feedback(secret_word, guess)
for message in feedback:
print(message)
if attempt == attempts - 1:
print(f"Sorry, you've run out of attempts. The word was '{secret_word}'.")
  1. words holds the list of possible secret words.
  2. secret_word is chosen randomly from the list.
  3. The player has 6 attempts to guess the word.
  4. For each guess, the player is given feedback based on their input.

Step 5: Run the Game

Finally, we need to call the main game function to start the game.

if __name__ == "__main__":
play_wordle()

This ensures that the game starts when we run the script.

Complete Solution

import random

def load_words():
return ["apple", "bread", "crane", "drake", "eagle", "flame", "grape", "honey", "index", "joker"]
def get_feedback(secret, guess):
feedback = []
for i, letter in enumerate(guess):
if letter == secret[i]:
feedback.append(f"{letter} is correct!")
elif letter in secret:
feedback.append(f"{letter} is in the word but in the wrong position.")
else:
feedback.append(f"{letter} is not in the word.")
return feedback
def play_wordle():
words = load_words()
secret_word = random.choice(words)
attempts = 6
print("Welcome to Wordle!")
print("Guess the 5-letter word. You have 6 attempts.")
for attempt in range(attempts):
guess = input(f"Attempt {attempt + 1}/{attempts}: ").lower()

if len(guess) != 5:
print("Please enter a 5-letter word.")
continue
if guess == secret_word:
print(f"Congratulations! You've guessed the word '{secret_word}' correctly!")
break
feedback = get_feedback(secret_word, guess)
for message in feedback:
print(message)
if attempt == attempts - 1:
print(f"Sorry, you've run out of attempts. The word was '{secret_word}'.")
if __name__ == "__main__":
play_wordle()

To run the game, simply save this code to a file (e.g., wordle.py) and run it using Python:

python wordle.py

Congratulations! You’ve just built your OWN Wordle game in Python. ✨

Let’s make things a bit more interesting. 😎

Challenge 1

Let’s make the list of words to be read from a file instead of inserting them manually.

We can download a comprehensive word list from sources like this GitHub repository which contains a list of English words. Download the words_alpha.txt file and place it in the same directory as your Python script.

Our new step 2 will be looking like this:

def load_words():
with open("words_alpha.txt", "r") as file:
words = file.read().splitlines()
five_letter_words = [word for word in words if len(word) == 5]
return five_letter_words

The load_words function reads the words from the words_alpha.txt file and filters them to include only 5-letter words.

for i, letter in enumerate(guess)

  • This is a for loop that iterates over each element in guess.
  • i is the index (position) of the current element in the list guess.
  • letter is the actual letter at the current index in guess.
  • enumerate is a built-in Python function that adds a counter to an iterable (in this case, the string guess) and returns it as an enumerate object.
  • When you loop through enumerate(guess), it yields pairs of the form (index, element). So, for each iteration, i will be the index of the letter, and letter will be the character at that index in the string guess.

if letter == secret[i]

  • This is a condition that checks whether the letter from the guess is equal to the corresponding letter in the secret word.
  • secret[i] accesses the letter in the secret word at index i.
  • The == operator checks for equality between letter and secret[i].

Challenge 2

Let’s use colored text output to make it more visually appealing (e.g., green for correct letters, yellow for correct but misplaced letters, and red for incorrect letters). 👀

First, we need to install the colorama library. You can do this using pip.

pip install colorama

Also, we’ll modify the get_feedback function to include colored text output and positional hints.

Complete Solution

import random
from colorama import Fore, Style, init

init(autoreset=True)

def load_words():
with open("words_alpha.txt", "r") as file:
words = file.read().splitlines()
five_letter_words = [word for word in words if len(word) == 5]
return five_letter_words

def get_feedback(secret, guess):
feedback = []
correct_position = 0
correct_letter = 0

for i, letter in enumerate(guess):
if letter == secret[i]:
feedback.append(Fore.GREEN + letter + Style.RESET_ALL)
correct_position += 1
elif letter in secret:
feedback.append(Fore.YELLOW + letter + Style.RESET_ALL)
correct_letter += 1
else:
feedback.append(Fore.RED + letter + Style.RESET_ALL)

hint = f"Correct letters in correct position: {correct_position}, Correct letters in wrong position: {correct_letter}"
return feedback, hint

def play_wordle():
words = load_words()
secret_word = random.choice(words)
attempts = 6

print("Welcome to Wordle!")
print("Guess the 5-letter word. You have 6 attempts.")

for attempt in range(attempts):
guess = input(f"Attempt {attempt + 1}/{attempts}: ").lower()

if len(guess) != 5:
print("Please enter a 5-letter word.")
continue

if guess == secret_word:
print(f"Congratulations! You've guessed the word '{secret_word}' correctly!")
break

feedback, hint = get_feedback(secret_word, guess)
print("Feedback: " + " ".join(feedback))
print(hint)

if attempt == attempts - 1:
print(f"Sorry, you've run out of attempts. The word was '{secret_word}'.")

if __name__ == "__main__":
play_wordle()

The init() function in colorama initializes the library and configures the terminal to support ANSI escape sequences. When autoreset is set to True, it automatically resets the text color and style after each print statement.

Challenge 3

Add a timer to track how long the player takes to guess the word. ⏰

Let’s import the time module at the beginning of our script.

import time

We record the start time right before the player starts making guesses using time.time(), which returns the current time in seconds since the epoch (a fixed point in time used as a reference, usually January 1, 1970).

start_time = time.time()

We record the end time when the player either guesses the word correctly or runs out of attempts.

end_time = time.time()

We calculate the duration by subtracting the start time from the end time. This gives us the total time taken by the player in seconds.

duration = end_time - start_time  

Complete Solution

import random
from colorama import Fore, Style, init
import time

init(autoreset=True)

def load_words():
with open("words_alpha.txt", "r") as file:
words = file.read().splitlines()
five_letter_words = [word for word in words if len(word) == 5]
return five_letter_words

def get_feedback(secret, guess):
feedback = []
correct_position = 0
correct_letter = 0

for i, letter in enumerate(guess):
if letter == secret[i]:
feedback.append(Fore.GREEN + letter + Style.RESET_ALL)
correct_position += 1
elif letter in secret:
feedback.append(Fore.YELLOW + letter + Style.RESET_ALL)
correct_letter += 1
else:
feedback.append(Fore.RED + letter + Style.RESET_ALL)

hint = f"Correct letters in correct position: {correct_position}, Correct letters in wrong position: {correct_letter}"
return feedback, hint

def play_wordle():
words = load_words()
secret_word = random.choice(words)
attempts = 6

print("Welcome to Wordle!")
print("Guess the 5-letter word. You have 6 attempts.")

start_time = time.time()

for attempt in range(attempts):
guess = input(f"Attempt {attempt + 1}/{attempts}: ").lower()

if len(guess) != 5:
print("Please enter a 5-letter word.")
continue

if guess == secret_word:
end_time = time.time()
duration = end_time - start_time
print(f"Congratulations! You've guessed the word '{secret_word}' correctly!")
print(f"You took {duration:.2f} seconds to guess the word.")
break

feedback, hint = get_feedback(secret_word, guess)
print("Feedback: " + " ".join(feedback))
print(hint)

if attempt == attempts - 1:
end_time = time.time()
duration = end_time - start_time
print(f"Sorry, you've run out of attempts. The word was '{secret_word}'.")
print(f"You took {duration:.2f} seconds to complete the game.")

if __name__ == "__main__":
play_wordle()

Challenge 4

Implement a leaderboard.

We import the json module to handle reading from and writing to the leaderboard file.

  • load_leaderboard: This function reads the leaderboard from the file. If the file does not exist, it initializes an empty leaderboard.
  • save_leaderboard: This function saves the leaderboard to the file.
  • update_leaderboard: This function updates the leaderboard with the player's time, sorts it, and keeps only the top 5 scores.
  • display_leaderboard: This function displays the current top scores.

At the start of the game, we will display the current leaderboard.

Let’s ask the player to enter their name.

When the player guesses the word correctly or runs out of attempts, we record the end time, calculate the duration, update the leaderboard, and display the updated leaderboard.

Complete Solution

import random
from colorama import Fore, Style, init
import time
import json

init(autoreset=True)

LEADERBOARD_FILE = "leaderboard.json"

def load_words():
with open("words_alpha.txt", "r") as file:
words = file.read().splitlines()
five_letter_words = [word for word in words if len(word) == 5]
return five_letter_words

def get_feedback(secret, guess):
feedback = []
correct_position = 0
correct_letter = 0

for i, letter in enumerate(guess):
if letter == secret[i]:
feedback.append(Fore.GREEN + letter + Style.RESET_ALL)
correct_position += 1
elif letter in secret:
feedback.append(Fore.YELLOW + letter + Style.RESET_ALL)
correct_letter += 1
else:
feedback.append(Fore.RED + letter + Style.RESET_ALL)

hint = f"Correct letters in correct position: {correct_position}, Correct letters in wrong position: {correct_letter}"
return feedback, hint

def load_leaderboard():
try:
with open(LEADERBOARD_FILE, "r") as file:
leaderboard = json.load(file)
except FileNotFoundError:
leaderboard = []
return leaderboard

def save_leaderboard(leaderboard):
with open(LEADERBOARD_FILE, "w") as file:
json.dump(leaderboard, file)

def update_leaderboard(name, duration):
leaderboard = load_leaderboard()
leaderboard.append({"name": name, "time": duration})
leaderboard = sorted(leaderboard, key=lambda x: x["time"])[:5]
save_leaderboard(leaderboard)
return leaderboard

def display_leaderboard():
leaderboard = load_leaderboard()
if not leaderboard:
print("No scores yet. Be the first to play!")
return
print("Leaderboard:")
for entry in leaderboard:
print(f"{entry['name']} - {entry['time']:.2f} seconds")

def play_wordle():
words = load_words()
secret_word = random.choice(words)
attempts = 6

print("Welcome to Wordle!")
print("Guess the 5-letter word. You have 6 attempts.")
display_leaderboard()
name = input("Enter your name: ")

start_time = time.time()

for attempt in range(attempts):
guess = input(f"Attempt {attempt + 1}/{attempts}: ").lower()

if len(guess) != 5:
print("Please enter a 5-letter word.")
continue

if guess == secret_word:
end_time = time.time()
duration = end_time - start_time
print(f"Congratulations! You've guessed the word '{secret_word}' correctly!")
print(f"You took {duration:.2f} seconds to guess the word.")
leaderboard = update_leaderboard(name, duration)
display_leaderboard()
break

feedback, hint = get_feedback(secret_word, guess)
print("Feedback: " + " ".join(feedback))
print(hint)

if attempt == attempts - 1:
end_time = time.time()
duration = end_time - start_time
print(f"Sorry, you've run out of attempts. The word was '{secret_word}'.")
print(f"You took {duration:.2f} seconds to complete the game.")
leaderboard = update_leaderboard(name, duration)
display_leaderboard()

if __name__ == "__main__":
play_wordle()

Challenge 5

Ensure the input is a valid word, not just a five letter mumbo jumbo. 🧐

Let’s define the is_valid_word function that checks if the guessed word is in the list of valid words and add it to our code.

import random
from colorama import Fore, Style, init
import time
import json

init(autoreset=True)

LEADERBOARD_FILE = "leaderboard.json"

def load_words():
with open("words_alpha.txt", "r") as file:
words = file.read().splitlines()
five_letter_words = [word for word in words if len(word) == 5]
return five_letter_words

def get_feedback(secret, guess):
feedback = []
correct_position = 0
correct_letter = 0

for i, letter in enumerate(guess):
if letter == secret[i]:
feedback.append(Fore.GREEN + letter + Style.RESET_ALL) # Correct letter in correct position
correct_position += 1
elif letter in secret:
feedback.append(Fore.YELLOW + letter + Style.RESET_ALL) # Correct letter in wrong position
correct_letter += 1
else:
feedback.append(Fore.RED + letter + Style.RESET_ALL) # Incorrect letter

hint = f"Correct letters in correct position: {correct_position}, Correct letters in wrong position: {correct_letter}"
return feedback, hint

def load_leaderboard():
try:
with open(LEADERBOARD_FILE, "r") as file:
leaderboard = json.load(file)
except FileNotFoundError:
leaderboard = []
return leaderboard

def save_leaderboard(leaderboard):
with open(LEADERBOARD_FILE, "w") as file:
json.dump(leaderboard, file)

def update_leaderboard(name, duration):
leaderboard = load_leaderboard()
leaderboard.append({"name": name, "time": duration})
leaderboard = sorted(leaderboard, key=lambda x: x["time"])[:5]
save_leaderboard(leaderboard)
return leaderboard

def display_leaderboard():
leaderboard = load_leaderboard()
if not leaderboard:
print("No scores yet. Be the first to play!")
return
print("Leaderboard:")
for entry in leaderboard:
print(f"{entry['name']} - {entry['time']:.2f} seconds")

def is_valid_word(word, valid_words):
return word in valid_words

def play_wordle():
words = load_words()
secret_word = random.choice(words)
attempts = 6

print("Welcome to Wordle!")
print("Guess the 5-letter word. You have 6 attempts.")
display_leaderboard()
name = input("Enter your name: ")

start_time = time.time()

for attempt in range(attempts):
guess = input(f"Attempt {attempt + 1}/{attempts}: ").lower()

if len(guess) != 5:
print("Please enter a 5-letter word.")
continue

if not is_valid_word(guess, words):
print("Invalid word. Please enter a valid 5-letter word.")
continue

if guess == secret_word:
end_time = time.time()
duration = end_time - start_time
print(f"Congratulations! You've guessed the word '{secret_word}' correctly!")
print(f"You took {duration:.2f} seconds to guess the word.")
leaderboard = update_leaderboard(name, duration)
display_leaderboard()
break

feedback, hint = get_feedback(secret_word, guess)
print("Feedback: " + " ".join(feedback))
print(hint)

if attempt == attempts - 1:
end_time = time.time()
duration = end_time - start_time
print(f"Sorry, you've run out of attempts. The word was '{secret_word}'.")
print(f"You took {duration:.2f} seconds to complete the game.")
leaderboard = update_leaderboard(name, duration)
display_leaderboard()

if __name__ == "__main__":
play_wordle()

Challenge 6

User Experience Enhancements

Develop a GUI using libraries such as Tkinter or Pygame to make the game more interactive. Add sound effects for correct/incorrect guesses to make the game more engaging. Provide clear instructions and a help menu for new players.

We import the necessary libraries, including tkinter for the GUI and pygame for sound effects.

Then, we can load sound effects for correct and incorrect guesses using pygame.mixer.Sound. All these additional files, such as these audio files, should be in the same directory with your Python file.

correct_sound = pygame.mixer.Sound("correct.mp3") 
incorrect_sound = pygame.mixer.Sound("incorrect.mp3")
win_sound = pygame.mixer.Sound("win.mp3")
lose_sound = pygame.mixer.Sound("lose.mp3")

The WordleGame class sets up the Tkinter GUI, including labels, entry fields, and buttons.

Let’s add a help button that displays instructions for the game using a Tkinter messagebox, and a label to display the number of remaining attempts and update it each time the player makes a guess. Each time the player makes a guess, we decrement the attempts count and update the label.

Let’s also make it so the leaderboard is updated only if the player guesses the word correctly. The update happens inside the condition that checks if the guess is correct.

The if __name__ == “__main__” block initializes the Tkinter main loop to start the game.

Complete Solution

import random
import time
import json
import tkinter as tk
from tkinter import messagebox
import pygame

# Initialize pygame
pygame.mixer.init()

# Load sound effects
correct_sound = pygame.mixer.Sound("correct.mp3")
incorrect_sound = pygame.mixer.Sound("incorrect.mp3")
win_sound = pygame.mixer.Sound("win.mp3")
lose_sound = pygame.mixer.Sound("lose.mp3")

LEADERBOARD_FILE = "leaderboard.json"
WORDS_FILE = "words_alpha.txt"

def load_words():
with open(WORDS_FILE, "r") as file:
words = file.read().splitlines()
five_letter_words = [word for word in words if len(word) == 5]
return five_letter_words

def get_feedback(secret, guess):
feedback = []

for i, letter in enumerate(guess):
if letter == secret[i]:
feedback.append(('green', letter))
elif letter in secret:
feedback.append(('yellow', letter))
else:
feedback.append(('red', letter))

return feedback

def load_leaderboard():
try:
with open(LEADERBOARD_FILE, "r") as file:
leaderboard = json.load(file)
except FileNotFoundError:
leaderboard = []
return leaderboard

def save_leaderboard(leaderboard):
with open(LEADERBOARD_FILE, "w") as file:
json.dump(leaderboard, file)

def update_leaderboard(name, duration):
leaderboard = load_leaderboard()
leaderboard.append({"name": name, "time": duration})
leaderboard = sorted(leaderboard, key=lambda x: x["time"])[:5]
save_leaderboard(leaderboard)
return leaderboard

def display_leaderboard():
leaderboard = load_leaderboard()
if not leaderboard:
return "No scores yet. Be the first to play!"
leaderboard_text = "Leaderboard:\n"
for entry in leaderboard:
leaderboard_text += f"{entry['name']} - {entry['time']:.2f} seconds\n"
return leaderboard_text

def is_valid_word(word, valid_words):
return word in valid_words

class WordleGame:
def __init__(self, root):
self.root = root
self.root.title("Wordle Game")

self.words = load_words()
self.secret_word = random.choice(self.words)
self.attempts = 6
self.current_attempt = 0
self.start_time = time.time()

self.setup_gui()

def setup_gui(self):
self.instruction_label = tk.Label(self.root, text="Guess the 5-letter word. You have 6 attempts.")
self.instruction_label.pack()

self.name_label = tk.Label(self.root, text="Enter your name:")
self.name_label.pack()

self.name_entry = tk.Entry(self.root)
self.name_entry.pack()

self.guess_label = tk.Label(self.root, text="Enter your guess:")
self.guess_label.pack()

self.guess_entry = tk.Entry(self.root)
self.guess_entry.pack()

self.guess_button = tk.Button(self.root, text="Guess", command=self.make_guess)
self.guess_button.pack()

self.feedback_frame = tk.Frame(self.root)
self.feedback_frame.pack()

self.hint_label = tk.Label(self.root, text="")
self.hint_label.pack()

self.attempts_label = tk.Label(self.root, text=f"Attempts remaining: {self.attempts}")
self.attempts_label.pack()

self.leaderboard_label = tk.Label(self.root, text=display_leaderboard())
self.leaderboard_label.pack()

self.help_button = tk.Button(self.root, text="Help", command=self.show_help)
self.help_button.pack()

def show_help(self):
help_text = ("Welcome to Wordle!\n"
"1. Enter your name.\n"
"2. Guess the 5-letter word.\n"
"3. You have 6 attempts to guess the word.\n"
"4. Feedback will be given for each guess:\n"
" - Green: Correct letter and position.\n"
" - Yellow: Correct letter but wrong position.\n"
" - Red: Incorrect letter.\n"
"5. Try to guess the word in the shortest time possible.\n"
"6. Your time will be recorded and displayed on the leaderboard.")
messagebox.showinfo("Help", help_text)

def make_guess(self):
guess = self.guess_entry.get().lower()
name = self.name_entry.get()

if len(guess) != 5:
messagebox.showerror("Error", "Please enter a 5-letter word.")
return

if not is_valid_word(guess, self.words):
messagebox.showerror("Error", "Invalid word. Please enter a valid 5-letter word.")
return

self.current_attempt += 1
self.attempts -= 1
self.attempts_label.config(text=f"Attempts remaining: {self.attempts}")

if guess == self.secret_word:
end_time = time.time()
duration = end_time - self.start_time
pygame.mixer.Sound.play(win_sound)
messagebox.showinfo("Congratulations!", f"You've guessed the word '{self.secret_word}' correctly!\nYou took {duration:.2f} seconds.")
leaderboard = update_leaderboard(name, duration)
self.leaderboard_label.config(text=display_leaderboard())
self.reset_game()
return

feedback = get_feedback(self.secret_word, guess)
self.display_feedback(feedback)

pygame.mixer.Sound.play(incorrect_sound)

if self.current_attempt == self.attempts:
end_time = time.time()
duration = end_time - self.start_time
pygame.mixer.Sound.play(lose_sound)
messagebox.showinfo("Game Over", f"Sorry, you've run out of attempts. The word was '{self.secret_word}'.\nYou took {duration:.2f} seconds.")
self.reset_game()

def display_feedback(self, feedback):
for widget in self.feedback_frame.winfo_children():
widget.destroy()

for color, letter in feedback:
label = tk.Label(self.feedback_frame, text=letter, bg=color, width=4, height=2)
label.pack(side=tk.LEFT)

def reset_game(self):
self.secret_word = random.choice(self.words)
self.current_attempt = 0
self.attempts = 6
self.start_time = time.time()
self.name_entry.delete(0, tk.END)
self.guess_entry.delete(0, tk.END)
self.feedback_frame.pack_forget()
self.hint_label.config(text="")
self.attempts_label.config(text=f"Attempts remaining: {self.attempts}")
self.feedback_frame = tk.Frame(self.root)
self.feedback_frame.pack()

if __name__ == "__main__":
root = tk.Tk()
game = WordleGame(root)
root.mainloop()

My final game looks like this:

What other things would you like to improve, and how would you do it?

Happy Coding!

Thank you for reading! 💖

Follow me |Subscribe to know when I publish a story

Like this lesson? Buy me a coffee and show your appreciation

--

--