Advanced Mad Lib Generator (code) in Python

← Back to Projects

Advance Mad Libs Generator in Python

About the project:This program code Generates a Mad Libs story with some advanced additional features:

  • Multiple Stories/Templates
  • Random Word Suggestions
  • Error Handling for Input
  • Save/Load Stories
  • User-Defined Stories
  • Score/Rating System
  • Clearer Instructions/Examples and
  • Looping Play

Project Level: Beginner

You can directly copy the below snippet code with the help of green copy button, paste it and run it in any Python editor you have.

Steps: choose any code snippet and follow these steps

Step 1: Copy below code using green 'copy' button.

Step 2: Paste the code on your chosen editor.

Step 3: Save the code with filename and .py extention.

Step 4: Run (Press F5 if using python IDLE)



# mad_libs_generator.py

import random
import json
import os


# Global Data

# File to save/load user-defined stories and completed stories
STORIES_FILE = "mad_libs_stories.json"
COMPLETED_STORIES_FILE = "completed_mad_libs.json"

# Predefined lists of words for suggestions
WORD_SUGGESTIONS = {
    "adjective": ["sparkling", "mysterious", "gigantic", "tiny", "brave", "silly", "ancient", "futuristic", "wobbly", "shiny"],
    "noun": ["wizard", "dragon", "castle", "robot", "cat", "mountain", "flower", "spaceship", "shoe", "cloud"],
    "verb": ["sing", "dance", "jump", "fly", "eat", "sleep", "run", "whisper", "shout", "explore"],
    "adverb": ["quickly", "happily", "slowly", "loudly", "softly", "bravely", "eagerly", "silently", "clumsily", "gracefully"],
    "animal": ["lion", "elephant", "penguin", "squirrel", "octopus", "giraffe", "dolphin", "owl", "zebra", "koala"],
    "food": ["pizza", "sushi", "taco", "broccoli", "chocolate", "spaghetti", "sandwich", "curry", "pancake", "donut"],
    "liquid": ["water", "juice", "soda", "coffee", "milk", "tea", "soup", "nectar", "slime", "potion"],
    "emotion": ["happy", "sad", "angry", "excited", "confused", "surprised", "peaceful", "annoyed", "joyful", "nervous"],
    "exclamation": ["Wow!", "Ouch!", "Hooray!", "Boo!", "Yippee!", "Aha!", "Oh no!", "Eureka!", "Gasp!", "Indeed!"],
    "plural_noun": ["books", "trees", "cars", "friends", "stars", "shoes", "clouds", "monsters", "flowers", "buildings"],
    "person_name": ["Alice", "Bob", "Charlie", "Diana", "Eve", "Frank", "Grace", "Harry", "Ivy", "Jack"],
    "mythical_creature": ["unicorn", "griffin", "mermaid", "goblin", "fairy", "centaur", "phoenix", "werewolf", "vampire", "gnome"],
    "verb_ing": ["running", "jumping", "sleeping", "eating", "flying", "swimming", "laughing", "crying", "thinking", "dreaming"]
}


# Story Management Functions

def get_default_stories():
    """
    Returns a dictionary of default Mad Libs stories.
    """
    return {
        "1": {
            "title": "A Day at the Park",
            "template": """
            Today, I went to the park with my {adjective_1} {noun_1}.
            We saw a {adjective_2} {animal_1} {verb_ing_1} {adverb_1} near the {noun_2}.
            Then, we decided to {verb_1} on the {adjective_3} {noun_3}.
            It was a really {adjective_4} day, and we felt very {emotion_1}.
            """,
            "placeholders": [
                "adjective_1", "noun_1", "adjective_2", "animal_1",
                "verb_ing_1", "adverb_1", "noun_2", "verb_1",
                "adjective_3", "noun_3", "adjective_4", "emotion_1"
            ]
        },
        "2": {
            "title": "The Mysterious Journey",
            "template": """
            Once upon a time, a brave {hero_noun_1} set out on a {adjective_1} journey.
            Their mission was to find the {adjective_2} {mythical_creature_1} that lived in the {noun_1} mountains.
            Along the way, they had to {verb_1} over a {adjective_3} river and {verb_2} through a {adjective_4} forest.
            Finally, they found the {mythical_creature_1} and it said, "{exclamation_1}!"
            The {hero_noun_1} returned {adverb_1} and lived {adverb_2} ever after.
            """,
            "placeholders": [
                "hero_noun_1", "adjective_1", "adjective_2", "mythical_creature_1",
                "noun_1", "verb_1", "adjective_3", "verb_2",
                "adjective_4", "exclamation_1", "adverb_1", "adverb_2"
            ]
        },
        "3": {
            "title": "The Great Feast",
            "template": """
            For dinner last night, I ate a {adjective_1} {food_1}.
            It was served with {adjective_2} {plural_noun_1} and a side of {liquid_1}.
            The chef, a {adjective_3} {person_name_1}, said it was his {adjective_4} creation.
            I felt very {emotion_1} after eating it, and decided to {verb_1} all night.
            """,
            "placeholders": [
                "adjective_1", "food_1", "adjective_2", "plural_noun_1",
                "liquid_1", "adjective_3", "person_name_1", "adjective_4",
                "emotion_1", "verb_1"
            ]
        }
    }

