From cdf9d96cc6b053e2384c77a7150f0f52dd7c7eff Mon Sep 17 00:00:00 2001 From: Sakimori Date: Mon, 21 Dec 2020 00:23:02 -0500 Subject: [PATCH] set up at-bat simulation in games.py, and a test function in the_prestige. --- .gitignore | 1 + database.py | 21 ++++++ games.py | 167 ++++++++++++++++++++++++++++++++++++++++++++ onomancer.py | 3 +- the-prestige.pyproj | 4 ++ the_prestige.py | 23 +++++- 6 files changed, 215 insertions(+), 4 deletions(-) create mode 100644 games.py diff --git a/.gitignore b/.gitignore index af5ace5..16243cc 100644 --- a/.gitignore +++ b/.gitignore @@ -341,6 +341,7 @@ healthchecksdb # Personal config file, contains bot token config.json +games_config.json ids # database diff --git a/database.py b/database.py index 0fb8e05..bb5e91a 100644 --- a/database.py +++ b/database.py @@ -30,10 +30,31 @@ def initialcheck(): player_name text NOT NULL, player_json_string text NOT NULL );""" + + player_stats_table_check_string = """ CREATE TABLE IF NOT EXISTS stats ( + counter integer PRIMARY KEY, + id text, + name text, + json_string text, + outs_pitched integer DEFAULT 0, + walks_allowed integer DEFAULT 0, + hits_allowed integer DEFAULT 0, + strikeouts_given integer DEFAULT 0, + runs_allowed integer DEFAULT 0, + plate_appearances integer DEFAULT 0, + walks_taken integer DEFAULT 0, + hits integer DEFAULT 0, + home_runs integer DEFAULT 0, + total_bases integer DEFAULT 0, + rbis integer DEFAULT 0, + strikeouts_taken integer DEFAULT 0 + );""" + if conn is not None: c = conn.cursor() c.execute(soulscream_table_check_string) c.execute(player_table_check_string) + c.execute(player_stats_table_check_string) conn.commit() conn.close() diff --git a/games.py b/games.py new file mode 100644 index 0000000..22fe10f --- /dev/null +++ b/games.py @@ -0,0 +1,167 @@ +import json, random, os, math +from enum import Enum +import database as db + +def config(): + if not os.path.exists("games_config.json"): + #generate default config + config_dic = { + "default_length" : 3, + "stlat_weights" : { + "batting_stars" : 1, #batting + "pitching_stars" : 1, #pitching + "baserunning_stars" : 1, #baserunning + "defense_stars" : 1 #defense + } + } + with open("games_config.json", "w") as config_file: + json.dump(config_dic, config_file, indent=4) + return config_dic + else: + with open("games_config.json") as config_file: + return json.load(config_file) + +class appearance_outcomes(Enum): + strikeoutlooking = "strikes out looking." + strikeoutswinging = "strikes out swinging." + groundout = "grounds out to" + flyout = "flies out to" + fielderschoice = "reaches on fielder's choice." + doubleplay = "grounds into a double play!" + walks = "draws a walk." + single = "hits a single!" + double = "hits a double!" + triple = "hits a triple!" + homerun = "hits a home run!" + grandslam = "hits a grand slam!" + + +class player(object): + def __init__(self, json_string): + self.stlats = json.loads(json_string) + self.id = self.stlats["id"] + self.name = self.stlats["name"] + self.game_stats = {} + + +class team(object): + def __init__(self): + self.name = None + self.lineup = [] + self.lineup_position = 0 + self.pitcher = None + + def add_lineup(self, new_player): + if len(self.lineup) <= 12: + self.lineup.append(new_player) + return (True,) + else: + return (False, "12 players in the lineup, maximum. We're being generous here.") + + def set_pitcher(self, new_player): + self.pitcher = new_player + return (True,) + + def is_ready(self): + return (len(self.lineup) >= 1 and self.pitcher is not None) + + def finalize(self): + if self.is_ready(): + while len(self.lineup) <= 4: + self.lineup.append(random.choice(self.lineup)) + return True + else: + return False + + +class game(object): + + def __init__(self, team1, team2, length=None): + self.teams = {"away" : team1, "home" : team2} + self.inning = 1 + self.top_of_inning = True + if length is not None: + self.max_innings = length + else: + self.max_innings = config()["default_length"] + self.bases = {1 : None, 2 : None, 3 : None} + + def get_batter(self): + if self.top_of_inning: + bat_team = self.teams["away"] + else: + bat_team = self.teams["home"] + return bat_team.lineup[bat_team.lineup_position % len(bat_team.lineup)] + + def get_pitcher(self): + if self.top_of_inning: + return self.teams["home"].pitcher + else: + return self.teams["away"].pitcher + + def at_bat(self): + pitcher = self.get_pitcher() + batter = self.get_batter() + if self.top_of_inning: + defender = random.choice(self.teams["home"].lineup) + else: + defender = random.choice(self.teams["away"].lineup) + + bat_stat = random_star_gen("batting_stars", batter) + pitch_stat = random_star_gen("pitching_stars", pitcher) + def_stat = random_star_gen("defense_stars", defender) + pb_system_stat = (random.gauss(1.5*math.erf((bat_stat - pitch_stat)/2)-1.5,3)) + hitnum = random.gauss(2*math.erf(bat_stat)-0.5,3) + + if pb_system_stat <= 0: + fc_flag = False + if hitnum < 1: + outcome = random.choice([(appearance_outcomes.strikeoutlooking,), (appearance_outcomes.strikeoutswinging,)]) + elif hitnum < 2: + outcome = (appearance_outcomes.groundout, defender) + else: + outcome = (appearance_outcomes.flyout, defender) + + if self.bases[1] is not None and hitnum < 1: + outcome = (appearance_outcomes.doubleplay,) + for base in self.bases.values(): + if base is not None: + fc_flag = True + if fc_flag and 1 <= hitnum and hitnum < 2: + outcome = (appearance_outcomes.fielderschoice,) + else: + if hitnum < 1: + outcome = (appearance_outcomes.single,) + elif hitnum < 2: + outcome = (appearance_outcomes.double,) + elif hitnum < 3: + outcome = (appearance_outcomes.triple,) + else: + if self.bases[1] is not None and self.bases[2] is not None and self.bases[3] is not None: + outcome = (appearance_outcomes.grandslam,) + else: + outcome = (appearance_outcomes.homerun,) + + if self.top_of_inning: + self.teams["away"].lineup_position += 1 + else: + self.teams["home"].lineup_position += 1 + return outcome + + + +def random_star_gen(key, player): + return random.gauss(config()["stlat_weights"][key] * player.stlats[key],1) +# innings_pitched +# walks_allowed +# strikeouts_given +# runs_allowed +# plate_appearances +# walks +# hits +# total_bases +# rbis +# walks_taken +# strikeouts_taken + + diff --git a/onomancer.py b/onomancer.py index 58d3857..72561ca 100644 --- a/onomancer.py +++ b/onomancer.py @@ -10,8 +10,7 @@ name_stats_hook = "generateStats2?name=" def get_stats(name): #yell at onomancer if not in cache or too old response = requests.get(onomancer_url + name_stats_hook + urllib.parse.quote_plus(name)) - if response.status_code == 200: - + if response.status_code == 200: return response.json() def get_scream(username): diff --git a/the-prestige.pyproj b/the-prestige.pyproj index 9f63274..9409db5 100644 --- a/the-prestige.pyproj +++ b/the-prestige.pyproj @@ -28,6 +28,9 @@ Code + + Code + @@ -44,6 +47,7 @@ + diff --git a/the_prestige.py b/the_prestige.py index 2c476ac..4004d1a 100644 --- a/the_prestige.py +++ b/the_prestige.py @@ -1,4 +1,4 @@ -import discord, json, os, roman +import discord, json, os, roman, games import database as db import onomancer as ono @@ -82,6 +82,24 @@ async def on_message(msg): except: await msg.channel.send("We can't find your idol. Looked everywhere, too.") + elif command == "testab": + team1 = games.team() + team2 = games.team() + team1.add_lineup(games.player(json.dumps(ono.get_stats("xvi")))) + team1.set_pitcher(games.player(json.dumps(ono.get_stats("16")))) + team1.finalize() + team2.add_lineup(games.player(json.dumps(ono.get_stats("artemis")))) + team2.set_pitcher(games.player(json.dumps(ono.get_stats("alphy")))) + team2.finalize() + + game = games.game(team1, team2) + batter = game.get_batter() + atbat = game.at_bat() + try: + await msg.channel.send(f"{batter.name} {atbat[0].value} {atbat[1].name}.") + except IndexError: + await msg.channel.send(f"{batter.name} {atbat[0].value}") + elif command == "credit": await msg.channel.send("Our avatar was graciously provided to us, with permission, by @HetreaSky on Twitter.") @@ -110,11 +128,12 @@ def build_star_embed(player_json): else: starnum = int(player_json[key]) addhalf = False - embedstring = "⭐" * starnum + embedstring += "⭐" * starnum if addhalf: embedstring += "✨" embed.add_field(name=starkeys[key], value=embedstring, inline=False) return embed + client.run(config()["token"]) \ No newline at end of file