def create_bot_summary(ld: LeagueDir): """ Create a json file with all information about the bots. Useful for casters. """ bots = load_all_bots(ld) rankings = RankingSystem.load(ld).ensure_all(list(bots.keys())) rank_list = rankings.as_sorted_list() def bot_data(bot_id): config = bots[bot_id] rank, mmr = [(i + 1, mrr) for i, (id, mrr, sigma) in enumerate(rank_list) if id == bot_id][0] return { "name": config.name, "developer": config.base_agent_config.get("Details", "developer"), "description": config.base_agent_config.get("Details", "description"), "fun_fact": config.base_agent_config.get("Details", "fun_fact"), "github": config.base_agent_config.get("Details", "github"), "language": config.base_agent_config.get("Details", "language"), "rank": rank, "mmr": mmr, } bot_summary = { defmt_bot_name(bot_id): bot_data(bot_id) for bot_id in bots.keys() } with open(ld.bot_summary, 'w') as f: json.dump(bot_summary, f, indent=4)
def parse_subcommand_ticket(args: List[str]): assert args[0] == "ticket" help_msg = """Usage: autoleague ticket get <bot_id> Get the number of tickets owned by <bot_id> autoleague ticket set <bot_id> <tickets> Set the number of tickets owned by <bot_id> autoleague ticket list Print list of number of tickets for all bots autoleague ticket newBotTickets <tickets> Set the number of tickets given to new bots""" ld = require_league_dir() if len(args) == 1 or args[1] == "help": print(help_msg) elif args[1] == "get" and len(args) == 3: bot = args[2] ticket_sys = TicketSystem.load(ld) tickets = ticket_sys.get(bot) if tickets: print(f"{bot} has {tickets} tickets") else: print( f"{bot} is not in the ticket system (counts as having {ticket_sys.new_bot_ticket_count} tickets)" ) elif args[1] == "set" and len(args) == 4: bot = args[2] tickets = int(args[3]) ticket_sys = TicketSystem.load(ld) ticket_sys.set(bot, tickets) ticket_sys.save(ld, make_timestamp()) print(f"Successfully set the number of tickets of {bot} to {tickets}") elif args[1] == "list" and len(args) == 2: bots = load_all_bots(ld) ticket_sys = TicketSystem.load(ld) ticket_sys.ensure(bots) tickets = list(ticket_sys.tickets.items()) tickets.sort(reverse=True, key=lambda elem: elem[1]) print(f"{'': <22} tickets") for bot_id, tickets in tickets: bar = "#" * tickets print(f"{defmt_bot_name(bot_id) + ' ':.<22} {tickets:>3} {bar}") print(f"\n{'TOTAL':<22} {ticket_sys.total()}") elif args[1] == "newBotTickets" and len(args) == 3: tickets = int(args[2]) # The number of tickets given to new bots are stored in LeagueSettings league_settings = LeagueSettings.load(ld) league_settings.new_bot_ticket_count = tickets league_settings.save(ld) else: print(help_msg)
def parse_subcommand_rank(args: List[str]): assert args[0] == "rank" help_msg = """Usage: autoleague rank list Print list of the current leaderboard""" ld = require_league_dir() if len(args) == 1 or args[1] == "help": print(help_msg) elif args[1] == "list" and len(args) == 2: bots = load_all_bots(ld) rank_sys = RankingSystem.load(ld) rank_sys.ensure_all(list(bots.keys())) rank_sys.print_ranks_and_mmr() else: print(help_msg)
def parse_subcommand_rank(args: List[str]): assert args[0] == "rank" help_msg = """Usage: autoleague rank list [showRetired] Print list of the current leaderboard""" ld = require_league_dir() if len(args) == 1 or args[1] == "help": print(help_msg) elif args[1] == "list" and (len(args) == 2 or len(args) == 3): show_retired = len(args) == 3 and bool(args[2]) exclude = [] if show_retired else load_retired_bots(ld) bots = load_all_bots(ld) rank_sys = RankingSystem.load(ld) rank_sys.ensure_all(list(bots.keys())) rank_sys.print_ranks_and_mmr(exclude) else: print(help_msg)
def parse_subcommand_bot(args: List[str]): assert args[0] == "bot" help_msg = """Usage: autoleague bot list Print list of all known bots autoleague bot test <bot_id> Run test match using a specific bot autoleague bot details <bot_id> Print details about the given bot autoleague bot unzip Unzip all bots in the bot directory autoleague bot summary Create json file with bot descriptions""" ld = require_league_dir() if len(args) == 1 or args[1] == "help": print(help_msg) elif args[1] == "list" and len(args) == 2: bot_configs = load_all_bots(ld) rank_sys = RankingSystem.load(ld) ticket_sys = TicketSystem.load(ld) bot_ids = list( set(bot_configs.keys()).union(set(rank_sys.ratings.keys())).union( set(ticket_sys.tickets.keys()))) print(f"{'': <22} c r t") for bot in sorted(bot_ids): c = "x" if bot in bot_configs else " " r = "x" if bot in rank_sys.ratings else " " t = "x" if bot in ticket_sys.tickets else " " print(f"{bot + ' ':.<22} {c} {r} {t}") elif args[1] == "test" and len(args) == 3: # Load bots = load_all_bots(ld) bot = args[2] if bot not in bots: print(f"Could not find the config file of '{bot}'") return # Run match = MatchMaker.make_test_match(bot) run_match(ld, match, bots, ReplayPreference.NONE) print(f"Test of '{bot}' complete") elif args[1] == "details" and len(args) == 3: bots = load_all_bots(ld) bot = args[2] if bot not in bots: print(f"Could not find the config file of '{bot}'") return print_details(bots[bot]) elif args[1] == "unzip" and len(args) == 2: print("Unzipping all bots:") unzip_all_bots(ld) elif args[1] == "summary" and len(args) == 2: create_bot_summary(ld) print("Bot summary created") else: print(help_msg)
def parse_subcommand_match(args: List[str]): assert args[0] == "match" help_msg = """Usage: autoleague match run Run a standard 3v3 soccer match autoleague match undo Undo the last match autoleague match list [n] Show the latest matches""" ld = require_league_dir() if len(args) == 1 or args[1] == "help": print(help_msg) elif args[1] == "run" and len(args) == 2: # Load bots = load_all_bots(ld) rank_sys = RankingSystem.load(ld) ticket_sys = TicketSystem.load(ld) # Run match = MatchMaker.make_next(bots, rank_sys, ticket_sys) result, replay = run_match(ld, match, bots, ReplayPreference.SAVE) rank_sys.update(match, result) match.result = result match.replay_id = replay.replay_id # Save match.save(ld) rank_sys.save(ld, match.time_stamp) ticket_sys.save(ld, match.time_stamp) # Print new ranks rank_sys.print_ranks_and_mmr() # Make summary league_settings = LeagueSettings.load(ld) make_summary(ld, league_settings.last_summary + 1) print( f"Created summary of the last {league_settings.last_summary + 1} matches." ) elif args[1] == "undo" and len(args) == 2: # Undo latest match ld = require_league_dir() latest_matches = MatchDetails.latest(ld, 1) if len(latest_matches) == 0: print("No matches to undo") else: latest_match = latest_matches[0] # Prompt user print(f"Latest match was {latest_match.name}") if prompt_yes_no( "Are you sure you want to undo the latest match?"): # Undo latest update to all systems RankingSystem.undo(ld) TicketSystem.undo(ld) MatchDetails.undo(ld) # New latest match new_latest_match = MatchDetails.latest(ld, 1) if new_latest_match: print(f"Reverted to {new_latest_match[0].name}") else: print("Reverted to beginning of league (no matches left)") elif args[1] == "list" and len(args) <= 3: count = 999999 if len(args) == 3: count = int(args[2]) # Show list of latest n matches played latest_matches = MatchDetails.latest(ld, count) if len(latest_matches) == 0: print("No matches have been played yet.") else: print(f"Match history (latest {len(latest_matches)} matches):") for match in latest_matches: print( f"{match.time_stamp}: {', '.join(match.blue) + ' ':.<46} {match.result.blue_goals} VS {match.result.orange_goals} {' ' + ', '.join(match.orange):.>46}" ) else: print(help_msg)
def parse_subcommand_retirement(args: List[str]): assert args[0] == "retirement" help_msg = """Usage: autoleague retirement list Print all bots in retirement autoleague retirement retire <bot> Retire a bot, removing it from play and the leaderboard autoleague retirement unretire <bot> Unretire a bot autoleague retirement retireall Retire all bots""" ld = require_league_dir() if len(args) == 1 or args[1] == "help": print(help_msg) elif args[1] == "list" and len(args) == 2: retired = load_retired_bots(ld) if len(retired) == 0: print("There are no bots in retirement") else: print("Retired bots:") for bot_id in sorted(retired): print(bot_id) elif args[1] == "retire" and len(args) == 3: bot = args[2] retired = load_retired_bots(ld) retired.add(bot) save_retired_bots(ld, retired) print(f"Retired {bot}") elif args[1] == "unretire" and len(args) == 3: bot = args[2] retired = load_retired_bots(ld) try: retired.remove(bot) save_retired_bots(ld, retired) print(f"Unretired {bot}") except KeyError: print(f"The bot {bot} is not in retirement") elif args[1] == "retireall" and len(args) == 2: bot_configs = load_all_bots(ld) rank_sys = RankingSystem.load(ld) ticket_sys = TicketSystem.load(ld) retired = load_retired_bots(ld) all_bots = set( bot_configs.keys()).union(set(rank_sys.ratings.keys())).union( set(ticket_sys.tickets.keys())).union(retired) save_retired_bots(ld, all_bots) count = len(all_bots) - len(retired) print(f"Retired {count} bots") else: print(help_msg)
def parse_subcommand_ticket(args: List[str]): assert args[0] == "ticket" help_msg = """Usage: autoleague ticket get <bot_id> Get the number of tickets owned by <bot_id> autoleague ticket set <bot_id> <tickets> Set the number of tickets owned by <bot_id> autoleague ticket list [showRetired] Print list of number of tickets for all bots autoleague ticket newBotTickets <tickets> Set the number of tickets given to new bots autoleague ticket ticketIncreaseRate <rate> Set the rate at which tickets increase autoleague ticket gameCatchupBoost <boost> Set the extra ticket increase factor when a bot has played fewer games""" ld = require_league_dir() if len(args) == 1 or args[1] == "help": print(help_msg) elif args[1] == "get" and len(args) == 3: bot = args[2] ticket_sys = TicketSystem.load(ld) tickets = ticket_sys.get(bot) if tickets: print(f"{bot} has {tickets} tickets") else: print( f"{bot} is not in the ticket system (counts as having {ticket_sys.new_bot_ticket_count} tickets)" ) elif args[1] == "set" and len(args) == 4: bot = args[2] tickets = int(args[3]) ticket_sys = TicketSystem.load(ld) ticket_sys.set(bot, tickets) ticket_sys.save(ld, make_timestamp()) print(f"Successfully set the number of tickets of {bot} to {tickets}") elif args[1] == "list" and (len(args) == 2 or len(args) == 3): show_retired = len(args) == 3 and bool(args[2]) retired = show_retired or load_retired_bots(ld) bots = load_all_bots(ld) ticket_sys = TicketSystem.load(ld) ticket_sys.ensure(bots) tickets = list(ticket_sys.tickets.items()) tickets.sort(reverse=True, key=lambda elem: elem[1]) total = 0 print(f"{'': <22} tickets") for bot_id, tickets in tickets: if show_retired or bot_id not in retired: total += int(tickets) bar = "#" * int(tickets) print( f"{defmt_bot_name(bot_id) + ' ':.<22} {int(tickets):>3} {bar}" ) print(f"\n{'TOTAL':<22} {total}") elif args[1] == "newBotTickets" and len(args) == 3: tickets = float(args[2]) if tickets < 1: print( "The number of tickets given to new bots must be 1.0 or greater" ) else: # The number-of-tickets-given-to-new-bots setting is stored in LeagueSettings league_settings = LeagueSettings.load(ld) league_settings.new_bot_ticket_count = tickets league_settings.save(ld) print(f"Updated number of tickets given to new bots to {tickets}") elif args[1] == "ticketIncreaseRate" and len(args) == 3: rate = float(args[2]) if rate < 1.0: print(f"The ticket increase rate must be 1.0 or greater") else: # The ticket-increase-rate setting is stored in LeagueSettings league_settings = LeagueSettings.load(ld) league_settings.ticket_increase_rate = rate league_settings.save(ld) print(f"Updated ticket increase rate to {rate}") elif args[1] == "gameCatchupBoost" and len(args) == 3: rate = float(args[2]) if rate < 0.0: print(f"The game catchup boost must be 0.0 or greater") else: # The ticket-increase-rate setting is stored in LeagueSettings league_settings = LeagueSettings.load(ld) league_settings.game_catchup_boost = rate league_settings.save(ld) print(f"Updated game catchup boost to {rate}") else: print(help_msg)
def make_summary(ld: LeagueDir, count: int): """ Make a summary of the N latest matches and the resulting ranks and tickets. If N is 0 the summary will just contain the current ratings. """ summary = {} tickets = TicketSystem.load(ld) # ========== Matches ========== matches = [] bot_wins = defaultdict( list) # Maps bots to list of booleans, where true=win and false=loss if count > 0: latest_matches = MatchDetails.latest(ld, count) for i, match in enumerate(latest_matches): matches.append({ "index": i, "blue_names": [defmt_bot_name(bot_id) for bot_id in match.blue], "orange_names": [defmt_bot_name(bot_id) for bot_id in match.orange], "blue_goals": match.result.blue_goals, "orange_goals": match.result.orange_goals, }) for bot in match.blue: bot_wins[bot].append( match.result.blue_goals > match.result.orange_goals) for bot in match.orange: bot_wins[bot].append( match.result.blue_goals < match.result.orange_goals) summary["matches"] = matches # ========= Ranks/Ratings ========= bots = load_all_bots(ld) bots_by_rank = [] if count <= 0: # Old rankings and current rankings is the same, but make sure all bots have a rank currently old_rankings = RankingSystem.load(ld).as_sorted_list() cur_rankings = RankingSystem.load(ld).ensure_all(list( bots.keys())).as_sorted_list() else: # Determine current rank and their to N matches ago n_rankings = RankingSystem.latest(ld, count + 1) old_rankings = n_rankings[0].as_sorted_list() cur_rankings = n_rankings[-1].ensure_all(list( bots.keys())).as_sorted_list() for i, (bot, mrr, sigma) in enumerate(cur_rankings): cur_rank = i + 1 old_rank = None old_mmr = None for j, (other_bot, other_mrr, _) in enumerate(old_rankings): if bot == other_bot: old_rank = j + 1 old_mmr = other_mrr break bots_by_rank.append({ "bot_id": defmt_bot_name(bot), "mmr": mrr, "old_mmr": old_mmr, "sigma": sigma, "cur_rank": cur_rank, "old_rank": old_rank, "tickets": tickets.get(bot) or tickets.new_bot_ticket_count, "wins": bot_wins[bot], }) summary["bots_by_rank"] = bots_by_rank # =========== Write ============= with open(PackageFiles.overlay_summary, 'w') as f: json.dump(summary, f, indent=4) league_settings = LeagueSettings.load(ld) league_settings.last_summary = count league_settings.save(ld)