set up at-bat simulation in games.py, and a test function in the_prestige.

This commit is contained in:
Sakimori 2020-12-21 00:23:02 -05:00
parent 0141723e1b
commit 8235532819
6 changed files with 220 additions and 4 deletions

1
.gitignore vendored
View File

@ -341,6 +341,7 @@ healthchecksdb
# Personal config file, contains bot token
config.json
games_config.json
ids
# database

View File

@ -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()

172
games.py Normal file
View File

@ -0,0 +1,172 @@
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)
outcome = {}
if pb_system_stat <= 0:
outcome["ishit"] = False
fc_flag = False
if hitnum < 1:
outcome["text"] = random.choice([appearance_outcomes.strikeoutlooking, appearance_outcomes.strikeoutswinging])
elif hitnum < 2:
outcome["text"] = appearance_outcomes.groundout
outcome["defender"] = defender
else:
outcome["text"] = appearance_outcomes.flyout
outcome["defender"] = defender
if self.bases[1] is not None and hitnum < 1:
outcome["text"] = 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["text"] = appearance_outcomes.fielderschoice
else:
if hitnum < 1:
outcome["text"] = appearance_outcomes.single
elif hitnum < 2:
outcome["text"] = appearance_outcomes.double
elif hitnum < 3:
outcome["text"] = 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["text"] = appearance_outcomes.grandslam
else:
outcome["text"] = 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

View File

@ -11,7 +11,6 @@ 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:
return response.json()
def get_scream(username):

View File

@ -28,6 +28,9 @@
<Compile Include="onomancer.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="games.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="roman.py" />
<Compile Include="the_prestige.py" />
</ItemGroup>
@ -44,6 +47,7 @@
</ItemGroup>
<ItemGroup>
<Content Include="config.json" />
<Content Include="games_config.json" />
<Content Include="ids" />
<Content Include="matteo.db" />
</ItemGroup>

View File

@ -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['text'].value} {atbat['defender'].name}.")
except KeyError:
await msg.channel.send(f"{batter.name} {atbat['text'].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"])