Implementations of early and well-known poetry generators

By Allison Parrish

This notebook has some Python implementations of a number of early and well-known poetry generators, including Knowles and Tenney's A House of Dust, Strachey's love letter generator and Nick Montfort's Taroko Gorge.

To Make a Dadaist Poem

Original written by Tristan Tzara in 1920.

In [1]:
import random
import textwrap

newspaper = """
Dada was an informal international movement, with 
participants in Europe and North America. The 
beginnings of Dada correspond to the outbreak of 
World War I. For many participants, the movement 
was a protest against the bourgeois nationalist 
and colonialist interests, which many Dadaists 
believed were the root cause of the war, and 
against the cultural and intellectual 
conformity — in art and more broadly in 
society — that corresponded to the war."""

words = newspaper.split()
random.shuffle(words)

print(textwrap.fill(" ".join(words), 60))
more Dadaists participants, international World movement
conformity corresponded participants beginnings The broadly
war, with informal Europe an Dada North war. to For cause of
War the of — cultural the movement, root the were was the
many to and of in art the the outbreak America. a in against
nationalist in against correspond and I. interests, — the
believed and many was intellectual protest that society
colonialist which and and Dada bourgeois

A House of Dust

Original written in Fortran in 1967 by Alison Knowles and James Tenney. ELMCIP entry. More information. Watch Alison Knowles read from this piece.

In [2]:
import random
In [3]:
materials = [
    'brick',
    'broken dishes',
    'discarded clothing',
    'dust',
    'glass',
    'leaves',
    'mud',
    'paper',
    'plastic',
    'roots',
    'sand',
    'steel',
    'stone',
    'straw',
    'tin',
    'weeds',
    'wood'
]
In [4]:
locations = [
    'among high mountains',
    'among other houses',
    'among small hills',
    'by a river',
    'by an abandoned lake',
    'by the sea',
    'in a cold, windy climate',
    'in a deserted airport',
    'in a deserted church',
    'in a deserted factory',
    'in a green, mossy terrain',
    'in a hot climate',
    'in a metropolis',
    'in a place with both heavy rain and bright sun',
    'in an overpopulated area',
    'in dense woods',
    'in heavy jungle undergrowth',
    'in japan',
    'in michigan',
    'in southern france',
    'inside a mountain',
    'on an island',
    'on the sea',
    'underwater'
]
In [5]:
lights = [
    'all available lighting',
    'candles',
    'electricity',
    'natural light'
]
In [6]:
inhabitants = [
    'all races of men represented wearing predominantly red clothing',
    'children and old people',
    'collectors of all types',
    'fishermen and families',
    'french and german speaking people',
    'friends',
    'friends and enemies',
    'horses and birds',
    'little boys',
    'lovers',
    'people from many walks of life',
    'people speaking many languages wearing little or no clothing',
    'people who eat a great deal',
    'people who enjoy eating together',
    'people who love to read',
    'people who sleep almost all the time',
    'people who sleep very little',
    'various birds and fish',
    'vegetarians',
    'very tall people'
]
In [7]:
stanza_count = 7
for i in range(stanza_count):
    print()
    print("A house of " + random.choice(materials))
    print("     " + random.choice(locations))
    print("          using " + random.choice(lights))
    print("                inhabited by " + random.choice(inhabitants))
A house of weeds
     in michigan
          using candles
                inhabited by people who enjoy eating together

A house of brick
     among small hills
          using natural light
                inhabited by friends and enemies

A house of straw
     in japan
          using natural light
                inhabited by collectors of all types

A house of roots
     on the sea
          using electricity
                inhabited by people who sleep very little

A house of mud
     in a green, mossy terrain
          using all available lighting
                inhabited by various birds and fish

A house of tin
     in a place with both heavy rain and bright sun
          using candles
                inhabited by people who love to read

A house of steel
     in a deserted airport
          using electricity
                inhabited by little boys

Love Letter Generator

Original by Christopher Strachey, written for the Manchester Mark I in 1952. Read more here.

Vocabulary based on this implementation.

In [8]:
sal_adjs = [
    "Beloved",
    "Darling",
    "Dear",
    "Dearest",
    "Fanciful",
    "Honey"]
In [9]:
sal_nouns = [
    "Chickpea",
    "Dear",
    "Duck",
    "Jewel",
    "Love",
    "Moppet",
    "Sweetheart"
]
In [10]:
adjs = [
    'affectionate',
    'amorous',
    'anxious',
    'avid',
    'beautiful',
    'breathless',
    'burning',
    'covetous',
    'craving',
    'curious',
    'eager',
    'fervent',
    'fondest',
    'loveable',
    'lovesick',
    'loving',
    'passionate',
    'precious',
    'seductive',
    'sweet',
    'sympathetic',
    'tender',
    'unsatisfied',
    'winning',
    'wistful'
]
In [11]:
nouns = [
    'adoration',
    'affection',
    'ambition',
    'appetite',
    'ardour',
    'being',
    'burning',
    'charm',
    'craving',
    'desire',
    'devotion',
    'eagerness',
    'enchantment',
    'enthusiasm',
    'fancy',
    'fellow feeling',
    'fervour',
    'fondness',
    'heart',
    'hunger',
    'infatuation',
    'little liking',
    'longing',
    'love',
    'lust',
    'passion',
    'rapture',
    'sympathy',
    'thirst',
    'wish',
    'yearning'
]
In [12]:
advs = [
    'affectionately',
    'ardently',
    'anxiously',
    'beautifully',
    'burningly',
    'covetously',
    'curiously',
    'eagerly',
    'fervently',
    'fondly',
    'impatiently',
    'keenly',
    'lovingly',
    'passionately',
    'seductively',
    'tenderly',
    'wistfully'
]
In [13]:
verbs = [
    'adores',
    'attracts',
    'clings to',
    'holds dear',
    'hopes for',
    'hungers for',
    'likes',
    'longs for',
    'loves',
    'lusts after',
    'pants for',
    'pines for',
    'sighs for',
    'tempts',
    'thirsts for',
    'treasures',
    'yearns for',
    'woos'
]
In [14]:
# textwrap library used to "wrap" the text at a particular length
import textwrap