def load_stories():
    """Loads user-defined stories from a JSON file."""
    if os.path.exists(STORIES_FILE):
        try:
            with open(STORIES_FILE, 'r') as f:
                return json.load(f)
        except json.JSONDecodeError:
            print(f"Warning: Could not decode {STORIES_FILE}. Starting with no user stories.")
            return {}
    return {}

def save_stories(stories):
    """Saves user-defined stories to a JSON file."""
    with open(STORIES_FILE, 'w') as f:
        json.dump(stories, f, indent=4)
    print("User stories saved successfully!")

def load_completed_stories():
    """Loads previously completed Mad Libs stories from a JSON file."""
    if os.path.exists(COMPLETED_STORIES_FILE):
        try:
            with open(COMPLETED_STORIES_FILE, 'r') as f:
                return json.load(f)
        except json.JSONDecodeError:
            print(f"Warning: Could not decode {COMPLETED_STORIES_FILE}. Starting with no completed stories.")
            return []
    return []

def save_completed_story(story_text, title, rating, completed_stories):
    """Saves a completed Mad Libs story to a JSON file."""
    completed_stories.append({
        "title": title,
        "story": story_text,
        "rating": rating
    })
    with open(COMPLETED_STORIES_FILE, 'w') as f:
        json.dump(completed_stories, f, indent=4)
    print("Your completed story has been saved!")

def view_completed_stories(completed_stories):
    """Displays all previously completed Mad Libs stories."""
    if not completed_stories:
        print("\nNo completed stories saved yet.")
        return

    print("\n--- Your Saved Stories ---")
    for i, story_data in enumerate(completed_stories):
        print(f"\nStory {i+1}: {story_data['title']}")
        print(f"Rating: {story_data['rating']} stars")
        print(story_data['story'])
    print("--------------------------")

def create_new_story():
    """Guides the user through creating a new Mad Libs story template."""
    print("\n--- Create Your Own Mad Libs Story ---")
    title = input("Enter a title for your new story: ").strip()
    while not title:
        print("Title cannot be empty.")
        title = input("Enter a title for your new story: ").strip()

    print("\nNow, type your story. Use curly braces {} for placeholders.")
    print("Examples: {adjective_1}, {noun_2}, {verb_ing_3}, {person_name_1}")
    print("Type 'END' on a new line when you are finished.")

    template_lines = []
    while True:
        line = input()
        if line.strip().upper() == 'END':
            break
        template_lines.append(line)
    template = "\n".join(template_lines)

    # Extract placeholders from the template
    import re
    placeholders = sorted(list(set(re.findall(r'\{(\w+)\}', template))))

    if not placeholders:
        print("No placeholders found in your story. Please try again.")
        return None, None # Indicate failure

    print("\nPlaceholders identified in your story:")
    for p in placeholders:
        print(f"- {p}")

    confirm = input("Does this look correct? (yes/no): ").strip().lower()
    if confirm != 'yes':
        print("Story creation cancelled.")
        return None, None

    print("New story created successfully!")
    return {"title": title, "template": template, "placeholders": placeholders}

# Helper Functions

def get_word_type_prompt(placeholder):
    """
    Provides a user-friendly prompt and example based on the placeholder name.
    """
    prompt_map = {
        "adjective": "adjective (e.g., 'fluffy', 'brave')",
        "noun": "noun (e.g., 'cat', 'computer')",
        "verb": "verb (e.g., 'run', 'sing')",
        "adverb": "adverb (e.g., 'quickly', 'loudly')",
        "animal": "animal (e.g., 'dog', 'elephant')",
        "food": "type of food (e.g., 'pizza', 'sushi')",
        "liquid": "type of liquid (e.g., 'water', 'soda')",
        "emotion": "emotion (e.g., 'happy', 'confused')",
        "exclamation": "exclamation (e.g., 'Wow!', 'Oh no!')",
        "plural_noun": "plural noun (e.g., 'shoes', 'trees')",
        "person_name": "person's name (e.g., 'Alice', 'Bob')",
        "mythical_creature": "mythical creature (e.g., 'dragon', 'unicorn')",
        "verb_ing": "verb ending in -ing (e.g., 'running', 'sleeping')",
    }
    # Try to find the most specific match
    for key, value in prompt_map.items():
        if key in placeholder:
            return value
    return "word" # Fallback for unknown placeholders

