added weather and stolen bases

This commit is contained in:
Sakimori 2020-12-27 16:51:41 -05:00
parent 8348521f12
commit 8ba7a4ff45
2 changed files with 137 additions and 47 deletions

148
games.py
View File

@ -12,7 +12,9 @@ def config():
"pitching_stars" : 1, #pitching "pitching_stars" : 1, #pitching
"baserunning_stars" : 1, #baserunning "baserunning_stars" : 1, #baserunning
"defense_stars" : 1 #defense "defense_stars" : 1 #defense
} },
"stolen_base_chance_mod" : 1,
"stolen_base_success_mod" : 1
} }
with open("games_config.json", "w") as config_file: with open("games_config.json", "w") as config_file:
json.dump(config_dic, config_file, indent=4) json.dump(config_dic, config_file, indent=4)
@ -125,7 +127,7 @@ class game(object):
self.inning = 1 self.inning = 1
self.outs = 0 self.outs = 0
self.top_of_inning = True self.top_of_inning = True
self.last_update = None self.last_update = ({},0) #this is a ({outcome}, runs) tuple
self.owner = None self.owner = None
self.ready = False self.ready = False
if length is not None: if length is not None:
@ -133,7 +135,7 @@ class game(object):
else: else:
self.max_innings = config()["default_length"] self.max_innings = config()["default_length"]
self.bases = {1 : None, 2 : None, 3 : None} self.bases = {1 : None, 2 : None, 3 : None}
self.weather = weather("Sunny","🌞")
def get_batter(self): def get_batter(self):
if self.top_of_inning: if self.top_of_inning:
@ -163,6 +165,9 @@ class game(object):
bat_stat = random_star_gen("batting_stars", batter) bat_stat = random_star_gen("batting_stars", batter)
pitch_stat = random_star_gen("pitching_stars", pitcher) pitch_stat = random_star_gen("pitching_stars", pitcher)
if weather.name == "Supernova":
pitch_stat = pitch_stat * 0.9
pb_system_stat = (random.gauss(1*math.erf((bat_stat - pitch_stat)*1.5)-1.8,2.2)) pb_system_stat = (random.gauss(1*math.erf((bat_stat - pitch_stat)*1.5)-1.8,2.2))
hitnum = random.gauss(2*math.erf(bat_stat/4)-1,3) hitnum = random.gauss(2*math.erf(bat_stat/4)-1,3)
@ -221,6 +226,57 @@ class game(object):
outcome["text"] = appearance_outcomes.homerun outcome["text"] = appearance_outcomes.homerun
return outcome return outcome
def thievery_attempts(self): #returns either false or "at-bat" outcome
thieves = []
attempts = []
for base in self.bases.keys():
if self.bases[base] is not None and base != 3: #no stealing home in simsim, sorry stu
if self.bases[base+1] is None: #if there's somewhere to go
thieves.append((self.bases[base], base))
for baserunner, start_base in thieves:
run_stars = random_star_gen("baserunning_stars", baserunner)*config()["stolen_base_chance_mod"]
if self.weather.name == "Midnight":
run_stars = run_stars*2
def_stars = random_star_gen("defense_stars", self.get_pitcher())
if run_stars >= (def_stars - 1.5): #if baserunner isn't worse than pitcher
roll = random.random()
if roll >= (-(((run_stars+1)/14)**2)+1): #plug it into desmos or something, you'll see
attempts.append((baserunner, start_base))
if len(attempts) == 0:
return False
else:
return (self.steals_check(attempts), 0) #effectively an at-bat outcome with no score
def steals_check(self, attempts):
if self.top_of_inning:
defense_team = self.teams["home"]
else:
defense_team = self.teams["away"]
outcome = {}
outcome["steals"] = []
for baserunner, start_base in attempts:
defender = random.choice(defense_team.lineup) #excludes pitcher
run_stat = random_star_gen("baserunning_stars", baserunner)
def_stat = random_star_gen("defense_stars", defender)
run_roll = random.gauss(2*math.erf((run_stat-def_stat)/4)-1,3)
if start_base == 2:
run_roll = run_roll * .9 #stealing third is harder
if run_roll < 1:
outcome["steals"].append(f"{baserunner} was caught stealing {base_string(start_base+1)} base by {defender}!")
self.outs += 1
else:
outcome["steals"].append(f"{baserunner} steals {base_string(start_base+1)} base!")
self.bases[start_base+1] = baserunner
self.bases[start_base] = None
if self.outs >= 3:
self.flip_inning()
return outcome
def baserunner_check(self, defender, outcome): def baserunner_check(self, defender, outcome):
def_stat = random_star_gen("defense_stars", defender) def_stat = random_star_gen("defense_stars", defender)
if outcome["text"] == appearance_outcomes.homerun or outcome["text"] == appearance_outcomes.grandslam: if outcome["text"] == appearance_outcomes.homerun or outcome["text"] == appearance_outcomes.grandslam:
@ -347,11 +403,13 @@ class game(object):
if self.top_of_inning: if self.top_of_inning:
offense_team = self.teams["away"] offense_team = self.teams["away"]
defense_team = self.teams["home"] defense_team = self.teams["home"]
defender = random.choice(self.teams["home"].lineup)
else: else:
offense_team = self.teams["home"] offense_team = self.teams["home"]
defense_team = self.teams["away"] defense_team = self.teams["away"]
defender = random.choice(self.teams["away"].lineup)
defenders = defense_team.lineup.copy()
defenders.append(defense_team.pitcher)
defender = random.choice(defenders) #pitcher can field outs now :3
if result["ishit"]: #if batter gets a hit: if result["ishit"]: #if batter gets a hit:
self.get_batter().game_stats["hits"] += 1 self.get_batter().game_stats["hits"] += 1
@ -454,39 +512,48 @@ class game(object):
} }
def gamestate_update_full(self): def gamestate_update_full(self):
self.last_update = self.batterup() attempts = self.thievery_attempts()
if attempts == False:
self.last_update = self.batterup()
else:
self.last_update = attempts
return self.gamestate_display_full() return self.gamestate_display_full()
def gamestate_display_full(self): def gamestate_display_full(self):
try: if "steals" in self.last_update[0].keys():
punc = "" return "Still in progress."
if self.last_update[0]["defender"] != "": else:
punc = "." try:
if not self.over: punc = ""
if self.top_of_inning: if self.last_update[0]["defender"] != "":
inningtext = "top" punc = "."
if not self.over:
if self.top_of_inning:
inningtext = "top"
else:
inningtext = "bottom"
updatestring = f"{self.last_update[0]['batter']} {self.last_update[0]['text'].value} {self.last_update[0]['defender']}{punc}\n"
if self.last_update[1] > 0:
updatestring += f"{self.last_update[1]} runs scored!"
return f"""Last update: {updatestring}
Score: {self.teams['away'].score} - {self.teams['home'].score}.
Current inning: {inningtext} of {self.inning}. {self.outs} outs.
Pitcher: {self.get_pitcher().name}
Batter: {self.get_batter().name}
Bases: 3: {str(self.bases[3])} 2: {str(self.bases[2])} 1: {str(self.bases[1])}
"""
else: else:
inningtext = "bottom" return f"""Game over! Final score: **{self.teams['away'].score} - {self.teams['home'].score}**
Last update: {self.last_update[0]['batter']} {self.last_update[0]['text'].value} {self.last_update[0]['defender']}{punc}"""
updatestring = f"{self.last_update[0]['batter']} {self.last_update[0]['text'].value} {self.last_update[0]['defender']}{punc}\n" except TypeError:
return "Game not started."
if self.last_update[1] > 0: except KeyError:
updatestring += f"{self.last_update[1]} runs scored!" return "Game not started."
return f"""Last update: {updatestring}
Score: {self.teams['away'].score} - {self.teams['home'].score}.
Current inning: {inningtext} of {self.inning}. {self.outs} outs.
Pitcher: {self.get_pitcher().name}
Batter: {self.get_batter().name}
Bases: 3: {str(self.bases[3])} 2: {str(self.bases[2])} 1: {str(self.bases[1])}
"""
else:
return f"""Game over! Final score: **{self.teams['away'].score} - {self.teams['home'].score}**
Last update: {self.last_update[0]['batter']} {self.last_update[0]['text'].value} {self.last_update[0]['defender']}{punc}"""
except TypeError:
return "Game not started."
def add_stats(self): def add_stats(self):
players = [] players = []
@ -555,4 +622,15 @@ def base_string(base):
elif base == 3: elif base == 3:
return "third" return "third"
elif base == 4: elif base == 4:
return "fourth" return "fourth"
class weather(object):
name = "Sunny"
emoji = "🌞"
def __init__(self, new_name, new_emoji):
self.name = new_name
self.emoji = new_emoji
def __str__(self):
return f"{self.emoji} {self.name}"

