Learning Python in 2020 – Beginner – Basic MadLibs Generator

Problem

Goal

Read a sentence from the command line, ask for the locations of blanks and generate the phrases. Display the user’s result and compare with original sentence.

Pseudo-code

  • Read sentence from command line
  • Ask for location of blanks and their associated categories or description (“e.g “noun”, “verb”, “place”, “celebrity,” “Exclamation” or “part of the body” )
  • Create dictionary ( relationship between blank and description )
  • Split sentences by blank locations
  • Generate sub sentences with blanks
  • Loop through blanked sentences and request answer until user presses Enter
  • Display entire sentence with fills
  • Display original sentence under

Sample sentence

Fortunately it was early, and we went along back streets, so few people saw us, and no one laughed at the funny party. ref

Solution

Required packages/modules

I will use the os.system method to call the clear function of my command line ( cls), while the re package will be used for the string replacements.

import re 
import os

Assemble descriptions of blanks

This function collects descriptions from the user for each word substituted with a blank in the story. If the user types nothing and presses enter, the description field is empty. The description value will be displayed close to the corresponding blank to help the player guess.

def generateDescriptionDictionary(positions):
    position_description_association = {}
    for word in positions:
        description = input("Describe this word : {} --- ".format(word))
        if len(description) == 0:
            print("Please provide description for word")
            description = ""
        position_description_association[word] = description
    return position_description_association

Generate each blanked phrases

After assembling the descriptions, the story/sentence is split, since the context should be hidden from the players. I used regular expressions to split only one occurrence of the word. This avoids the problem of multiple splits.

def splitSentencesByPositions(sentence, words):
    newsentence = sentence
    splitted = sentence
    subs = {}
    for word in words:
        newsentence = re.sub(word, delimiter,newsentence,1)
        splittedtex = re.sub(word, delimiter,splitted,1)
        splittedArr = splittedtex.split(delimiter)
        first = splittedArr[0]
        splitted = splittedArr[1]
        subs[word] = first
    return { "subLibs":subs,"blankedSentence":newsentence }

Display madlibs and ask for possible substitute

The fragment phrases are looped over and displayed to the player. The player types in a substitute word with help of the description. Once complete, the program displays the entire blanked sentence, the user’s solution and original sentence.

def displayAndRequestAnswer(subLibs, blankedSentence, originalSentence, descriptions):
    print("Begin: ")
    keyToAnswer = {}
    for key in subLibs:
        print(subLibs[key] + delimiter + "  ({}) ".format(descriptions[key]))
        answer = input("Type in your solution: ")
        if len(answer) == 0:
            answer = ""
        answer = subLibs[key] + answer
        keyToAnswer[key] = answer
        os.system("cls")
    filledSentence = blankedSentence
    for newKey in keyToAnswer:
        answer = keyToAnswer[newKey]
        match = subLibs[newKey]
        filledSentence = re.sub(match + delimiter, answer,filledSentence,1)

    print(blankedSentence)
    print("-"*100)
    print("Your solution:")
    print()
    print(filledSentence)
    print("-"*100)
    print("The Original sentence: ")
    print()
    print(originalSentence)
    print("-"*100)
    print("Bye....")

Trigger Action

delimiter = "_________"
def main():
    fallbackstory = "Fortunately it was early, and we went along back streets, so few people saw us, and no one laughed at the funny party"
    story = input("Please type in a story:  ")
    locationsAsString = input("Type in words to be blanked seperated by comma: ")
    fallbackLocationsAsString = "early,streets,us"
    if len(story) <= 1:
        print("Story is not long enough")
        story = fallbackstory
    locationsAsString = locationsAsString.strip()
    if len(locationsAsString) == 0:
        locationsAsString = fallbackLocationsAsString
    temppositions = locationsAsString.split(",")
    positions = []
    for t in temppositions:
        t = t.strip()
        if len(t) > 0:
            positions.append(t)
    if len(positions) == 0:
        print("Please provide positions of blanks")
    position_description_association = generateDescriptionDictionary(positions)
    splitted = splitSentencesByPositions(story, positions)
    displayAndRequestAnswer(splitted["subLibs"], splitted["blankedSentence"], story, position_description_association)
def generateDescriptionDictionary(positions):
    position_description_association = {}
    for word in positions:
        description = input("Describe this word : {} --- ".format(word))
        if len(description) == 0:
            print("Please provide description for word")
            description = ""
        position_description_association[word] = description
    return position_description_association




if __name__ == "__main__":
    main()

Run Program

Microsoft Windows [Version 10...]
(c) 2020 Microsoft Corporation. Alle Rechte vorbehalten.

Fortunately it was _________, and we went along back _________, so few people saw _________, and no one laughed at the funny party
----------------------------------------------------------------------------------------------------
Your solution:

Fortunately it was used, and we went along back home, so few people saw us, and no one laughed at the funny party
----------------------------------------------------------------------------------------------------
The Original sentence:

Fortunately it was early, and we went along back streets, so few people saw us, and no one laughed at the funny party
----------------------------------------------------------------------------------------------------
Bye....

Author’s Notes

This is most likely not the cleanest implementation, just a heads up.