Merge pull request #262 from Sakimori/draft-pool-expansion

Draft pool expansion
This commit is contained in:
Sakimori 2021-06-30 17:01:52 -04:00 committed by GitHub
commit bdc6841826
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 154 additions and 29 deletions

1
.gitignore vendored
View file

@ -358,3 +358,4 @@ env
/data/leagues
/simmadome/build
/simmadome/.eslintcache
/matteo_env/Lib/site-packages

View file

@ -50,6 +50,8 @@ class player(object):
"strikeouts_taken" : 0
}
self.stat_name = self.name
if self.name == "Tim Locastro":
self.randomize_stars()
def star_string(self, key):
str_out = ""
@ -68,6 +70,15 @@ class player(object):
def __str__(self):
return self.name
def randomize_stars(self):
for key in ["batting_stars", "pitching_stars", "baserunning_stars", "defense_stars"]:
#random star value between 0 and 6.5
stars = random.randint(0,6)
half_star = random.random() < 0.5 #half star addition
if half_star:
stars = half_star + 0.5
self.stlats[key] = stars
class team(object):
def __init__(self):
@ -208,6 +219,7 @@ class game(object):
def __init__(self, team1, team2, length=None):
self.over = False
self.random_weather_flag = False
self.teams = {"away" : team1, "home" : team2}
self.inning = 1
self.outs = 0
@ -682,6 +694,9 @@ class game(object):
self.top_of_inning = not self.top_of_inning
if self.random_weather_flag and self.top_of_inning:
setattr(self, "weather", random.choice(list(weather.safe_weathers().values()))(self))
self.weather.on_flip_inning(self)
self.choose_next_batter()
@ -690,6 +705,7 @@ class game(object):
self.inning += 1
if self.inning > self.max_innings and self.teams["home"].score != self.teams["away"].score: #game over
self.over = True
try: #if something goes wrong with OBL don't erase game
if self.max_innings >= 9 or self.weather.name in ["Leaf Eddies", "Torrential Downpour"]:
if self.teams["home"].score == 16:
this_xvi_team = self.teams["home"]
@ -698,6 +714,9 @@ class game(object):
else:
this_xvi_team = None
db.save_obl_results(self.teams["home"] if self.teams["home"].score > self.teams["away"].score else self.teams["away"], self.teams["home"] if self.teams["home"].score < self.teams["away"].score else self.teams["away"], xvi_team=this_xvi_team)
except:
pass
def end_of_game_report(self):
@ -798,6 +817,9 @@ def get_team(name):
team_json.rotation.append(team_json.pitcher)
team_json.pitcher = None
update_team(team_json)
for player in team_json.rotation + team_json.lineup:
if player.name == "Tim Locastro":
player.randomize_stars()
return team_json
return None
except AttributeError:
@ -818,6 +840,9 @@ def get_team_and_owner(name):
team_json.rotation.append(team_json.pitcher)
team_json.pitcher = None
update_team(team_json)
for player in team_json.rotation + team_json.lineup:
if player.name == "Tim Locastro":
player.randomize_stars()
return (team_json, owner_id)
return None
except AttributeError:
@ -864,6 +889,9 @@ def search_team(search_term):
team_json.rotation.append(team_json.pitcher)
team_json.pitcher = None
update_team(team_json)
for player in team_json.rotation + team_json.lineup:
if player.name == "Tim Locastro":
player.randomize_stars()
except AttributeError:
team_json.rotation = []
team_json.rotation.append(team_json.pitcher)

View file

