Esempio n. 1
0
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)
Esempio n. 2
0
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)
Esempio n. 3
0
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)
Esempio n. 4
0
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)
Esempio n. 5
0
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)
Esempio n. 6
0
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)
Esempio n. 7
0
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)
Esempio n. 8
0
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)
Esempio n. 9
0
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)