Created
August 4, 2017 15:15
-
-
Save anonymous/5edb4e06ed7ca2997c0655f380bafbc8 to your computer and use it in GitHub Desktop.
Procedural Pantheon by acidicrhyme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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