4
\$\begingroup\$

I was doing a simple mad libs game thing but I want to know if there's any more efficient or readable way to write the code as I don't know the best ways to structure code as I am just begginning. Before I write any more of them please can someone tell me if there's a "better" or more accpeted way to write any of the code like if I should make more things in to functions and how to do so. This is Python 3.6.6. The game is supposed to prompt the user to enter a random word of their choice (it has to be a certain type of word to make sense in the sentence like adjective or verb) and inputs the prompted words into a sentence so it's funny and doesn't make any sense

import random

print("<<<<<<<<<<<<<<<<<<<<<<<<< Mad Libs >>>>>>>>>>>>>>>>>>>>>>>>>")
adjective = []
noun = []
verb_pr = []
noun_p = []
verb_pa = []
verb = []
def nouns():
    global noun
    ans = input("Noun(singular):\n> ").lower()
    noun.append(ans)

def nouns_p():
    global noun_p
    ans = input("Noun(plural):\n> ").lower()
    noun_p.append(ans)

def adjectives():
    global adjective
    ans = input("Adjective:\n> ").lower()
    adjective.append(ans)

def verbs_pr():
    global verb_pr
    ans = input("Verb(-ing):\n> ").lower()
    verb_pr.append(ans)

def verbs_pa():
    global verb_pa
    ans = input("Verb(-ed):\n> ").lower()
    verb_pa.append(ans)

def verbs():
    global verb
    ans = input("Verb:\n> ").lower()
    verb.append(ans)



verbs_pr()
nouns_p()
nouns()
nouns()
verbs_pr()
nouns_p()
verbs_pa()
verbs()
nouns_p()
adjectives()
verbs_pr()
nouns_p()
verbs_pr()

random.shuffle(adjective)
random.shuffle(noun)
random.shuffle(verb_pr)
random.shuffle(noun_p)
random.shuffle(verb_pa)
random.shuffle(verb)

print("{3[0]} these {2[0]}, {1[0]} like a {1[1]}, I'm {3[1]} {2[1]} now, someone {4[0]} me do I {5[0]} {2[2]}, it's gonna be {0[0]}, {3[2]} {2[3]} that's what I'm {3[3]} about yeah".format(adjective,noun,noun_p,verb_pr,verb_pa,verb))

adjective = []
noun = []
verb_pr = []
noun_p = []
verb_pa = []
verb = []
verbs_pa()
nouns()
adjectives()
adjectives()
verbs_pr()
nouns()
verbs()
nouns_p()
verbs_pa()
nouns()
nouns()
nouns()
nouns()
adjectives()
nouns_p()
verbs()
nouns()
nouns()
adjectives()
nouns_p()
nouns()
nouns()
nouns()
verbs()

random.shuffle(adjective)
random.shuffle(noun)
random.shuffle(verb_pr)
random.shuffle(noun_p)
random.shuffle(verb_pa)
random.shuffle(verb)
print("""You have been {4[0]} into Hogwarts {1[0]} of {0[0]} and {0[1]}. You will be {2[0]} throughout the {1[1]} and will {5[0]} in the {3[0]}. You will be {4[1]} in one of the four houses.
{1[2]}, {1[3]}, {1[4]} or {1[5]} and will learn much about the {0[2]} {3[1]}. Once you arrive you will {5[1]} The Great {1[6]} for a feast with the headmaster, Proffessor
{1[7]}. You will need to get all the {0[3]} {3[2]} in {1[8]} Alley and get a {1[9]} from Ollivanders {1[10]} shop. We hope to {5[2]} you there.""".format(adjective,noun,verb_pr,noun_p,verb_pa,verb))
\$\endgroup\$
3
\$\begingroup\$

That works, but obviously, the code is repetitive, and a lot of work to maintain. To prepare each Mad Lib, you have to count the number of each type of blank, to make the required number of prompts. Then, you fill in the blanks using str.format(…) with some rather cryptic placeholders in the format string.

A smarter approach would be to have the computer do most of that work for you, so that you only need to supply a template in some human-friendly format, and the code figures out the necessary prompts. That would necessitate a complete rewrite of the code.

Furthermore, you should avoid making separate lists for each part of speech, because that forces you to write separate code to handle each part of speech. Rather, you should store the words in a dictionary, with the parts of speech as keys, and list of words as values. (More specifically, you can use a defaultdict to ensure that each key is initially associated to an empty list.) Storing the data in a dictionary would also help you avoid the nasty use of global variables.

Suggested solution

This solution uses regular expressions to analyze the template and perform the word substitutions.

from collections import defaultdict
import random
import re

def mad_lib(template):
    blanks = re.findall(r'\{(.*?)\}', template)
    random.shuffle(blanks)
    words = defaultdict(list)
    for part_of_speech in blanks:
        words[part_of_speech].append(input(part_of_speech + ":\n> "))
    for answers in words.values():
        random.shuffle(answers)
    return re.sub(
        r'\{(.*?)\}',
        lambda match: words[match.group(1)].pop(),
        template
    )


print("<<<<<<<<<<<<<<<<<<<<<<<<< Mad Libs >>>>>>>>>>>>>>>>>>>>>>>>>")

print(mad_lib(
    "{Verb(-ing)} these {Noun(plural)}, {Noun} like a {Noun}, I'm {Verb(-ing)} {Noun(plural)} now, someone {Verb(-ed)} me do I {Verb} {Noun(plural)}, it's gonna be {Adjective}, {Verb(-ing)} {Noun(plural)} that's what I'm {Verb(-ing)} about yeah"
))

print(mad_lib(
    """You have been {Verb(-ed)} into Hogwarts {Noun(singular)} of {Adjective} and {Adjective}. You will be {Verb(-ing)} throughout the {Noun(singular)} and will {Verb} in the {Noun(plural)}. You will be {Verb(-ed)} in one of the four houses.
{Noun(singular)}, {Noun(singular)}, {Noun(singular)} or {Noun(singular)} and will learn much about the {Adjective} {Noun(plural)}. Once you arrive you will {Verb} The Great {Noun(singular)} for a feast with the headmaster, Proffessor
{Noun(singular)}. You will need to get all the {Adjective} {Noun(plural)} in {Noun(singular)} Alley and get a {Noun(singular)} from Ollivanders {Noun(singular)} shop. We hope to {Verb} you there."""
))
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.