Initial code commit
This commit is contained in:
commit
d8cb73fa6c
|
@ -0,0 +1,113 @@
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/python
|
||||||
|
# Edit at https://www.gitignore.io/?templates=python
|
||||||
|
|
||||||
|
### Python ###
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
wheels/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
share/python-wheels/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
MANIFEST
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.nox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*.cover
|
||||||
|
.hypothesis/
|
||||||
|
.pytest_cache/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# pipenv
|
||||||
|
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||||
|
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||||
|
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||||
|
# install all needed dependencies.
|
||||||
|
#Pipfile.lock
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# SageMath parsed files
|
||||||
|
*.sage.py
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
.spyproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# Mr Developer
|
||||||
|
.mr.developer.cfg
|
||||||
|
.project
|
||||||
|
.pydevproject
|
||||||
|
|
||||||
|
# mkdocs documentation
|
||||||
|
/site
|
||||||
|
|
||||||
|
# mypy
|
||||||
|
.mypy_cache/
|
||||||
|
.dmypy.json
|
||||||
|
dmypy.json
|
||||||
|
|
||||||
|
# Pyre type checker
|
||||||
|
.pyre/
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/python
|
||||||
|
|
||||||
|
# save
|
||||||
|
save.json
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2020 Robert 'khuxkm' Miles, https://khuxkm.tilde.team <khuxkm@tilde.team>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,18 @@
|
||||||
|
# PearlyGates
|
||||||
|
|
||||||
|
A game about heaven and hell, where you get to be the scales of morality.
|
||||||
|
|
||||||
|
## How to play?
|
||||||
|
|
||||||
|
Download the repo, and run `main.py` in your Python interpreter of choice. Be
|
||||||
|
sure to install the `tracery` library, which is required for the name generator.
|
||||||
|
|
||||||
|
## How to contribute?
|
||||||
|
|
||||||
|
For the most part, the code in `person.py` is self-explanatory. For example:
|
||||||
|
|
||||||
|
- To add a trait, add an entry to `TRAITS`.
|
||||||
|
- To add a set of traits you cannot have at the same time (like misogynist and feminist), add an entry to `EXCLUSIONARY_TRAITS` (see comment above definition).
|
||||||
|
- To change the average life expectancy, change `AVERAGE_LIFE_EXPECTANCY`.
|
||||||
|
|
||||||
|
The rest of the code may be poorly commented. Sorry, other coders (and future me).
|
|
@ -0,0 +1,120 @@
|
||||||
|
import person, json, random
|
||||||
|
|
||||||
|
# save file defaults
|
||||||
|
SAVE = dict(
|
||||||
|
most_holy=dict(),
|
||||||
|
most_sinful=dict(),
|
||||||
|
last_20_holy_ages=[],
|
||||||
|
last_20_sinful_ages=[],
|
||||||
|
holy=0,
|
||||||
|
sinful=0,
|
||||||
|
intro=False,
|
||||||
|
day=1
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
with open("save.json") as f:
|
||||||
|
# load save file
|
||||||
|
savefile = json.load(f)
|
||||||
|
# if a key is missing from the save file it'll be set to the default automatically
|
||||||
|
SAVE.update(savefile)
|
||||||
|
except: pass
|
||||||
|
|
||||||
|
# convenience functions
|
||||||
|
next_person = lambda: person.Person.generate()
|
||||||
|
avg = lambda l: sum(l)/len(l)
|
||||||
|
|
||||||
|
print("Welcome to PearlyGates!")
|
||||||
|
if not SAVE["intro"]:
|
||||||
|
# display story intro fragment
|
||||||
|
print()
|
||||||
|
print("Saint Peter has retired, and has left you in charge of the gate to heaven.")
|
||||||
|
print("Rather than being held to any standard, you are given full freedom to send")
|
||||||
|
print("people to heaven or hell based on your arbitrary guidelines.")
|
||||||
|
print()
|
||||||
|
print("So, let's begin!")
|
||||||
|
# don't show it on next startup
|
||||||
|
SAVE["intro"]=True
|
||||||
|
running=True
|
||||||
|
while running:
|
||||||
|
print("It is day {!s}.".format(SAVE["day"]))
|
||||||
|
print("Would you like to:")
|
||||||
|
print("1) See the dead people?")
|
||||||
|
print("2) See stats")
|
||||||
|
print("3) Quit")
|
||||||
|
choice = None
|
||||||
|
while choice is None:
|
||||||
|
try:
|
||||||
|
choice = int(input("? ").strip())
|
||||||
|
assert choice in (1,2,3)
|
||||||
|
except:
|
||||||
|
print("Choose 1, 2, or 3.")
|
||||||
|
choice=None
|
||||||
|
if choice==2: # stats
|
||||||
|
print("Stats:")
|
||||||
|
print("-"*80)
|
||||||
|
print("Amount of people sent to heaven all-time: {!s}".format(SAVE["holy"]))
|
||||||
|
print("Average age of holy person (over last 20): {!s}".format(avg(SAVE["last_20_holy_ages"])))
|
||||||
|
print("Top 5 most common holy traits:")
|
||||||
|
# get all traits of people marked "holy"
|
||||||
|
holy_traits = list(SAVE["most_holy"].items())
|
||||||
|
# sort by occurrences descending
|
||||||
|
holy_traits.sort(key=lambda x: -x[1])
|
||||||
|
# display top 5
|
||||||
|
for trait, count in holy_traits[:5]:
|
||||||
|
print(f" - {trait} ({count!s})")
|
||||||
|
print("-"*80)
|
||||||
|
print("Amount of people sent to hell all-time: {!s}".format(SAVE["sinful"]))
|
||||||
|
print("Average age of sinful person (over last 20): {!s}".format(avg(SAVE["last_20_sinful_ages"])))
|
||||||
|
print("Top 5 most common sinful traits:")
|
||||||
|
# get all traits of people marked "sinful"
|
||||||
|
sinful_traits = list(SAVE["most_sinful"].items())
|
||||||
|
# sort by occurences descending
|
||||||
|
sinful_traits.sort(key=lambda x: -x[1])
|
||||||
|
# show top 5
|
||||||
|
for trait, count in sinful_traits[:5]:
|
||||||
|
print(f" - {trait} ({count!s})")
|
||||||
|
print("-"*80)
|
||||||
|
elif choice==3:
|
||||||
|
print("Goodbye!")
|
||||||
|
running = False
|
||||||
|
else:
|
||||||
|
for i in range(random.randint(7,13)):
|
||||||
|
# get new person and show summary
|
||||||
|
p = next_person()
|
||||||
|
print(p.toString())
|
||||||
|
print("Send them to:")
|
||||||
|
print("1) Heaven")
|
||||||
|
print("2) Hell")
|
||||||
|
choice = None
|
||||||
|
while choice is None:
|
||||||
|
try:
|
||||||
|
choice = int(input("? ").strip())
|
||||||
|
assert choice in (1,2)
|
||||||
|
except:
|
||||||
|
print("Choose 1 or 2.")
|
||||||
|
choice=None
|
||||||
|
if choice==1: # heaven
|
||||||
|
print(p.pronoun,"smile"+('' if p.pronoun=="They" else "s"),"at you as",p.pronoun.lower(),"enter"+('' if p.pronoun=="They" else "s")+" the pearly gates.")
|
||||||
|
# update stats
|
||||||
|
SAVE["holy"]+=1
|
||||||
|
SAVE["last_20_holy_ages"]=(SAVE["last_20_holy_ages"]+[p.age])[-20:]
|
||||||
|
for trait in p.traits:
|
||||||
|
if trait not in SAVE["most_holy"]:
|
||||||
|
SAVE["most_holy"][trait]=1
|
||||||
|
else:
|
||||||
|
SAVE["most_holy"][trait]+=1
|
||||||
|
else:
|
||||||
|
print(p.pronoun,"scream"+('' if p.pronoun=="They" else "s"),"as",p.pronoun.lower(),"fall"+('' if p.pronoun=="They" else "s")+" into the depths of hell.")
|
||||||
|
# update stats
|
||||||
|
SAVE["sinful"]+=1
|
||||||
|
SAVE["last_20_sinful_ages"]=(SAVE["last_20_sinful_ages"]+[p.age])[-20:]
|
||||||
|
for trait in p.traits:
|
||||||
|
if trait not in SAVE["most_sinful"]:
|
||||||
|
SAVE["most_sinful"][trait]=1
|
||||||
|
else:
|
||||||
|
SAVE["most_sinful"][trait]+=1
|
||||||
|
# dawn of the next day
|
||||||
|
SAVE["day"]+=1
|
||||||
|
|
||||||
|
with open("save.json","w") as f:
|
||||||
|
json.dump(SAVE,f)
|
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"first_name_male": ["James","John","Robert","Michael","William","David","Richard","Charles","Joseph","Thomas","Christopher","Daniel","Paul","Mark","Donald","George","Kenneth","Steven","Edward","Brian","Ronald","Anthony","Kevin","Jason","Matthew","Gary","Timothy","Jose","Larry","Jeffrey","Frank","Scott","Eric","Stephen","Andrew","Raymond","Gregory","Joshua","Jerry","Dennis","Walter","Patrick","Peter","Harold","Douglas","Henry","Carl","Arthur","Ryan","Roger","Joe","Juan","Jack","Albert","Jonathan","Justin","Terry","Gerald","Keith","Samuel","Willie","Ralph","Lawrence","Nicholas","Roy","Benjamin","Bruce","Brandon","Adam","Harry","Fred","Wayne","Billy","Steve","Louis","Jeremy","Aaron","Randy","Howard","Eugene","Carlos","Russell","Bobby","Victor","Martin","Ernest","Phillip","Todd","Jesse","Craig","Alan","Shawn","Clarence","Sean","Philip","Chris","Johnny","Earl","Jimmy","Antonio"],
|
||||||
|
"first_name_female": ["Mary","Patricia","Linda","Barbara","Elizabeth","Jennifer","Maria","Susan","Margaret","Dorothy","Lisa","Nancy","Karen","Betty","Helen","Sandra","Donna","Carol","Ruth","Sharon","Michelle","Laura","Sarah","Kimberly","Deborah","Jessica","Shirley","Cynthia","Angela","Melissa","Brenda","Amy","Anna","Rebecca","Virginia","Kathleen","Pamela","Martha","Debra","Amanda","Stephanie","Carolyn","Christine","Marie","Janet","Catherine","Frances","Ann","Joyce","Diane","Alice","Julie","Heather","Teresa","Doris","Gloria","Evelyn","Jean","Cheryl","Mildred","Katherine","Joan","Ashley","Judith","Rose","Janice","Kelly","Nicole","Judy","Christina","Kathy","Theresa","Beverly","Denise","Tammy","Irene","Jane","Lori","Rachel","Marilyn","Andrea","Kathryn","Louise","Sara","Anne","Jacqueline","Wanda","Bonnie","Julia","Ruby","Lois","Tina","Phyllis","Norma","Paula","Diana","Annie","Lillian","Emily","Robin"],
|
||||||
|
"first_name": ["#first_name_male#","#first_name_female#"],
|
||||||
|
"lastname": ["Smith","Johnson","Williams","Brown","Jones","Miller","Davis","Garcia","Rodriguez","Wilson","Martinez","Anderson","Taylor","Thomas","Hernandez","Moore","Martin","Jackson","Thompson","White","Lopez","Lee","Gonzalez","Harris","Clark","Lewis","Robinson","Walker","Perez","Hall","Young","Allen","Sanchez","Wright","King","Scott","Green","Baker","Adams","Nelson","Hill","Ramirez","Campbell","Mitchell","Roberts","Carter","Phillips","Evans","Turner","Torres","Parker","Collins","Edwards","Stewart","Flores","Morris","Nguyen","Murphy","Rivera","Cook","Rogers","Morgan","Peterson","Cooper","Reed","Bailey","Bell","Gomez","Kelly","Howard","Ward","Cox","Diaz","Richardson","Wood","Watson","Brooks","Bennett","Gray","James","Reyes","Cruz","Hughes","Price","Myers","Long","Foster","Sanders","Ross","Morales","Powell","Sullivan","Russell","Ortiz","Jenkins","Gutierrez","Perry","Butler","Barnes","Fisher","Henderson","Coleman","Simmons","Patterson","Jordan","Reynolds","Hamilton","Graham","Kim","Gonzales","Alexander","Ramos","Wallace","Griffin","West","Cole","Hayes","Chavez","Gibson","Bryant","Ellis","Stevens","Murray","Ford","Marshall","Owens","Harrison","Ruiz","Kennedy","Wells","Alvarez","Woods","Mendoza","Castillo","Olson","Webb","Washington","Tucker","Freeman","Burns","Henry","Vasquez","Snyder","Simpson","Crawford","Jimenez","Porter","Mason","Shaw","Gordon","Wagner","Hunter","Romero","Hicks","Dixon","Hunt","Palmer","Robertson","Black","Holmes","Stone","Meyer","Boyd","Mills","Warren","Fox","Rose","Rice","Moreno","Schmidt","Patel","Ferguson","Nichols","Herrera","Medina","Ryan","Fernandez","Weaver","Daniels","Stephens","Gardner","Payne","Kelley","Dunn","Pierce","Arnold","Tran","Spencer","Peters","Hawkins","Grant","Hansen","Castro","Hoffman","Hart","Elliott","Cunningham","Knight","Bradley"],
|
||||||
|
"stereotypical_male_name": ["#first_name_male# #lastname#"],
|
||||||
|
"stereotypical_female_name": ["#first_name_female# #lastname#"],
|
||||||
|
"random_name": ["#first_name# #lastname#"]
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
import tracery, json, sys, random, traceback, math
|
||||||
|
|
||||||
|
# name generator
|
||||||
|
NAMES = None
|
||||||
|
try:
|
||||||
|
with open("name.json") as f: NAMES = tracery.Grammar(json.load(f))
|
||||||
|
except Exception as e:
|
||||||
|
if type(e)==FileNotFoundError:
|
||||||
|
print("ERROR! name.json not found!",file=sys.stderr)
|
||||||
|
print("Download `name.json` and place it in the same folder as `person.py`.",file=sys.stderr)
|
||||||
|
traceback.print_exc()
|
||||||
|
sys.exit(-1)
|
||||||
|
|
||||||
|
# traits list
|
||||||
|
TRAITS = """Transgender
|
||||||
|
Homosexual
|
||||||
|
Christian
|
||||||
|
Muslim
|
||||||
|
Hindu
|
||||||
|
Jewish
|
||||||
|
Plays video games
|
||||||
|
Is a jerk to service workers (cashiers, waiters, etc)
|
||||||
|
Is nice to service workers (cashiers, waiters, etc)
|
||||||
|
Kicks puppies
|
||||||
|
Might be a nazi?
|
||||||
|
Racist
|
||||||
|
Misogynist
|
||||||
|
Feminist
|
||||||
|
Bigoted
|
||||||
|
Died rich
|
||||||
|
Died poor""".splitlines()
|
||||||
|
|
||||||
|
# list of traits you can't have together
|
||||||
|
# if a person is generated with more than one of the traits in a tuple,
|
||||||
|
# they will reroll all but one of those traits
|
||||||
|
EXCLUSIONARY_TRAITS = [
|
||||||
|
("Hindu","Jewish","Muslim"),
|
||||||
|
("Is a jerk to service workers (cashiers, waiters, etc)","Is nice to service workers (cashiers, waiters, etc)"),
|
||||||
|
("Died rich","Died poor"),
|
||||||
|
("Misogynist","Feminist")
|
||||||
|
]
|
||||||
|
|
||||||
|
# average life expectancy
|
||||||
|
# according to the UN, world life expectancy was ~72.6 in 2019, so we'll go with that
|
||||||
|
AVERAGE_LIFE_EXPECTANCY=72.6
|
||||||
|
|
||||||
|
# pronouns list
|
||||||
|
# male uses he/him, female uses she/her, and non-binary can use any pronoun in the list below
|
||||||
|
PRONOUNS = """He
|
||||||
|
She
|
||||||
|
They
|
||||||
|
Ze
|
||||||
|
Xe
|
||||||
|
Ve
|
||||||
|
Vi""".splitlines()
|
||||||
|
|
||||||
|
class Person:
|
||||||
|
GENDER_DESCRIPTORS = ["Male","Female","Non-binary"]
|
||||||
|
def __init__(self,name,age,gender=0,traits=["Boring"]):
|
||||||
|
self.name=name
|
||||||
|
self.age=age
|
||||||
|
self.gender=gender
|
||||||
|
self.traits=traits
|
||||||
|
# force gender-specific pronouns on binary genders
|
||||||
|
if self.gender==0:
|
||||||
|
self.pronoun="He"
|
||||||
|
elif self.gender==1:
|
||||||
|
self.pronoun="She"
|
||||||
|
elif self.gender==2:
|
||||||
|
# non-binary people get to have whatever pronoun they desire from the list
|
||||||
|
self.pronoun=random.choice(PRONOUNS)
|
||||||
|
def toString(self):
|
||||||
|
# change gender number to gender descriptor
|
||||||
|
gender = self.GENDER_DESCRIPTORS[self.gender]
|
||||||
|
out=""
|
||||||
|
out+=(f"{self.name}, {self.age}\n")
|
||||||
|
out+=(f"Gender: {gender}\n")
|
||||||
|
c = len(self.traits)
|
||||||
|
out+=(f"Traits: ({c!s})\n")
|
||||||
|
for trait in self.traits:
|
||||||
|
out+=(f" - {trait}\n")
|
||||||
|
return out.strip()
|
||||||
|
def __str__(self):
|
||||||
|
return self.toString()
|
||||||
|
@classmethod
|
||||||
|
def generate(cls):
|
||||||
|
# pick a random gender
|
||||||
|
gender = random.randint(0,len(cls.GENDER_DESCRIPTORS)-1)
|
||||||
|
tag = "random_name"
|
||||||
|
# ~67% chance name is guaranteed to be stereotypical of gender if gender in binary
|
||||||
|
if gender==0:
|
||||||
|
tag = random.choice(["stereotypical_male_name","stereotypical_male_name","random_name"])
|
||||||
|
elif gender==1:
|
||||||
|
tag = random.choice(["stereotypical_female_name","stereotypical_female_name","random_name"])
|
||||||
|
# generate name from tracery grammar
|
||||||
|
name = NAMES.flatten("#"+tag+"#")
|
||||||
|
# pick age, skewed towards average life expectancy
|
||||||
|
age = random.choice([math.floor,math.ceil])(random.triangular(5,100,AVERAGE_LIFE_EXPECTANCY))
|
||||||
|
# pick 3-7 random traits
|
||||||
|
traits = [random.choice(TRAITS) for i in range(random.randint(3,7))]
|
||||||
|
check = True
|
||||||
|
while check:
|
||||||
|
check = False
|
||||||
|
for trait_exc in EXCLUSIONARY_TRAITS:
|
||||||
|
# indexes of conflicting traits
|
||||||
|
ind = [i for i, c in enumerate(traits) if c in trait_exc]
|
||||||
|
# if person doesn't have anything in the list, go to next
|
||||||
|
if not ind: continue
|
||||||
|
ind.pop(0) # keep first rolled trait
|
||||||
|
if ind: # more than one?
|
||||||
|
for i in ind:
|
||||||
|
# reroll
|
||||||
|
traits[i]=random.choice(TRAITS)
|
||||||
|
check = True # check for conflicting traits again
|
||||||
|
# don't allow duplicates
|
||||||
|
c = len(traits) # length before
|
||||||
|
traits = list(set(traits)) # remove duplicates
|
||||||
|
while len(traits)<c: # if the list had duplicates
|
||||||
|
check = True # make sure to check again after you...
|
||||||
|
traits.append(random.choice(TRAITS)) # ...add new traits
|
||||||
|
# return object
|
||||||
|
return cls(name,age,gender,traits)
|
|
@ -0,0 +1 @@
|
||||||
|
tracery>=0.1.1
|
Loading…
Reference in New Issue