Skip to content

Instantly share code, notes, and snippets.

@stickytruth
Created August 27, 2014 17:33
Show Gist options
  • Save stickytruth/42b83a6f5233f50fdfa3 to your computer and use it in GitHub Desktop.
Save stickytruth/42b83a6f5233f50fdfa3 to your computer and use it in GitHub Desktop.
import argparse
import random
import json
GENDER = ['female', 'male']
JOBS = ["CEO", "Vice President", "Human Resources", "IT Manager", "Tech Support", "Sales Floor Employee"]
HAIR = ["White", "Black", "Red", "Blonde", "Brunette", "Grey"]
LENGTH = ["Short", "Medium", "Long", "Super Long"]
EYES = ["Brown", "Blue", "Green", "Hazel"]
GLASSES = [True, False]
NAMES_FEMALE = ["Alex", "Renee", "Laura", "Lina", "Angel", "Molly"]
NAME_MALE = ["Bob", "George", "Fred", "Greg", "Tony", "Justin"]
BRASSIERE = ["A", "B", "C", "D", "DD", "E"]
#######################################
# These really ought to be in files...
#######################################
CHARINFO = \
{'CEO': {'female': {'diff': [3, 14, 17, 18],
'text': ['You stare blankly at the square box in front of you and scratch at your $HAIR hair. You know this box is supposed to do something. You smack it thinking it might help. Unfortunately it seems smacking it caused a piece to fall off. Picking it up you examine it and pull out a hammer. Knowing full well this will fix the problem.',
"Being a woman, it's been hard to be in the lime light of the company, being that you're not particularly smart. Especially in the IT field. You think secretly the IT scum are making fun of you behind your back. You always just merely flip your $LENGTH $HAIR hair and turn your nose up at them as they walk by. Knowing full well they like the view as you walk away.",
"Being that you're a woman and the owner of your own company. Not many think that you're smart, but the IT guys seem to have your back when it comes to questions. They're nice and respectful and you always seem to have the right questions and follow through with their advice. You may be no tech guru, but you sure as hell try.",
"It's been rough being a woman, and being extremely intelligent. Especially to the IT crowd. Not many women fills it's rosters. You made this company, and grew it from the ground up with barely any need of an IT crew. You hire them anyways though to carry out the tasks you deem necessary and they don't seem to really complain too much. They know you're not stupid and respect your decisions."]},
'male': {'diff': [3, 14, 17, 18],
'text': ['You stare blankly at the square box in front of you and scratch at your $HAIR hair. You know this box is supposed to do something. You smack it thinking it might help. Unfortunately it seems smacking it caused a piece to fall off. Picking it up you examine it and pull out a hammer. Knowing full well this will fix the problem.',
"You are the big cheese, the boss to end all bosses. Those IT guys and their thingamajiggers aren't anything to you. You rule this company with an iron fist and it doesn't matter a lick that you don't even know what a survore is.",
"Looking at your email you notice you've lost connection to the exchange server. Knowing that's a pretty bad thing you call up the IT department just to double check they're on the case. Knowing full well they're probably already on it. You love your IT guys, they keep the world revolving.",
"You've pretty much single handedly programmed every server in the company and often times find yourself in the IT department just to get your hands dirty. The IT guys love you and often come to your own office just to chit chat. You always make sure the IT department is well taken care of and often make sure the rest of your employees go through your general computing classes."]}},
'default': {'female': {'diff': [4, 8, 12, 16],
'text': ['Variables are case-sensitive! $NAME $name $Name $NPC1NAME $NPC1name $NPC1Name',
'Dumb $Job',
'Semi-smart $Job',
'Smart $Job']},
'male': {'diff': [4, 8, 12, 16],
'text': ['Variables are case-sensitive! $NAME $name $Name $NPC1NAME $NPC1name $NPC1Name',
'Dumb $Name',
'Semi-smart $job',
'Smart $Job']}}}
CHARPATH = \
{'CEO': [["Sitting in your office you comb back your $length $hair hair with a weary hand. It's been a long day at the office.",
["This box in front of you is making some wierd beeping sounds every time you try and turn it on. At least you think your trying to turn it on. You really have no idea, you know it's got to be the Tech Support departments fault though. They're always screwing with you.",
"Those damned tech bastards have been screwing things up all damn day. First they wouldn't paint your black monitor white, and then they damn well insulted you! You begin to think of a way to get back at them.",
'Leaning back you begin to think on what you can do. It really has been a long day and the tech deparment seems to have really came through for you today. $NPC1Name in the Tech department could probably use a visit.',
"A computer lay in front of you in pieces. You had told $NPC1Name that you would fix it for them so they could get a little bit of a break from the constant grueling ticket queue. It seems as though this hard drive is fried. You'll probably have to go down to the tech department to get a new one."]],
['Leader prompt for CEO #2',
['$Name is very dumb and $NPC1Name knows it',
"$Name is almost competent, with $NPC1Name's help",
"$Name is has enough knowledge to be the bane of $NPC1Name's existence",
'$Name and $NPC1Name get along']]],
'default': [['default prompt',
['thread 1', 'thread 2', 'thread 3', 'thread 4']]]}
#######################################
def get_remote_files(save=False):
'''
I can't ask a bunch of strangers to download
and execute code from the Internet, can I?
:type save: bool Save files to disk?
:rtype: None
'''
global CHARINFO, CHARPATH
vers = 2
try:
from urllib2 import urlopen
except ImportError:
from urllib.request import urlopen
vers = 3
def get_remote_file(url):
resp = urlopen(url)
if vers > 2:
return json.loads(resp.readall().decode('utf-8'))
return json.load(resp)
CHARINFO = get_remote_file('https://gist.githubusercontent.com/stickytruth/549ed6b879560ae9edf6/raw/charinfo.json')
CHARPATH = get_remote_file('https://gist.githubusercontent.com/stickytruth/549ed6b879560ae9edf6/raw/charpath.json')
if save:
with open('charinfo.json', 'w') as fp:
fp.write(json.dumps(CHARINFO, indent=4, sort_keys=True))
with open('charpath.json', 'w') as fp:
fp.write(json.dumps(CHARPATH, indent=4, sort_keys=True))
def load_local_files():
global CHARINFO, CHARPATH
def load_file(name):
try:
with open(name, 'r') as fp:
js = json.load(fp)
return js
except Exception as e:
print('Error loading %s' % name)
print(e)
CHARINFO = load_file('charinfo.json')
CHARPATH = load_file('charpath.json')
class CharacterBase(object):
def __init__(self):
self.age = random.randint(17, 40)
self.weight = random.randint(90,180)
self.hair = random.choice(HAIR)
self.length = random.choice(LENGTH)
self.eyes = random.choice(EYES)
self.feet = random.randint(4,6)
self.inches = random.randint(0, 11)
self.breast = random.choice(BRASSIERE)
self.glasses = random.randint(0, 1) == 0
self.str = random.randint(3, 18)
self.dex = random.randint(3, 18)
self.con = random.randint(3, 18)
self.int = random.randint(3, 18)
self.wis = random.randint(3, 18)
self.char = random.randint(3, 18)
self.job = random.choice(JOBS)
def display(self):
for k, v in self.__dict__.items():
print('%s: %s' % (k, v))
def keys(self):
return self.__dict__.keys()
class CharacterUser(CharacterBase):
def __init__(self, name, gender):
CharacterBase.__init__(self)
self.name = name
self.gender = gender
class CharacterNPC(CharacterBase):
def __init__(self):
CharacterBase.__init__(self)
self.gender = random.choice(GENDER)
self.name = random.choice(NAMES_FEMALE)
if self.gender == 'male':
self.name = random.choice(NAME_MALE)
def closest_index(l, i):
'''
given a list of numbers `l` and a number `i`
the index of the number closest to `i` in `l`
will be returned
:param l: list
:param i: int
:rtype: int
'''
return min(range(len(l)), key=lambda j: abs(l[j]-i))
def weighted_choice(choices):
'''
choices is a nested list like [["70%", 0.7], ["30%", 0.3]]
which would return "70%" around 70% of the time
:type choices: list
:rtype: object
'''
total = sum(w for c, w in choices)
r = random.uniform(0, total)
upto = 0
for c, w in choices:
if upto + w > r:
return c
upto += w
assert False, "Shouldn't get here"
# def get_character_info(job, gender, intelligence):
def get_character_info(character):
'''
if the character's job doesn't yet exist use the default template
use the character's intelligence to find the index to use for texts
:type character: CharacterUser
:rtype: str, int
'''
job = character.job
if not job in CHARINFO:
job = 'default'
index = closest_index(CHARINFO[job][character.gender]['diff'], character.int)
return job, index
def get_story_1(player, npc):
'''
use the intelligence index to pull out relevant text
returns the text formatted with info from player and npc
:type player: CharacterUser
:type npc: CharacterNPC
:return: str
'''
job, index = get_character_info(player)
story = CHARINFO[job][player.gender]['text'][index]
return format_text(story, player, npc)
def get_story_2(player, npc):
'''
use the intelligence index to pull out relevant text
(the second part of the story has two parts:
the lead text and the meat)
returns both texts formatted with info from player and npc
:type player: CharacterUser
:type npc: CharacterNPC
:rtype: str, str
'''
job, index = get_character_info(player)
arc = random.randint(0, len(CHARPATH[job])-1)
lead = format_text(CHARPATH[job][arc][0], player, npc)
story = format_text(CHARPATH[job][arc][1][index], player, npc)
return lead, story
def format_text(text, player, npc):
'''
Placeholders in text are replaced with values from player and npc
Placeholders are case-sensitive:
$Name- > Bob, $NAME -> BOB
$NPC1JOB -> CEO, $NPC1job -> ceo
:type text: str
:type player CharacterBase
:type npc CharacterNPC
:rtype: str
'''
for k in player.keys():
text = text.replace('$' + k.upper(), str(getattr(player, k)).upper())
text = text.replace('$' + k.lower(), str(getattr(player, k)).lower())
text = text.replace('$' + k.title(), str(getattr(player, k)).title())
for k in npc.keys():
text = text.replace('$NPC1' + k.upper(), str(getattr(npc, k)).upper())
text = text.replace('$NPC1' + k.lower(), str(getattr(npc, k)).lower())
text = text.replace('$NPC1' + k.title(), str(getattr(npc, k)).title())
return text
def run(name=False, gender=False):
'''
Given a character's name and gender (or not) create a story
:type name: str
:type gender: str
:rtype: None
'''
gender = gender or random.choice(GENDER)
if not name:
name = random.choice(NAMES_FEMALE) if gender == 'female' else random.choice(NAME_MALE)
player = CharacterUser(name, gender)
npc = CharacterNPC()
story1 = get_story_1(player, npc)
story2a, story2b = get_story_2(player, npc)
player.display()
print(story1)
print(story2a)
print(story2b)
def getargs():
parser = argparse.ArgumentParser()
parser.add_argument("name", help="character's name", type=str, nargs='?', default=None)
parser.add_argument("gender", help="character's gender", type=str, nargs='?', default=None)
parser.add_argument("--download-save", help="download data from github gist save locally", action="store_true")
parser.add_argument("--download", help="download data from github gist [NO SAVE]", action="store_true")
parser.add_argument("--load-data", help="use data from local files", action="store_true")
return parser.parse_args()
if __name__ == '__main__':
args = getargs()
if args.download_save:
get_remote_files(True)
elif args.download:
get_remote_files()
if args.load_data:
load_local_files()
run(args.name, args.gender)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment