Skip to content

Instantly share code, notes, and snippets.

/pantheon.py
Created Aug 4, 2017

Embed
What would you like to do?
Procedural Pantheon by acidicrhyme
# WordNet/Jung Pantheon Generator copyright 2017 Adam Biltcliffe
# Released under the terms of the MIT License - https://opensource.org/licenses/MIT
from nltk.corpus import wordnet as wn
import textblob as tb
import random
import graphviz
# convenience methods for identifying seed synsets
def s(word):
for synset in wn.synsets(word):
print(synset.name(), synset.definition())
# hand-selected seed words based on Jungian archetypes
archetypes = [
# innocent
['happiness.n.01',
'happiness.n.02',
'mystic.n.01',
'idealist.n.01',
'romantic.n.01',
'faith.n.04',
'optimism.n.02'],
# everyman
['orphan.n.01',
'child.n.02',
'connection.n.02',
'belonging.n.01',
'empathy.n.01',
'realism.n.01',
'employment.n.02',
'citizen.n.01'],
# hero
['hero.n.01',
'hero.n.05',
'fight.n.02',
'champion.n.02',
'courage.n.01',
'command.n.06',
'strength.n.01',
'force.n.03',
'courage.n.01',
'warrior.n.01',
'soldier.n.01',
'competence.n.01',
'arrogance.n.01',
'victory.n.01'],
# caregiver
['defender.n.01',
'assistant.n.01',
'caregiver.n.02',
'martyr.n.01',
'compassion.n.01',
'compassion.n.02',
'generosity.n.01',
'philanthropist.n.01',
'support.n.03',
'altruism.n.01'],
# explorer
['explorer.n.01',
'freedom.n.01',
'fulfillment.n.01',
'experience.n.02',
'travel.n.01',
'journey.n.01',
'wanderlust.n.01',
'seeker.n.01',
'autonomy.n.02',
'pilgrim.n.01',
'individualist.n.01'],
# rebel
['insurgent.n.01',
'maverick.n.01',
'revolution.n.01',
'revolution.n.02',
'disturbance.n.03',
'disruption.n.04',
'radical.n.03',
'freedom.n.01',
'criminal.n.01',
'misfit.n.01',
'retaliation.n.01',
'shock.n.02',
'shock.n.06'],
#lover
['lover.n.01',
'love_affair.n.01',
'love_story.n.01',
'romanticism.n.03',
'closeness.n.01',
'familiarity.n.03',
'affair.n.02',
'attraction.n.03',
'attraction.n.04',
'attractiveness.n.02',
'passion.n.01',
'heat.n.04',
'passion.n.05',
'love.n.02',
'commitment.n.02',
'spouse.n.01',
'enthusiasm.n.01'],
#creator
['creator.n.02',
'artist.n.01',
'imagination.n.01',
'vision.n.01',
'value.n.02',
'skill.n.01',
'culture.n.02',
'polish.n.02',
'perfection.n.01',
'perfection.n.03',
'paragon.n.01',
'musician.n.01',
'musician.n.02',
'inventor.n.01'],
# jester
['jester.n.01',
'enjoyment.n.01',
'play.n.08',
'fun.n.02',
'play.n.14',
'gambling.n.01',
'wit.n.01',
'humor.n.04',
'joy.n.01',
'jest.n.02',
'antic.n.01',
'trick.n.01',
'trick.n.03'],
# sage
['sage.n.01',
'truth.n.01',
'truth.n.03',
'accuracy.n.01',
'intelligence.n.01',
'analysis.n.01',
'wisdom.n.01',
'detective.n.02',
'scholar.n.01',
'expert.n.01',
'philosopher.n.01',
'philosopher.n.02',
'teacher.n.01',
'teacher.n.02',
'mentor.n.01'],
# magician
['sorcerer.n.01',
'reason.n.03',
'vision.n.05',
'shaman.n.01',
'therapist.n.01',
'visionary.n.02',
'prophet.n.01',
'magic.n.01',
'spirit.n.04',
'catalyst.n.02',
'change.n.01'],
# ruler
['power.n.01',
'ability.n.02',
'power.n.05',
'might.n.01',
'ruler.n.01',
'influence.n.01',
'dominion.n.01',
'leadership.n.03',
'leadership.n.04',
'control.n.01',
'sovereign.n.01',
'politician.n.01']
]
# also add a few extras in so that the structure of the pantheon is
# less repetitive
extra_concepts = ['animal.n.01', 'birth.n.02', 'death.n.01', 'ocean.n.01',
'plant.n.02', 'weather.n.01']
# This list is very hard to get right and almost certainly imperfect
to_pluralise = [wn.synset('physical_entity.n.01'),
#wn.synset('occupation.n.01'),
wn.synset('event.n.01'),
wn.synset('cognitive_factor.n.01'),
wn.synset('literary_composition.n.01'),
wn.synset('imaginary_being.n.01'),
wn.synset('happening.n.01')]
def should_pluralise(thing):
return any(c in c.lowest_common_hypernyms(thing) for c in to_pluralise)
def choose_domains(m, d, focus):
if len(m) == 0:
n = min(random.choice([1, 1, 1, 1, 2, 2, 3]), len(d))
return random.sample(d, n)
hypos = m[0].hyponyms()
if len(hypos) == 0 or random.random() < focus:
return choose_domains(m[1:], d+[m[0]], focus)
else:
return choose_domains(m[1:], d+hypos, focus)
def name_domain(d):
lemma = ' '.join([word.capitalize() for word in random.choice(d.lemma_names()).split('_')])
if should_pluralise(d):
return tb.Word(lemma).pluralize()
else:
return lemma
def domain_importance(d):
return max(len(p) for p in d.hypernym_paths())
titles = ['God', 'Goddess', 'Deity', 'Demigod']
# this brief experiment generated "The Goddess of Attraction appears in the form of a window washer."
#forms = list(wn.synset('organism.n.01').closure(lambda s: s.hyponyms()))
class Deity(object):
def __init__(self, domains):
domains = sorted(domains, key=domain_importance)
self.domains = domains
if len(domains) == 1:
domain_name_string = name_domain(domains[0])
else:
domain_names = [name_domain(d) for d in domains]
domain_name_string = ', '.join(domain_names[:-1]) + " and " + domain_names[-1]
self.title = random.choice(titles)
self.style = "{0} of {1}".format(self.title, domain_name_string)
self.rank = sum(domain_importance(d) for d in domains) / len(domains)
#self.form = max(random.sample(forms, 250), key=lambda f: self.affinity(f))
#print("The {0} appears in the form of a {1}".format(self.style, self.form))
self.children = []
def affinity(self, other):
if isinstance(other, Deity):
return min(a.path_similarity(b) for a in self.domains for b in other.domains)
else: #if isinstance(other, nltk.corpus.reader.wordnet.Synset):
return min(a.path_similarity(other) for a in self.domains)
deities = []
for a in archetypes:
q = [wn.synset(c) for c in a]
domains = choose_domains(q, [], 0.9)
deities.append(Deity(domains))
extra = random.sample(extra_concepts, random.randrange(4))
for q in [[wn.synset(c)] for c in extra]:
domains = choose_domains(q, [], 0.3)
deities.append(Deity(domains))
#deities.sort(key=lambda d: d.affinity(wn.synset('leadership.n.04')))
deities.sort(key=lambda d: d.rank)
root = deities.pop(0)
root.nodename = "R"
pantheon = [root]
n=1
while len(deities) > 0:
d = deities.pop(0)
d.nodename = "D{0}".format(n)
n += 1
parent = max(pantheon, key=d.affinity)
parent.children.append(d)
pantheon.append(d)
dot = graphviz.Digraph(comment="The Pantheon")
def visit(deity, indent=0):
dot.node(deity.nodename, deity.style)
#print(" " * indent + deity.style)
for c in deity.children:
visit(c, indent+1)
dot.edge(deity.nodename, c.nodename)
visit(root)
print(dot.source)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.