View File

@ -1,4 +1,4 @@
import discord, json, math, os, roman, games, asyncio import discord, json, math, os, roman, games, asyncio, random
import database as db import database as db
import onomancer as ono import onomancer as ono
@ -501,6 +501,9 @@ async def watch_game(channel, newgame, user = None):
top_of_inning = True top_of_inning = True
victory_lap = False victory_lap = False
weathers = [games.weather("Supernova", "🌟"), games.weather("Midnight", "🕶")]
newgame.weather = random.choice(weathers)
while not newgame.over or newgame.top_of_inning != top_of_inning: while not newgame.over or newgame.top_of_inning != top_of_inning:
state = newgame.gamestate_display_full() state = newgame.gamestate_display_full()
@ -540,19 +543,28 @@ async def watch_game(channel, newgame, user = None):
new_embed.add_field(name="🍿", value=f"Bottom of {newgame.inning}. {newgame.teams['home'].name} batting!", inline=False) new_embed.add_field(name="🍿", value=f"Bottom of {newgame.inning}. {newgame.teams['home'].name} batting!", inline=False)
if pause != 1 and state != "Game not started.": if pause != 1 and state != "Game not started.":
punc = "" if "steals" in newgame.last_update[0].keys():
if newgame.last_update[0]["defender"] != "": updatestring = ""
punc = ". " for attempt in newgame.last_update[0]["steals"]:
updatestring += attempt + "\n"
new_embed.add_field(name="💎", value=updatestring, inline=False)
if "fc_out" in newgame.last_update[0].keys():
name, base_string = newgame.last_update[0]['fc_out']
updatestring = f"{newgame.last_update[0]['batter']} {newgame.last_update[0]['text'].value.format(name, base_string)} {newgame.last_update[0]['defender']}{punc}"
else: else:
updatestring = f"{newgame.last_update[0]['batter']} {newgame.last_update[0]['text'].value} {newgame.last_update[0]['defender']}{punc}" updatestring = ""
if newgame.last_update[1] > 0: punc = ""
updatestring += f"{newgame.last_update[1]} runs scored!" if newgame.last_update[0]["defender"] != "":
punc = ". "
new_embed.add_field(name="🏏", value=updatestring, inline=False) if "fc_out" in newgame.last_update[0].keys():
name, base_string = newgame.last_update[0]['fc_out']
updatestring = f"{newgame.last_update[0]['batter']} {newgame.last_update[0]['text'].value.format(name, base_string)} {newgame.last_update[0]['defender']}{punc}"
else:
updatestring = f"{newgame.last_update[0]['batter']} {newgame.last_update[0]['text'].value} {newgame.last_update[0]['defender']}{punc}"
if newgame.last_update[1] > 0:
updatestring += f"{newgame.last_update[1]} runs scored!"
new_embed.add_field(name="🏏", value=updatestring, inline=False)
basemessage = str(blank_emoji) basemessage = str(blank_emoji)
if newgame.bases[2] is not None: if newgame.bases[2] is not None:
@ -573,7 +585,7 @@ async def watch_game(channel, newgame, user = None):
basemessage += str(empty_base) basemessage += str(empty_base)
new_embed.add_field(name="Bases:", value=basemessage, inline = False) new_embed.add_field(name="Bases:", value=basemessage, inline = False)
new_embed.add_field(name="Weather:", value="🌟 Supernova", inline = False) new_embed.add_field(name="Weather:", value=str(newgame.weather), inline = False)
await embed.edit(content=None, embed=new_embed) await embed.edit(content=None, embed=new_embed)
top_of_inning = newgame.top_of_inning top_of_inning = newgame.top_of_inning