# output begins with salutation
output = random.choice(sal_adjs) + " " + random.choice(sal_nouns) + ",\n"
output += "\n"

# inside this loop, build the phrases. strachey implemented "short" phrases
# and "long" phrases; two or more "short" phrases in a row have special
# formatting rules, so we need to know what the last phrase kind was in
# order to generate the output.
history = []
body = ""
for i in range(5):
    kind = random.choice(["short", "long"])
    if kind == "long":
        # adjectives and adverbs will be present only 50% of the time
        line = " ".join([
            "My",
            random.choice([random.choice(adjs), ""]),
            random.choice(nouns),
            random.choice([random.choice(advs), ""]),
            random.choice(verbs),
            "your",
            random.choice([random.choice(adjs), ""]),
            random.choice(nouns)])
        body += line
    else:
        adj_noun = random.choice(adjs) + " " + random.choice(nouns)
        # if the last phrase was "short," use truncated form
        if len(history) > 0 and history[-1] == "short":
            body += ": my " + adj_noun
        else:
            body += "You are my " + adj_noun
    body += ". "
    history.append(kind)
# clean up output
body = body.replace("  ", " ")
body = body.replace(". :", ":")
# put everything together
output += textwrap.fill(body, 60)
output += "\n\nYours " + random.choice(advs) + ",\n"
output += "M.U.C."
print(output)
Dearest Love,

You are my lovesick fellow feeling. My ardour tempts your
sympathetic affection. My lust fervently hungers for your
unsatisfied desire. My fondness anxiously lusts after your
fellow feeling. You are my precious yearning.

Yours beautifully,
M.U.C.
In [15]:
above = ['brow', 'mist', 'shape', 'layer', 'the crag', 'stone', 'forest', 'height']
below = ['flow', 'basin', 'shape', 'vein', 'rippling', 'stone', 'cove', 'rock']
transitive = ['command', 'pace', 'roam', 'trail', 'frame', 'sweep', 'exercise', 'range']
imperative = ['track', 'shade', 'translate', 'stamp', 'progress through', 'direct', 'run', 'enter']
intransitive = ['linger', 'dwell', 'rest', 'relax', 'hold', 'dream', 'hum']
texture = ['rough', 'fine']
adjectives = ['encompassing', 'sinuous', 'straight', 'objective', 'arched', 'cool', 'clear', 'dim', 'driven']
In [16]:
def path():
    plural = random.sample(["s", ""], k=2)
    words = random.choice(above)
    if words == "forest" and random.randrange(4) == 0:
        words = "monkeys" + " " + random.choice(transitive)
    else:
        words += plural[0] + " " + random.choice(transitive) + plural[1]
    words += " the " + random.choice(below) + random.choice(["s", ""]) + "."
    return words.capitalize()
In [17]:
def cave():
    adjs = adjectives[:] + random.sample(texture, 1)
    return "  " + random.choice(imperative) + " " + \
        " ".join(random.sample(adjs, random.randrange(1, 4))) + " —"
In [18]:
def site():
    if random.randrange(2) == 0:
        words = random.choice(above)
    else:
        words = random.choice(below)
    words += "s " + random.choice(intransitive) + "."
    return words.capitalize()
In [19]:
stanza_count = 10
for repeat in range(stanza_count):
    line_count = random.randrange(3, 6)
    for i in range(line_count):
        if i == 0:
            print(path())
        elif i == line_count - 2:
            print(path())
        elif i == line_count - 1:
            print()
            print(cave())
            print()
        else:
            print(site())
Layer frames the ripplings.
Stones relax.
Mist trails the rocks.

  translate rough —

Heights roam the rocks.
Stones dream.
Stones dream.
Shape frames the coves.

  progress through sinuous fine dim —

Brows trail the shapes.
Stone trails the flow.

  run encompassing —

Stones command the stones.
Brow sweeps the stone.

  progress through sinuous cool dim —

Mists command the coves.
Veins hum.
Shapes dream.
Shapes pace the vein.

  stamp driven objective encompassing —

Forests range the cove.
Flows rest.
Forests hold.
Mists frame the veins.

  enter driven —

Height paces the flow.
Ripplings dwell.
Brow commands the stones.

  enter fine —

Brows roam the flow.
Basins hum.
Shape frames the veins.

  progress through clear —

The crag exercises the flow.
Forests rest.
Layer frames the flows.

  translate encompassing objective sinuous —

Heights sweep the coves.
Shapes trail the stones.

  stamp driven —