def get_random_word(placeholder):
    """
    Returns a random word based on the placeholder type.
    """
    for word_type in WORD_SUGGESTIONS:
        if word_type in placeholder:
            return random.choice(WORD_SUGGESTIONS[word_type])
    # Fallback if no specific type is matched, pick a random noun
    return random.choice(WORD_SUGGESTIONS["noun"])

def get_user_input(prompt_text, placeholder_type):
    """
    Gets user input, handles 'suggest' command, and validates for emptiness.
    """
    while True:
        user_input = input(prompt_text).strip()
        if user_input.lower() == 'suggest':
            suggested_word = get_random_word(placeholder_type)
            print(f"Suggestion: '{suggested_word}'")
            confirm_suggestion = input("Use this suggestion? (yes/no): ").strip().lower()
            if confirm_suggestion == 'yes':
                return suggested_word
            else:
                print("Please enter your own word.")
        elif not user_input:
            print("Input cannot be empty. Please try again.")
        else:
            return user_input

# Game Logic

def play_mad_libs(story_data, completed_stories):
    """
    Plays a single round of Mad Libs with the given story data.
    """
    print(f"\n--- Playing: {story_data['title']} ---")
    print("Please provide the following words (type 'suggest' for a random word):\n")

    mad_libs_words = {}
    for placeholder in story_data['placeholders']:
        prompt_text = f"Enter a {get_word_type_prompt(placeholder)} for '{placeholder}': "
        user_input = get_user_input(prompt_text, placeholder)
        mad_libs_words[placeholder] = user_input

    completed_story = story_data['template'].format(**mad_libs_words)

    print("\nHere is your completed Mad Libs story:\n")
    print(completed_story)

    # Rating system
    while True:
        try:
            rating = int(input("\nHow would you rate this story? (1-5 stars, 5 being best): ").strip())
            if 1 <= rating <= 5:
                break
            else:
                print("Please enter a number between 1 and 5.")
        except ValueError:
            print("Invalid input. Please enter a number.")

    # Save completed story
    save_completed_story(completed_story, story_data['title'], rating, completed_stories)


def main():
    """
    Main function to run the Mad Libs Generator, allowing multiple plays and features.
    """
    print("Welcome to the Advanced Mad Libs Generator!")

    # Load stories (default + user-defined)
    all_stories = get_default_stories()
    user_stories = load_stories()
    # Merge user stories, ensuring keys don't clash (by appending to existing keys)
    next_key = max([int(k) for k in all_stories.keys()] + [0]) + 1
    for i, (key, story) in enumerate(user_stories.items()):
        all_stories[str(next_key + i)] = story

    completed_stories = load_completed_stories()

    while True:
        print("\n--- Main Menu ---")
        print("1. Play a Mad Libs Story")
        print("2. Create a New Story")
        print("3. View Saved Stories")
        print("4. Quit")

        choice = input("Enter your choice (1-4): ").strip()

        if choice == '1':
            print("\nAvailable Stories:")
            for key, story in all_stories.items():
                print(f"  {key}. {story['title']}")

            story_choice = input("Enter the number of the story you want to play: ").strip()
            if story_choice in all_stories:
                play_mad_libs(all_stories[story_choice], completed_stories)
            else:
                print("Invalid story choice. Please enter a valid number.")

        elif choice == '2':
            new_story_data = create_new_story()
            if new_story_data:
                # Add new story to all_stories and save user_stories
                next_key = max([int(k) for k in all_stories.keys()] + [0]) + 1
                all_stories[str(next_key)] = new_story_data
                user_stories[str(next_key)] = new_story_data # Add to user_stories for saving
                save_stories(user_stories)

        elif choice == '3':
            view_completed_stories(completed_stories)

        elif choice == '4':
            print("Thanks for playing! Goodbye.")
            break
        else:
            print("Invalid choice. Please enter a number between 1 and 4.")

# This ensures that main() is called only when the script is executed directly.
if __name__ == "__main__":
    main()



If you like to see simpler version code view Simple Mad Lib Generator


For more Python project codes go to Python Projects