From 333476548d1cb38b675e8dce5df6045f019a392e Mon Sep 17 00:00:00 2001 From: Sakimori Date: Thu, 14 Jan 2021 23:39:08 -0500 Subject: [PATCH] standings and wildcard commands added --- leagues.py | 67 +++++++++++++++-- the_prestige.py | 196 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 196 insertions(+), 67 deletions(-) diff --git a/leagues.py b/leagues.py index dfb9c3a..9356d45 100644 --- a/leagues.py +++ b/leagues.py @@ -13,6 +13,7 @@ class league_structure(object): self.historic = False self.owner = None self.season = 1 + self.autoplay = -1 def setup(self, league_dic, division_games = 1, inter_division_games = 1, inter_league_games = 1, games_per_hour = 2): self.league = league_dic # { subleague name : { division name : [team object] } } @@ -182,6 +183,22 @@ class league_structure(object): scheduled = True day += 1 + def division_standings(self, division, standings): + def sorter(team_in_list): + if team_in_list[2] == 0 and team_in_list[1] == 0: + return (0, team_in_list[3]) + return (team_in_list[1]/(team_in_list[1]+team_in_list[2]), team_in_list[3]) + + teams = division.copy() + + for index in range(0, len(teams)): + this_team = teams[index] + teams[index] = [this_team, standings[teams[index].name]["wins"], standings[teams[index].name]["losses"], standings[teams[index].name]["run_diff"], 0] + + teams.sort(key=sorter, reverse=True) + return teams + + def standings_embed(self): this_embed = Embed(color=Color.purple(), title=self.name) standings = {} @@ -191,21 +208,54 @@ class league_structure(object): this_embed.add_field(name="Subleague:", value=f"**{subleague}**", inline = False) for division in iter(self.league[subleague].keys()): this_embed.add_field(name="Division:", value=f"**{division}**", inline = False) - teams = self.league[subleague][division].copy() - for index in range(0, len(teams)): - this_team = teams[index] - teams[index] = (this_team, standings[teams[index].name]["wins"], standings[teams[index].name]["losses"], standings[teams[index].name]["run_diff"],) + teams = self.division_standings(self.league[subleague][division], standings) - def sorter(team_in_list): - return (team_in_list[1], team_in_list[3]) - teams.sort(key=sorter, reverse=True) + for index in range(0, len(teams)): + if index == self.constraints["division_leaders"] - 1: + teams[index][4] = "-" + else: + games_behind = ((teams[self.constraints["division_leaders"] - 1][1] - teams[index][1]) + (teams[index][2] - teams[self.constraints["division_leaders"] - 1][2]))/2 + teams[index][4] = games_behind for this_team in teams: - this_embed.add_field(name=this_team[0].name, value=f"{this_team[1]} - {this_team[2]} Diff: {this_team[3]}", inline = False) + if this_team[2] != 0 or this_team[1] != 0: + this_embed.add_field(name=this_team[0].name, value=f"{this_team[1]} - {this_team[2]} WR: {round(this_team[1]/(this_team[1]+this_team[2]), 3)} GB: {this_team[4]}", inline = False) + else: + this_embed.add_field(name=this_team[0].name, value=f"{this_team[1]} - {this_team[2]} WR: - GB: {this_team[4]}", inline = False) this_embed.set_footer(text=f"Standings as of day {self.day-1}") return this_embed + def wildcard_embed(self): + this_embed = Embed(color=Color.purple(), title=f"{self.name} Wildcard Race") + standings = {} + for team_name, wins, losses, run_diff in league_db.get_standings(self.name): + standings[team_name] = {"wins" : wins, "losses" : losses, "run_diff" : run_diff} + for subleague in iter(self.league.keys()): + this_embed.add_field(name="Subleague:", value=f"**{subleague}**", inline = False) + subleague_array = [] + for division in iter(self.league[subleague].keys()): + this_div = [this_team for this_team, wins, losses, diff, gb in self.division_standings(self.league[subleague][division], standings)[self.constraints["division_leaders"]:]] + subleague_array += this_div + + teams = self.division_standings(subleague_array, standings) + + for index in range(0, len(teams)): + if index == self.constraints["wild_cards"] - 1: + teams[index][4] = "-" + else: + games_behind = ((teams[self.constraints["wild_cards"] - 1][1] - teams[index][1]) + (teams[index][2] - teams[self.constraints["wild_cards"] - 1][2]))/2 + teams[index][4] = games_behind + + for this_team in teams: + if this_team[2] != 0 or this_team[1] != 0: + this_embed.add_field(name=this_team[0].name, value=f"{this_team[1]} - {this_team[2]} WR: {round(this_team[1]/(this_team[1]+this_team[2]), 3)} GB: {this_team[4]}", inline = False) + else: + this_embed.add_field(name=this_team[0].name, value=f"{this_team[1]} - {this_team[2]} WR: - GB: {this_team[4]}", inline = False) + + this_embed.set_footer(text=f"Wildcard standings as of day {self.day-1}") + return this_embed + class tournament(object): def __init__(self, name, team_dic, series_length = 5, finals_series_length = 7, max_innings = 9, id = None, secs_between_games = 300, secs_between_rounds = 600): self.name = name @@ -330,6 +380,7 @@ def load_league_file(league_name): this_league.day = state_dic["day"] this_league.schedule = state_dic["schedule"] + this_league.constraints = state_dic["constraints"] this_league.game_length = state_dic["game_length"] this_league.series_length = state_dic["series_length"] this_league.owner = state_dic["owner"] diff --git a/the_prestige.py b/the_prestige.py index c34fc97..21cc57b 100644 --- a/the_prestige.py +++ b/the_prestige.py @@ -562,7 +562,12 @@ class StartTournamentCommand(Command): if team == None: await msg.channel.send(f"We couldn't find {name}. Try again?") return - team_dic[team] = {"wins": 0} + add = True + for extant_team in team_dic.keys(): + if extant_team.name == team.name: + add = False + if add: + team_dic[team] = {"wins": 0} channel = msg.channel await msg.delete() @@ -754,26 +759,39 @@ class DebugLeagueDisplay(Command): class StartLeagueCommand(Command): name = "startleague" - template = "m;startleague [league name]" - description = """Optional flag: `--queue X` or `-q X` to play X number of series before stopping. -Plays a league with a given name, provided that league has been saved on the website.""" + template = "m;startleague [league name]\n[games per hour]" + description = """Optional flag for the first line: `--queue X` or `-q X` to play X number of series before stopping. +Plays a league with a given name, provided that league has been saved on the website. The games per hour sets how often the games will start. (e.g. GPH 2 will start games at X:00 and X:30)""" async def execute(self, msg, command): - league_name = command.split("-")[0].strip() + league_name = command.split("-")[0].split("\n")[0].strip() autoplay = None - try: + + try: if "--queue " in command: - autoplay = int(command.split("--queue ")[1]) + autoplay = int(command.split("--queue ")[1].split("\n")[0]) elif "-q " in command: - autoplay = int(command.split("-q ")[1]) + autoplay = int(command.split("-q ")[1].split("\n")[0]) if autoplay is not None and autoplay <= 0: raise ValueError elif autoplay is None: autoplay = -1 - except: + command = command.split("\n")[1] + except ValueError: await msg.channel.send("Sorry boss, the queue flag needs a natural number. Any whole number over 0 will do just fine.") return + except IndexError: + await msg.channel.send("We need a games per hour number in the second line.") + return + + try: + gph = int(command.strip()) + if gph < 1 or gph > 12: + raise ValueError + except ValueError: + await msg.channel.send("Chief, we need a games per hour number between 1 and 12. We think that's reasonable.") + return if league_exists(league_name): league = leagues.load_league_file(league_name) @@ -784,10 +802,50 @@ Plays a league with a given name, provided that league has been saved on the web if active_league.name == league.name: await msg.channel.send("That league is already running, boss. Patience is a virtue, you know.") return - await start_league_day(msg.channel, league, autoplay = autoplay) + league.autoplay = autoplay + league.games_per_hour = gph + await start_league_day(msg.channel, league) else: await msg.channel.send("Couldn't find that league, boss. Did you save it on the website?") +class LeagueDisplayCommand(Command): + name = "leaguestandings" + template = "m;leaguestandings [league name]" + description = "Displays the current standings for the given league." + + async def execute(self, msg, command): + if league_exists(command.strip()): + league = leagues.load_league_file(command.strip()) + await msg.channel.send(embed=league.standings_embed()) + else: + await msg.channel.send("Can't find that league, boss.") + +class LeagueWildcardCommand(Command): + name = "leaguewildcard" + template = "m;leaguewildcard [league name]" + description = "Displays the current wildcard race for the given league, if the league has wildcard slots." + + async def execute(self, msg, command): + if league_exists(command.strip()): + league = leagues.load_league_file(command.strip()) + if league.constraints["wild_cards"] > 0: + await msg.channel.send(embed=league.wildcard_embed()) + else: + await msg.channel.send("That league doesn't have wildcards, boss.") + else: + await msg.channel.send("Can't find that league, boss.") + +class LeaguePauseCommand(Command): + name = "pauseleague" + template = "m;pauseleague [league name]" + descripton = "Tells a currently running league to stop running automatically after the current series." + + async def execute(self, msg, command): + league_name = command.strip() + for active_league in active_leagues: + if active_league.name == league_name: + active_league.autoplay = 0 + await msg.channel.send(f"Loud and clear, chief. {league_name} will stop after this series is over.") commands = [ IntroduceCommand(), CountActiveGamesCommand(), @@ -809,6 +867,9 @@ commands = [ StartGameCommand(), StartTournamentCommand(), StartLeagueCommand(), + LeaguePauseCommand(), + LeagueDisplayCommand(), + LeagueWildcardCommand(), StartRandomGameCommand(), CreditCommand(), RomanCommand(), @@ -1152,7 +1213,7 @@ async def tourney_round_watcher(channel, tourney, games_list, filter_url, finals try: for i in range(0, len(games_list)): game, key = games_list[i] - if game.over and main_controller.master_games_dic[key][1]["end_delay"] <= 8: + if game.over and ((key in main_controller.master_games_dic.keys() and main_controller.master_games_dic[key][1]["end_delay"] <= 8) or not key in main_controller.master_games_dic.keys()): if game.teams['home'].name not in wins_in_series.keys(): wins_in_series[game.teams["home"].name] = 0 if game.teams['away'].name not in wins_in_series.keys(): @@ -1406,7 +1467,7 @@ async def game_watcher(): this_array = gamesarray.copy() for i in range(0,len(this_array)): game, channel, user, key = this_array[i] - if game.over and main_controller.master_games_dic[key][1]["end_delay"] <= 8: + if game.over and ((key in main_controller.master_games_dic.keys() and main_controller.master_games_dic[key][1]["end_delay"] <= 8) or not key in main_controller.master_games_dic.keys()): final_embed = game_over_embed(game) if isinstance(user, str): await channel.send(f"A game started by {user} just ended.") @@ -1452,7 +1513,7 @@ def get_team_fuzzy_search(team_name): team = teams[0] return team -async def start_league_day(channel, league, autoplay = 1): +async def start_league_day(channel, league): current_games = [] games_to_start = league.schedule[str(league.day_to_series_num(league.day))] @@ -1490,12 +1551,12 @@ async def start_league_day(channel, league, autoplay = 1): await channel.send(f"The day {league.day} series of the {league.name} is starting now, at {config()['simmadome_url']+ext}") last = False - await league_day_watcher(channel, league, current_games, config()['simmadome_url']+ext, autoplay, last) + await league_day_watcher(channel, league, current_games, config()['simmadome_url']+ext, last) -async def league_day_watcher(channel, league, games_list, filter_url, autoplay, last = False): +async def league_day_watcher(channel, league, games_list, filter_url, last = False): league.active = True - autoplay -= 1 + league.autoplay -= 1 if league not in active_leagues: active_leagues.append(league) series_results = {} @@ -1503,49 +1564,50 @@ async def league_day_watcher(channel, league, games_list, filter_url, autoplay, while league.active: queued_games = [] while len(games_list) > 0: - #try: - for i in range(0, len(games_list)): - game, key = games_list[i] - if game.over and main_controller.master_games_dic[key][1]["end_delay"] <= 8: - if game.teams['home'].name not in series_results.keys(): - series_results[game.teams["home"].name] = {} - series_results[game.teams["home"].name]["wins"] = 0 - series_results[game.teams["home"].name]["losses"] = 0 - series_results[game.teams["home"].name]["run_diff"] = 0 - if game.teams['away'].name not in series_results.keys(): - series_results[game.teams["away"].name] = {} - series_results[game.teams["away"].name]["wins"] = 0 - series_results[game.teams["away"].name]["losses"] = 0 - series_results[game.teams["away"].name]["run_diff"] = 0 + try: + for i in range(0, len(games_list)): + game, key = games_list[i] + if game.over and ((key in main_controller.master_games_dic.keys() and main_controller.master_games_dic[key][1]["end_delay"] <= 8) or not key in main_controller.master_games_dic.keys()): + if game.teams['home'].name not in series_results.keys(): + series_results[game.teams["home"].name] = {} + series_results[game.teams["home"].name]["wins"] = 0 + series_results[game.teams["home"].name]["losses"] = 0 + series_results[game.teams["home"].name]["run_diff"] = 0 + if game.teams['away'].name not in series_results.keys(): + series_results[game.teams["away"].name] = {} + series_results[game.teams["away"].name]["wins"] = 0 + series_results[game.teams["away"].name]["losses"] = 0 + series_results[game.teams["away"].name]["run_diff"] = 0 - winner_name = game.teams['home'].name if game.teams['home'].score > game.teams['away'].score else game.teams['away'].name - loser_name = game.teams['away'].name if game.teams['home'].score > game.teams['away'].score else game.teams['home'].name - rd = int(math.fabs(game.teams['home'].score - game.teams['away'].score)) + winner_name = game.teams['home'].name if game.teams['home'].score > game.teams['away'].score else game.teams['away'].name + loser_name = game.teams['away'].name if game.teams['home'].score > game.teams['away'].score else game.teams['home'].name + rd = int(math.fabs(game.teams['home'].score - game.teams['away'].score)) - series_results[winner_name]["wins"] += 1 - series_results[winner_name]["run_diff"] += rd + series_results[winner_name]["wins"] += 1 + series_results[winner_name]["run_diff"] += rd - winner_dic = {"wins" : 1, "run_diff" : rd} + winner_dic = {"wins" : 1, "run_diff" : rd} - series_results[loser_name]["losses"] += 1 - series_results[loser_name]["run_diff"] -= rd + series_results[loser_name]["losses"] += 1 + series_results[loser_name]["run_diff"] -= rd - loser_dic = {"losses" : 1, "run_diff" : -rd} + loser_dic = {"losses" : 1, "run_diff" : -rd} - league.add_stats_from_game(game.get_team_specific_stats()) - league.update_standings({winner_name : winner_dic, loser_name : loser_dic}) - leagues.save_league(league) - final_embed = game_over_embed(game) - final_embed.add_field(name="Series score:", value=f"{series_results[game.teams['away'].name]['wins']} - {series_results[game.teams['home'].name]['wins']}") - await channel.send(f"A {league.name} game just ended!") - await channel.send(embed=final_embed) - if series_results[winner_name]["wins"] + series_results[winner_name]["losses"] < league.series_length: - queued_games.append(game) - games_list.pop(i) - break - #except: - #print("something went wrong in league_day_watcher") - await asyncio.sleep(1) + league.add_stats_from_game(game.get_team_specific_stats()) + league.update_standings({winner_name : winner_dic, loser_name : loser_dic}) + leagues.save_league(league) + final_embed = game_over_embed(game) + final_embed.add_field(name="Day:", value=league.day) + final_embed.add_field(name="Series score:", value=f"{series_results[game.teams['away'].name]['wins']} - {series_results[game.teams['home'].name]['wins']}") + await channel.send(f"A {league.name} game just ended!") + await channel.send(embed=final_embed) + if series_results[winner_name]["wins"] + series_results[winner_name]["losses"] < league.series_length: + queued_games.append(game) + games_list.pop(i) + break + except: + print("something went wrong in league_day_watcher") + await asyncio.sleep(2) league.day += 1 if len(queued_games) > 0: @@ -1555,8 +1617,16 @@ async def league_day_watcher(channel, league, games_list, filter_url, autoplay, validminutes = [int((60 * div)/league.games_per_hour) for div in range(0,league.games_per_hour)] for i in range(0, len(validminutes)): if now.minute > validminutes[i]: - if i <= len(validminutes)-2: - delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute)) + if i <= len(validminutes)-3: + if validminutes[i+1] == now.minute: + delta = datetime.timedelta(minutes= (validminutes[i+2] - now.minute)) + else: + delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute)) + elif i <= len(validminutes)-2: + if validminutes[i+1] == now.minute: + delta = datetime.timedelta(minutes= (60 - now.minute)) + else: + delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute)) else: delta = datetime.timedelta(minutes= (60 - now.minute)) @@ -1576,7 +1646,7 @@ async def league_day_watcher(channel, league, games_list, filter_url, autoplay, - if last or autoplay == 0: #if this series was the last of the season OR number of series to autoplay has been reached + if last or league.autoplay == 0: #if this series was the last of the season OR number of series to autoplay has been reached await channel.send(embed=league.standings_embed()) await channel.send(f"The {league.name} is no longer autoplaying.") leagues.save_league(league) @@ -1588,8 +1658,16 @@ async def league_day_watcher(channel, league, games_list, filter_url, autoplay, validminutes = [int((60 * div)/league.games_per_hour) for div in range(0,league.games_per_hour)] for i in range(0, len(validminutes)): if now.minute > validminutes[i]: - if i < len(validminutes)-2: - delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute)) + if i <= len(validminutes)-3: + if validminutes[i+1] == now.minute: + delta = datetime.timedelta(minutes= (validminutes[i+2] - now.minute)) + else: + delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute)) + elif i <= len(validminutes)-2: + if validminutes[i+1] == now.minute: + delta = datetime.timedelta(minutes= (60 - now.minute)) + else: + delta = datetime.timedelta(minutes= (validminutes[i+1] - now.minute)) else: delta = datetime.timedelta(minutes= (60 - now.minute)) @@ -1601,7 +1679,7 @@ async def league_day_watcher(channel, league, games_list, filter_url, autoplay, await channel.send(f"""This {league.name} series is now complete! The next series will be starting in {int(wait_seconds/60)} minutes.""") await asyncio.sleep(wait_seconds) - await start_league_day(channel, league, autoplay) + await start_league_day(channel, league) async def continue_league_series(league, queue, games_list, series_results): for oldgame in queue: