Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Mad Libs Program
#1
Hey everyone!

I'm working on my first python project on my own and decided to take on building a Mad Libs Program. I have a directory of possible stories that the program can select from. The program will then ask the user to fill in the blank word, without the user knowing the story. After all words in the story have been completed it will show the completed story and save a copy to the directory.

Im enjoying struggling through this but looking for some tips to push me in the right direction. Currently i'm stuck on replacing the found phrase in the story with the user inputed word.

I'd appreciate any thoughts or comments on my processes as well.
Thanks

import os,random,re
#Change the working directory to the Mad Libs base folder.
os.chdir('/MY DIRECTORY HERE')
#randomly Select a Story to be opened from the File
story = open(random.choice(os.listdir(''/MY DIRECTORY HERE'')))
storyContent = story.read()

#search the story for a key phrase and replace it with a user defined phrase
#The phrase will start with INSERT and finish with END.
storyRegex = re.compile(r'(INSERT)(.....?.?.?.?.?.?)(END)')
mo = storyRegex.search(storyContent)
speechType = mo.group(2)
print('Please enter a ' + speechType)
newWord = input()
storyRegex = re.compile(mo.group(0))
storyRegex.sub(newWord,storyContent)
print(storyContent)

#Create a for loop to find every instance of the phrase starting with INSERT
# Print out the story
#Save story to a new directory
Reply
#2
It's hard to help, the way you've structured this question. We'd need to know what your story files look like, primarily. So I'll explain how I would do it, though I would have preferred to be guided by your choices...

If it were me, my story files would probably be JSON. Probably something like this:
{
    "substitutions": [
        {
            "key": "adjective1",
            "type": "adjective"
        },
        {
            "key": "plural_noun1",
            "type": "plural_noun"
        }
    ],
    "story": "I felt {adjective1} while hunting {plural_noun1}"
}
And here's what I'd get started with in terms of using this JSON
import json

# you'd use json.load with a file instead of hard-coding it like I am here, for simplicity
madlib = json.loads('''
{
    "substitutions": [
        {
            "key": "adjective1",
            "type": "adjective"
        },
        {
            "key": "plural_noun1",
            "type": "plural_noun"
        }
    ],
    "story": "I felt {adjective1} while hunting {plural_noun1}"
}
''')

substitutions_to_do = {}
for substitution in madlib["substitutions"]:    
    choice = input("Please provide a {}: ".format(substitution["type"]))
    substitutions_to_do[substitution["key"]] = choice

print(madlib["story"].format(**substitutions_to_do))
and here you can see it in action
Output:
$ python3 doit.py Please provide a adjective: helpless Please provide a plural_noun: children I felt helpless while hunting children
Reply
#3
A lot of this depends on how you structure the story files and how you signal you need a word (and what type). One method, since you control the story text, would be to have a key character that identifies that a word is needed, followed by the type of word. You can then pick up that word type and ask verbatim for that to be entered, after which you substitute that word in the string. For example, you could use the pipe as your signal character. A sentence in the story could be "I thought I saw a |noun , but it turned out to be a |adjective |noun ." Your program would look for pipes (|), take the next word and use it as the prompt, then substitute the entry for the pipe and word. All types of words would then be treated the same.

Just a thought.
Reply
#4
I suggest not bothering with pipes or regular expressions if you can just use the format method, unless there's something you'd gain with the added complexity.
Reply
#5
The only issue i see using the json is the ability to have a variety of different stories each with a different number of descriptors. One with 3 Nouns and another with 9 nouns. I will be adding an ability to write and save stories with the user to be able to put it whatever descriptor they would like.

Here is an example of a story I have been using.

In my junior year of high school, this guy asked me on a date. He rented a INSERTNOUNEND and made a INSERTADJECTIVEEND pizza. We were watching the INSERTADJECTIVEEND movie and the oven VERB so the pizza was done. He looked me dead in the INSERTBODY PARTEND and said, “This is the worst part.” I then watched this boy open the oven and pull the pizza out with his INSERTBODY PARTEND, rack and all, screaming at the top of his lungs. We never had a second date.

My thought was similar to Jefsummers where i would be able to create a for loop and have the program scroll through looking for any word that starts with INSERT. I found I also needed a end phrase because not all descriptors will be one word. Like the example of BODY PART.
Reply
#6
Using open and closing braces or brackets could work to denote beginning and end of the prompt, allowing multiword prompts. Your INSERT and END works too.
Loop the text and when you find the prompt marker, prompt the user from the text, and substitute it. You can then display the text at the end and offer to save. You can use regex but I don't think it necessary.
Reply
#7
(Nov-15-2019, 04:20 AM)theguywithcurls Wrote: The only issue i see using the json is the ability to have a variety of different stories each with a different number of descriptors.
Could you elaborate on this being an issue? It should be as simple as adding to the list in my example, and then referencing whatever key name you chose in the story template. My JSON is one story, so one with 9 substitutions would have a longer list and each of the keys in the list would appear in the story.

(Nov-15-2019, 04:20 AM)theguywithcurls Wrote: My thought was similar to Jefsummers where i would be able to create a for loop and have the program scroll through looking for any word that starts with INSERT. I found I also needed a end phrase because not all descriptors will be one word. Like the example of BODY PART.
I believe you'd be better off with Python's string format method, than writing a loop. I'll reiterate what I said before, stick to format unless your use case becomes too complex for it (which I'd say is unlikely in this case).

You may want to add a "descriptor" key to your JSON, what I gave as an example was as basic as I could come up with. Multi-word descriptors shouldn't be a problem.

(Nov-15-2019, 12:37 PM)jefsummers Wrote: Using open and closing braces or brackets could work to denote beginning and end of the prompt, allowing multiword prompts. Your INSERT and END works too. Loop the text and when you find the prompt marker, prompt the user from the text, and substitute it. You can then display the text at the end and offer to save. You can use regex but I don't think it necessary.
The brackets are for the format method, again, there's no need to loop through the string or do manual substitutions, and INSERT and END are probably unnecessary. I agree that regex is likely unnecessary here.
Reply
#8
I changed my characters to curly brackets instead of the words I previously used:

In my junior year of high school, this girl asked me on a date. She rented a {NOUN} and made a {ADJECTIVE} pizza. We were watching the {ADJECTIVE} movie and the oven {VERB} so the pizza was done. She looked me dead in the {BODY PART} and said, “This is the worst part.” I then watched this girl open the oven and pull the pizza out with his {BODY PART}, rack and all, screaming at the top of his lungs. We never had a second date.

I'm stuck in creating a loop for my code to loop through and replace the text when the prompt marker is found. I feel I need one more loop to properly replace what I have found. The current code doesn't work because as soon as I modify the story, the values I had stored in the dictionaries in the beginning of the code are no longer valid due to the subtraction/addition of characters.

What kind/where would would i put the needed loop?

import os,random,re
#Change the working directory to the Mad Libs base folder.
os.chdir('/Mad Libs/Story')
#randomly Select a Story to be opened from the File
story = open(random.choice(os.listdir('/Mad Libs/Story')))
storyContent = story.read()
n=0
q=0
count=0
startList = {}
endList={}
#Create a dictionary to find the starting and ending values of phrases that need to be replaced
#The phrase will start with { and finish with }.
for m in re.finditer('{',storyContent): #find all "{" characters in story and store their index number
    startList[n] = m.end()
    n=n+1
for l in re.finditer('}',storyContent): #find all "{" characters in story and store their index number
    endList[q] = l.start()
    q=q+1
for b in startList: # Take a user entry for the phrase and replace it in the story
    userEntry = input("Please enter a " + storyContent[startList[b]:endList[b]] + ':')
    storyContent1 = storyContent[0:startList[b]-1]
    storyContent2 = storyContent[endList[b]+1:]
    storyContent = storyContent1 + userEntry + storyContent2

print(storyContent)
Reply
#9
(Nov-15-2019, 11:43 PM)theguywithcurls Wrote: I'm stuck in creating a loop for my code to loop through and replace the text when the prompt marker is found.
Why not just use replace, as I demo'd above? It looks to me like you're way overcomplicating this.
Reply
#10
I've updated my code here using the substitution/json method.

import json, os,random
#Change the working directory to the Mad Libs base folder.
os.chdir('/mydirectory')
#randomly Select a Story to be opened from the File
story = open(random.choice(os.listdir('/mydirectory')))
storyContent = story.read()
#Load in the substitutions found in the story
madlib = json.loads('''
{
    "substitutions": [
        {
            "key": "NOUN1",
            "type": "Noun"
        },
        {
            "key": "ADJECTIVE1",
            "type": "Adjective"
        },
        {
            "key": "ADJECTIVE2",
            "type": "Adjective"
        },
        {
            "key": "VERB1",
            "type": "Verb"
        },
        {
            "key": "BODY PART1",
            "type": "Body Part"
        },
        {
            "key": "BODY PART2",
            "type": "Body Part"
        }
    ]
}
''')
substitutions_to_do = {}
for substitution in madlib["substitutions"]:
    choice = input("Please provide a {}: ".format(substitution["type"]))
    substitutions_to_do[substitution["key"]] = choice
print(storyContent.format(**substitutions_to_do))
This does work for this story. Where it doesn't work is if I have a completely different story with different phrases/parts of speech required. I would like to program to step through a story and find all the keys and types, without me having to hard code it in. That will allow for new keys to be added in new stories. Is it possible to do this with json?
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Running 3rd party libs on Steam Deck (Arch Linux) with restricted access metulburr 0 1,872 Jan-07-2023, 10:41 PM
Last Post: metulburr
  How can I use CRC libs in python? blodht 0 1,664 Feb-03-2020, 10:26 PM
Last Post: blodht
  using py32, just need py64 LIBS for now, how to install? davecotter 1 2,295 Jan-29-2019, 10:40 PM
Last Post: davecotter
  [split] adding 3rd party libs Blue Dog 7 6,846 Oct-22-2016, 12:03 PM
Last Post: Blue Dog

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020