Mad Libs Game with Python
Welcome to Project #4 of the Build & Challenge Series!
Today, we’re adding a playful twist by making a Mad Libs game in Python.
Remember those stories where you fill in random words and end up with something completely hilarious?
Now, you’ll create that experience yourself with a simple app that lets users add words to a pre-made story.
It’s easy to build and full of laughs—perfect for sharing with friends!
What you’ll build:
Contents
Mad Libs Game with Python
Step 0: Create or Download the CSV File
Purpose of CSV: The CSV file is like a small database where each story template with placeholders is saved. Each row represents a unique story with a title and a template text.
Columns in the CSV:
sno
: Serial number, which uniquely identifies each story.Title
: The title of the story.Story
: The story text containing placeholders (e.g.,[ADJECTIVE]
,[NOUN]
) that users will replace with their own words.
You can use this CSV:
➡️ Click for the CSV:
sno, Title, Story
1, The Princess, Once upon a time there was a [ADJECTIVE] princess named [PERSONS_NAME] she was from [COUNTRY] she lived in a beautiful kingdom on the hills called [KINGDOM_NAME] she had five [PLURAL_NOUN] while she was [VERB] the horse she fell off of the horse and her dress had a [COLOR] stain on it when she got back to the kingdom she quickly changed to she could wash her dress her [NOUN] told her to come down for dinner after they finished eating they all went to take [PLURAL_VERB] the following day the princess went out to the village to go to the supermarket when she ran into a prince they fel in love and got married and had three children and they lived happily ever after.
2, A Rainy Day, One [ADJECTIVE] day I was walking my [COLOR] pet [NOUN] when [PLURAL_NOUN] started flying from the sky! I called my friend [PERSONS_NAME] and she said one just landed right on her [PLACE] ! [ADVERB] there was raining [PLURAL_NOUN] as well and they were just going everywhere! My [NOUN] started [VERB] and catching [PLURAL_NOUN] with his mouth to eat.
3, Bats Are So Cool!,Bats are so cool! They are [COLOR] [ADJECTIVE] animals which have wings. They like to fly around at [TIME] which makes some people scared of them. But bats are [ADJECTIVE] and they don't want to hurt people. I have a pet bat that lives in [PLACE]. I like to feed him [FOOD] and [FOOD]. He likes to [VERB]. I am his favorite person but he also likes [NOUN]. I want to convince my parents to get me [NUMBER] more bats.
4,My First Day Of School,"Today was my first day of [NUMBER_1_TO_8] grade. My teacher is ms.. She seems [ADJECTIVE] and [ADJECTIVE]. I think her class will be pretty [ADJECTIVE]. My friends [NOUN] and [NOUN] are also in my class. We messed around during class by hiding [NOUN] in peoples' [PLURAL_NOUN] and asking questions about [NOUN]. The teacher got really [ADJECTIVE] at us and told us that we have to go to the [NOUN]. This just made us [VERB] more. It was a [ADJECTIVE] first day of school!"
5,"Birthday Party Fun!","Yesterday I went to [PERSONS_NAME]'s birthday party. I got him/her a [NOUN]. The party was [ADJECTIVE]. We started by playing [ACTIVITY] and then there was a [VERB] party. Lots of my friends were there but I mostly hung out with [PERSONS_NAME]. We talked about [NOUN] and how our friend [PERSONS_NAME] is a [NOUN]. During cake everyone [PAST_TENSE_VERB] and sang [SONG_NAME]. I had a [ADJECTIVE] time at the party and enjoyed celebrating [PERSONS_NAME]. He/she is such a [ADJECTIVE] friend."
6,The New TV Show,The new TV show titled [TITLE] has taken the world by [NOUN]. It features [NUMBER] [ADJECTIVE] characters including [NAME] who is a [OCCUPATION] with a secret talent for [VERB_WITH_IN] . Each episode the characters find themselves in [ADJECTIVE] situations like [VERB] in a [PLACE] or having a [ADJECTIVE] showdown with a [NOUN]. The most shocking twist came when [NAME] revealed they were actually a [ADJECTIVE] [ANIMAL] ! Fans can't stop talking about the [ADJECTIVE] [NOUN] that appears in every episode and everyone is dying to know how it all ends. With a [NUMBER] -season arc planned viewers are [VERB_WITH_IN] for more! Join the craze and watch the show to see why it's the [ADJECTIVE] show of the year!
Mad Libs Game with Python Mad Libs Game with Python Mad Libs Game with Python Mad Libs Game with Python Mad Libs Game with Python
Step 1: Create the Main Menu (main_menu
Method)
Create the main screen of the app with options to either:
- Add a New Story: Allows the user to create a new story template.
- Play Existing Story: Lets the user choose from existing stories in the CSV file.
➡️ Click for the code
from customtkinter import *
import csv
import re
class MadLib(CTk):
def __init__(self):
super().__init__()
self.title("MadLib")
self.main_menu()
# Step 1: Create main menu
def main_menu(self):
self.title_lb = CTkLabel(self, text="Mad Lib!")
self.title_lb.grid(row=0, column=1, padx=30, columnspan=2)
self.add_story_btn = CTkButton(self, text="Add Story!", command=self.create_story)
self.add_story_btn.grid(row=1, column=1, padx=10, pady=10)
self.existing_story_btn = CTkButton(self, text="Existing Story!", command=self.show_stories)
self.existing_story_btn.grid(row=1, column=2, padx=10, pady=10)
Mad Libs Game with Python Mad Libs Game with Python Mad Libs Game with Python
- Creating the Main Menu: The
main_menu
method creates two buttons:- Add Story Button: Calls the
create_story
method to allow users to add a new story template. - Existing Story Button: Calls the
show_stories
method to display all the stories saved in the CSV file.
- Add Story Button: Calls the
- Using
CTkLabel
andCTkButton
: These are part of thecustomtkinter
library, which offers customizable versions of standard Tkinter widgets. Labels (CTkLabel
) display static text, while buttons (CTkButton
) trigger actions when clicked.
Step 2: Display All Stories (show_stories
Method)
This step reads all stories from the CSV file and shows each one as a clickable option for the user.
➡️ Click for the code
# Step 2: Get all Stories
def show_stories(self):
"""Fetches all the stories from the csv file"""
# Clear screen and go back to main menu
self.clear_screen()
self.main_menu()
self.clear_screen()
# Display title
title_label = CTkLabel(self, text="Existing Stories")
title_label.grid(row=0, column=1, padx=30, pady=10, columnspan=2)
# Read stories from the CSV file
with open("madlib.csv", "r") as file:
reader = csv.reader(file)
for idx, row in enumerate(reader):
if idx != 0:
sid, title, story = row
# Display each story title with a 'Play' button
title_label = CTkLabel(self, text=f"{sid}. {title}")
title_label.grid(row=idx, column=0, padx=10, pady=5)
play_btn = CTkButton(self, text="Play", command=lambda story=story: self.play(story))
play_btn.grid(row=idx, column=1, padx=10, pady=5)
Mad Libs Game with Python Mad Libs Game with Python
- Reading the CSV File:
- The method opens
madlib.csv
in read mode. - It reads each row using
csv.reader
, where each row contains the story’s serial number (sno
), title, and story template.
- The method opens
- Displaying Stories:
- For each story in the CSV, a label displays the story title.
- A “Play” button is created for each story, allowing users to start playing a particular story.
- Lambda Function:
- Each “Play” button uses a lambda function to call the
play
method with the corresponding story’s template. This lambda function is necessary because it allows us to pass each story’s content to theplay
method dynamically.
- Each “Play” button uses a lambda function to call the
Step 2.1: clear_screen
Helper Method
This method clears all widgets from the screen by iterating over each widget and calling widget.destroy()
on it, allowing the app to update the display with new content.
➡️ Click for the code
# Step 2.1: Helper for all the methods
def clear_screen(self):
# Loop through all widgets and destroy them
for widget in self.winfo_children():
widget.destroy()
Mad Libs Game with Python Mad Libs Game with Python Mad Libs Game with Python
Step 3: Play the Selected Story (play
Method)
Once a user selects a story, this method displays fields for each placeholder in the story template, prompting the user to enter their own words.
➡️ Click for the code
# Step 3: Play Selected Story
def play(self, story_data):
"""Let's you play the selected story"""
self.clear_screen()
placeholders = set(re.findall(r'\[(\w+)\]', story_data))
self.entry_fields = {}
row = 0
for placeholder in placeholders:
CTkLabel(self, text=f"Enter {placeholder}").grid(row=row, column=0, padx=10, pady=5)
entry = CTkEntry(self)
entry.grid(row=row, column=1, padx=10, pady=5)
# Save entry field for future reference
self.entry_fields[placeholder] = entry
row += 1
# Button to generate completed story
submit_btn = CTkButton(self, text="See Story", command=lambda: self.show_completed_story(self.entry_fields, story_data))
submit_btn.grid(row=row, column=1, padx=10, pady=10)
Mad Libs Game with Python
- Extracting Placeholders:
- The
re.findall(r'\[(\w+)\]', story_data)
line uses regular expressions to identify placeholders within square brackets (like[ADJECTIVE]
or[NOUN]
). - These placeholders are stored in a set (
placeholders
) to avoid duplicates.
- The
- Creating Input Fields for Placeholders:
- For each placeholder, the code dynamically creates a label and an entry field.
- Each entry field is saved in a dictionary (
self.entry_fields
), with the placeholder text as the key. This allows for easy access to user inputs for each placeholder.
- Submit Button:
- A button labeled “See Story” triggers the
show_completed_story
method. When clicked, it sends both the user inputs and the story template toshow_completed_story
, which fills in the placeholders with user inputs.
- A button labeled “See Story” triggers the
Step 4: Show Completed Story (show_completed_story
Method)
This step takes the story template and user inputs, fills in each placeholder, and displays the completed story.
➡️ Click for the code
# Step 4: Show completed stories
def show_completed_story(self, input_fields:dict, story:str):
"""Generate the final story by replacing placeholders with user input."""
# Replace each placeholder in the story with the input from the corresponding entry field
for placeholder, entry in input_fields.items():
user_input = entry.get() # Get the text from the entry field
story = story.replace(f"[{placeholder}]", user_input) # Replace placeholder in the story
# Clear the screen to display the completed story
self.clear_screen()
# Display the completed story
completed_story_label = CTkLabel(self, text="Your Completed Story!")
completed_story_label.grid(row=0, column=0, padx=20, pady=10, columnspan=2)
# Show the final story text in a label, breaking lines as needed
story_text_label = CTkLabel(self, text=story, wraplength=400, justify="left")
story_text_label.grid(row=1, column=0, padx=20, pady=20, columnspan=2)
# Button to go back to the main screen or restart
back_btn = CTkButton(self, text="Back to Menu", command=self.temp)
back_btn.grid(row=2, column=0, padx=10, pady=10, columnspan=2)
Mad Libs Game with Python Mad Libs Game with Python
- Replacing Placeholders:
- A loop goes through each placeholder, fetching the user input from
self.entry_fields[placeholder]
usingentry.get()
. - The
story.replace(f"[{placeholder}]", user_input)
line replaces each placeholder with the corresponding user input.
- A loop goes through each placeholder, fetching the user input from
- Displaying the Final Story:
- After replacing all placeholders, the screen is cleared, and the completed story is displayed in a label.
- A “Back to Menu” button allows users to return to the main menu, calling the
temp
method.
Step 5: Create New Story (create_story
Method)
This step allows users to create and save a new story template into the CSV file.
➡️ Click for the code
# Step 5: Create new story
def create_story(self):
"""Let's create a new story. By taking story from user."""
self.clear_screen()
# Create label and entry for story title
title_label = CTkLabel(self, text="Enter Story Title")
title_label.grid(row=0, column=0, padx=10, pady=10)
self.title_entry = CTkEntry(self, width=300)
self.title_entry.grid(row=0, column=1, padx=10, pady=10)
# Create label and entry for story content
content_label = CTkLabel(self, text="Enter Story Content")
content_label.grid(row=1, column=0, padx=10, pady=10)
self.content_entry = CTkEntry(self, width=300, height=150)
self.content_entry.grid(row=1, column=1, padx=10, pady=10)
# Button to save story
save_btn = CTkButton(self, text="Save Story", command=self.save_story)
save_btn.grid(row=2, column=1, padx=10, pady=10)
Mad Libs Game with Python Mad Libs Game with Python Mad Libs Game with Python Mad Libs Game with Python
- Title and Content Fields:
- Two entry fields are created, one for the story title and one for the story content.
- The content can include placeholders to be filled by users when they play the story.
- Save Button:
- A “Save Story” button calls the
save_story
method, which stores the new story in the CSV file.
- A “Save Story” button calls the
Step 6: Save Created Story (save_story
Method)
This step handles saving the new story entered by the user to the CSV file.
➡️ Click for the code
# Step 6: Save Created story
def save_story(self):
"""Saves created story to the csv."""
# Get story title and content from entry fields
story_title = self.title_entry.get()
story_content = self.content_entry.get()
# Remove commas and newlines from the story content to avoid CSV format issues
story_content = re.sub(r"[,\n\r]", "", story_content)
# Determine the next serial number based on the last entry in the CSV
try:
with open("madlib.csv", "r", encoding="utf-8") as file:
reader = csv.reader(file)
rows = list(reader)
if len(rows) > 1: # Check if there are rows other than the header
last_sno = int(rows[-1][0]) # Get the last serial number
sno = last_sno + 1
else:
sno = 1 # Start with 1 if no other entries
except FileNotFoundError:
# File doesn't exist, start from serial number 1
sno = 1
# Append the new story to the CSV file
with open("madlib.csv", "a", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerow([sno, story_title, story_content])
Mad Libs Game with Python Mad Libs Game with Python
- Fetching User Inputs:
- The title and content entered by the user are retrieved from the entry fields.
- Formatting Content:
- Commas and newline characters are removed from the content to avoid issues with CSV formatting.
- Determining Serial Number (
sno
):- If the CSV file already has entries, it reads the last entry to determine the next serial number. If the CSV doesn’t exist, it defaults to serial number 1.
- Appending to CSV:
- The story is saved by appending a new row with
sno
, title, and content to the CSV file.
- The story is saved by appending a new row with
Step 6.1: temp
Helper Method
This method is a helper to clear the screen and return to the main menu by calling clear_screen
and then main_menu
.
➡️ Click for the code
# Step 6.1:Helper For the save story method
def temp(self):
self.clear_screen()
self.main_menu()
Mad Libs Game with Python Mad Libs Game with Python
Step 7: Running the Application
Finally, app = MadLib()
creates an instance of the MadLib
class, and app.mainloop()
starts the main event loop, allowing the application to run continuously, awaiting user input.
app = MadLib()
app.mainloop()
Mad Libs Game with Python Mad Libs Game with Python
Ending Challenge
Challenge Time!
- Story Shuffle: Add a random story selector to your game so players get a surprise story every time they play.
- Double Trouble: Can you add a “Double Trouble” feature where two players take turns adding words to the same story? The end result? Twice the laughs!
- Leaderboard of Laughs: Create a leaderboard where players can rate each story for hilarity or creativity. Who will be crowned the Mad Libs Master?
Full Source Code
Once you’ve nailed the challenge, share your updated version here in the project’s repository GitHub! Let’s grow the project together and learn as a community.
The complete source code is in the GitHub link provided above.