@ -45,7 +45,7 @@ class game_strings_base(object):
twoparts = []
diff_formats = {fielderschoice[0]: ("batter", "base_string"),
diff_formats = {fielderschoice[0]: ("runner", "base_string"),
steal_success[0]: ("runner", "base_string"),
steal_caught[0]: ("runner", "base_string", "defender")}
no_formats = strikeoutlooking + strikeoutswinging + doubleplay + walk + single + double + triple + homerun + grandslam

View file

@ -190,15 +190,19 @@ def update_loop():
else:
if this_game.top_of_inning:
state["update_text"] = f"Top of {this_game.inning}. {this_game.teams['away'].name} batting!"
this_game.weather.modify_top_of_inning_message(this_game, state)
if this_game.random_weather_flag:
this_game.weather.weather_report(this_game, state)
else:
if this_game.inning >= this_game.max_innings:
if this_game.teams["home"].score > this_game.teams["away"].score:
this_game.victory_lap = True
state["update_text"] = f"Bottom of {this_game.inning}. {this_game.teams['home'].name} batting!"
this_game.weather.modify_top_of_inning_message(this_game, state)
elif state["update_pause"] != 1 and this_game.play_has_begun:
if "twopart" in this_game.last_update[0].keys():
@ -256,4 +260,4 @@ def update_loop():
socket_thread = threading.Thread(target=socketio.emit, args=("states_update", game_states))
socket_thread.start()
#socketio.emit("states_update", game_states)
time.sleep(8)
time.sleep(3)

24
real_players.py Normal file
View file

@ -0,0 +1,24 @@
from lxml import html
import requests, json
import onomancer as ono
def random_real_player():
name = []
while name == []:
page = requests.get("http://www.baseball-reference.com/rand.fcgi")
tree = html.fromstring(page.content)
name = tree.xpath("//h1[@itemprop='name']/span/text()")
if len(name) > 0 and len(name[0]) == 4:
name = [] #gets rid of years
name = name[0]
return name
def get_real_players(num):
names = []
for i in range(0, num):
names.append(random_real_player())
players = {}
for name in names:
players[name] = json.loads(ono.get_stats(name))
return players

View file

@ -46,6 +46,9 @@
<Compile Include="games.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="real_players.py">
<SubType>Code</SubType>
</Compile>
<Compile Include="roman.py" />
<Compile Include="the_draft.py" />
<Compile Include="the_prestige.py" />

View file

@ -2,7 +2,7 @@ from collections import namedtuple
import games
import json
import uuid
import real_players
import onomancer
Participant = namedtuple('Participant', ['handle', 'team'])
@ -16,19 +16,22 @@ class Draft:
"""
@classmethod
def make_draft(cls, teamsize, draftsize, minsize, pitchers):
draft = cls(teamsize, draftsize, minsize, pitchers)
def make_draft(cls, teamsize, draftsize, minsize, pitchers, ono_ratio):
draft = cls(teamsize, draftsize, minsize, pitchers, ono_ratio)
return draft
def __init__(self, teamsize, draftsize, minsize, pitchers):
self.DRAFT_SIZE = draftsize
def __init__(self, teamsize, draftsize, minsize, pitchers, ono_ratio):
self.DRAFT_SIZE = int(draftsize * ono_ratio)
self.REAL_SIZE = draftsize - self.DRAFT_SIZE
self.REFRESH_DRAFT_SIZE = minsize # fewer players remaining than this and the list refreshes
self.DRAFT_ROUNDS = teamsize
self.pitchers = pitchers
self._id = str(uuid.uuid4())[:6]
self._participants = []
self._active_participant = BOOKMARK # draft mutex
self._players = onomancer.get_names(limit=self.DRAFT_SIZE)
nameslist = onomancer.get_names(limit=self.DRAFT_SIZE)
nameslist.update(real_players.get_real_players(self.REAL_SIZE))
self._players = nameslist
self._round = 0
@property
@ -68,7 +71,9 @@ class Draft:
self.advance_draft()
def refresh_players(self):
self._players = onomancer.get_names(limit=self.DRAFT_SIZE)
nameslist = onomancer.get_names(limit=self.DRAFT_SIZE)
nameslist.update(real_players.get_real_players(self.REAL_SIZE))
self._players = nameslist
def advance_draft(self):
"""

View file

@ -1,4 +1,4 @@
import discord, json, math, os, roman, games, asyncio, random, main_controller, threading, time, urllib, leagues, datetime, gametext
import discord, json, math, os, roman, games, asyncio, random, main_controller, threading, time, urllib, leagues, datetime, gametext, real_players
import database as db
import onomancer as ono
from league_storage import league_exists, season_save, season_restart
@ -646,6 +646,8 @@ class StartDraftCommand(Command):
draftsize = 20
minsize = 4
pitchers = 3
ono_ratio = 0.5
timeout = 120
for flag in flags:
try:
@ -657,10 +659,16 @@ class StartDraftCommand(Command):
minsize = int(flag[1])
elif flag[0] == "p":
pitchers = int(flag[1])
elif flag[0] == "c":
ono_ratio = float(flag[1])
if ono_ratio > 1 or ono_ratio < 0:
raise CommandError("The Chaos value needs to be between 0 and 1, chief. Probability has rules.")
elif flag[0] == "w": #wait
timeout = int(flag[1])
else:
raise CommandError(f"We don't recognize that {flag[0]} flag.")
except ValueError:
raise CommandError(f"Your {flag[0]} flag isn't a valid integer, boss.")
raise CommandError(f"Your {flag[0]} flag isn't a valid nummber, boss.")
if teamsize-pitchers > 20 or pitchers > 8:
raise CommandError("You can't fit that many players on a team, chief. Slow your roll.")
@ -669,7 +677,13 @@ class StartDraftCommand(Command):
if draftsize > 40:
raise CommandError("40 players is the max. We're not too confident about pushing for more.")
draft = Draft.make_draft(teamsize, draftsize, minsize, pitchers)
await msg.channel.send("Got it, boss. Give me a sec to find all the paperwork.")
try:
draft = Draft.make_draft(teamsize, draftsize, minsize, pitchers, ono_ratio)
except ConnectionError:
await msg.channel.send("Baseball Reference isn't playing nice. Could you try again for us in a minute or so?")
mentions = {f'<@!{m.id}>' for m in msg.mentions}
content = msg.content.split('\n')[1:] # drop command out of message
if not content or len(content) % 3:
@ -683,7 +697,7 @@ class StartDraftCommand(Command):
handle = mention
break
else:
await msg.channel.send(f"I don't recognize {handle_token}")
await msg.channel.send(f"I don't recognize {handle_token}.")
return
team_name = content[i + 1].strip()
if games.get_team(team_name):
@ -727,7 +741,7 @@ class StartDraftCommand(Command):
embed=build_draft_embed(draft.get_draftees(), footer=footer),
)
try:
draft_message = await self.wait_draft(msg.channel, draft)
draft_message = await self.wait_draft(msg.channel, draft, timeout)
draft.draft_player(f'<@!{draft_message.author.id}>', draft_message.content.split(' ', 1)[1])
except SlowDraftError:
player = random.choice(draft.get_draftees())
@ -777,7 +791,7 @@ class StartDraftCommand(Command):
return False
return False
async def wait_draft(self, channel, draft):
async def wait_draft(self, channel, draft, timeout):
def check(m):
if m.channel != channel:
@ -790,16 +804,16 @@ class StartDraftCommand(Command):
return False
try:
draft_message = await client.wait_for('message', timeout=120.0, check=check)
draft_message = await client.wait_for('message', timeout=timeout, check=check)
except asyncio.TimeoutError:
raise SlowDraftError('Too slow')
raise SlowDraftError('Too slow, boss.')
return draft_message
class StartLeagueCommand(Command):
name = "startleague"
template = "m;startleague [league name]\n[games per hour]"
description = """Optional flags for the first line: `--queue X` or `-q X` to play X number of series before stopping; `--noautopostseason` will pause the league before starting postseason.
description = """Optional flags for the first line: `--queue X` or `-q X` to play X number of series before stopping; `--autopostseason` will automatically start postseason at the end of the season.
Starts games from a league with a given name, provided that league has been saved on the website and has been claimed using claimleague. The games per hour sets how often the games will start (e.g. GPH 2 will start games at X:00 and X:30). By default it will play the entire season followed by the postseason and then stop but this can be customized using the flags.
Not every team will play every series, due to how the scheduling algorithm is coded but it will all even out by the end."""
@ -2095,6 +2109,16 @@ def build_team_embed(team):
def build_star_embed(player_json):
starkeys = {"batting_stars" : "Batting", "pitching_stars" : "Pitching", "baserunning_stars" : "Baserunning", "defense_stars" : "Defense"}
embed = discord.Embed(color=discord.Color.purple(), title=player_json["name"])
if player_json["name"] == "Tim Locastro": #the tim easter egg
for key in ["batting_stars", "pitching_stars", "baserunning_stars", "defense_stars"]:
#random star value between 0 and 6.5
stars = random.randint(0,6)
half_star = random.random() < 0.5 #half star addition
if half_star:
stars = half_star + 0.5
player_json[key] = stars
for key in starkeys.keys():
embedstring = ""
starstring = str(player_json[key])

View file

@ -57,6 +57,11 @@ class Weather:
def modify_game_end_message(self, game, state):
pass
def weather_report(self, game, state):
game.weather = random.choice(list(safe_weathers().values()))(game)
state["update_emoji"] = "🚌"
state["update_text"] += f" Weather report: {game.weather.name} {game.weather.emoji}"
class Supernova(Weather):
name = "Supernova"
@ -545,6 +550,18 @@ class LeafEddies(Weather):
if game.inning == 1:
state["weather_text"] = self.name
class Smog(Weather):
name = "Smog"
emoji = "🚌"
duration_range = [1,1]
def __init__(self, game):
game.random_weather_flag = True
setattr(game, "weather", random.choice(list(safe_weathers().values()))(game))
pass
def all_weathers():
weathers_dic = {
"Supernova" : Supernova,
@ -562,7 +579,26 @@ def all_weathers():
"Tornado" : Tornado,
"Torrential Downpour" : Downpour,
"Summer Mist" : SummerMist,
"Leaf Eddies" : LeafEddies
"Leaf Eddies" : LeafEddies,
"Smog" : Smog
}
return weathers_dic
def safe_weathers():
"""weathers safe to swap in mid-game"""
weathers_dic = {
"Supernova" : Supernova,
"Midnight": Midnight,
"Slight Tailwind": SlightTailwind,
"Twilight" : Twilight,
"Thinned Veil" : ThinnedVeil,
"Drizzle" : Drizzle,
"Breezy": Breezy,
"Starlight" : Starlight,
"Meteor Shower" : MeteorShower,
"Hurricane" : Hurricane,
"Tornado" : Tornado,
"Summer Mist" : SummerMist
}
return weathers_dic