def run_match(
    ld: LeagueDir, match_details: MatchDetails,
    bots: Mapping[BotID, BotConfigBundle], replay_preference: ReplayPreference
) -> Tuple[MatchResult, Optional[ReplayData]]:
    """
    Run a match, wait for it to finish, and return the result.
    """

    with setup_manager_context() as setup_manager:

        # Expose data to overlay
        make_overlay(ld, match_details, bots)

        # Prepare the match exercise
        print(
            f"Starting match: {match_details.blue} vs {match_details.orange}. Waiting for match to finish..."
        )
        match = MatchExercise(name=match_details.name,
                              match_config=match_details.to_config(bots),
                              grader=MatchGrader(replay_monitor=ReplayMonitor(
                                  replay_preference=replay_preference), ))

        # If any bots have signed up for early start, give them 10 seconds.
        # This is typically enough for Scratch.
        setup_manager.early_start_seconds = 10

        # For loop, but should only run exactly once
        for exercise_result in run_playlist(
            [match],
                setup_manager=setup_manager,
                render_policy=RenderPolicy.DEFAULT):

            replay_data = None

            # Warn if no replay was found
            replay_data = exercise_result.exercise.grader.replay_monitor.replay_data(
            )
            if isinstance(exercise_result.grade,
                          Fail) and replay_data.replay_id is None:
                print(
                    f"WARNING: No replay was found for the match '{match_details.name}'."
                )
            else:
                if replay_preference != ReplayPreference.NONE and replay_data.replay_path is not None:
                    try:
                        dst = ld.replays / f"{replay_data.replay_id}.replay"
                        shutil.copy(replay_data.replay_path, dst)
                        print(
                            "Replay successfully copied to replays directory")
                    except:
                        pass

            match_result = confirm_match_result(
                exercise_result.exercise.grader.match_result)
            return match_result, replay_data
Exemple #2
0
    def load(ld: LeagueDir) -> 'TicketSystem':
        ticket_sys = TicketSystem()
        if any(ld.tickets.iterdir()):
            # Assume last tickets file is the newest, since they are prefixed with a time stamp
            with open(list(ld.tickets.iterdir())[-1]) as f:
                ticket_sys.tickets = json.load(f)

        settings = LeagueSettings.load(ld)
        ticket_sys.new_bot_ticket_count = settings.new_bot_ticket_count
        ticket_sys.ticket_increase_rate = settings.ticket_increase_rate
        ticket_sys.game_catchup_boost = settings.game_catchup_boost

        matches_in_session = MatchDetails.latest(ld, settings.last_summary)
        for match in matches_in_session:
            bots = match.blue + match.orange
            ticket_sys.ensure(bots)
            for bot_id in bots:
                ticket_sys.session_game_counts[bot_id] += 1

        return ticket_sys
Exemple #3
0
    def make_next(bots: Mapping[BotID,
                                BotConfigBundle], rank_sys: RankingSystem,
                  ticket_sys: TicketSystem) -> MatchDetails:
        """
        Make the next match to play. This will use to TicketSystem and the RankingSystem to find
        a fair match between some bots that haven't played for a while. It is assumed that the match
        is guaranteed to finish (since the TicketSystem is updated).
        """

        time_stamp = make_timestamp()
        blue, orange = MatchMaker.decide_on_players(bots.keys(), rank_sys,
                                                    ticket_sys)
        name = "_".join([time_stamp] + blue + ["vs"] + orange)
        map = choice([
            "ChampionsField",
            "DFHStadium",
            "NeoTokyo",
            "ChampionsField",
            "UrbanCentral",
            "BeckwithPark",
        ])
        return MatchDetails(time_stamp, name, blue, orange, map)
from pathlib import Path

from matplotlib.colors import ListedColormap

from match import MatchDetails
from paths import LeagueDir
from ranking_system import RankingSystem
from settings import PersistentSettings

settings = PersistentSettings.load()
ld = LeagueDir(Path(settings.league_dir_raw))

ranks = RankingSystem.latest(ld, 1)[0]
bots = sorted(ranks.ratings.keys(), key=lambda bot: -ranks.get_mmr(bot))
N = len(bots)
matches = MatchDetails.all(ld)

win_rate = np.full((N, N), -0.01)
for i in range(N):
    for j in range(N):
        if i < j:
            wins_i = 0
            wins_j = 0
            for match in matches:
                if bots[i] in match.blue and bots[j] in match.orange:
                    if match.result.blue_goals > match.result.orange_goals:
                        wins_i += 1
                    else:
                        wins_j += 1
                elif bots[j] in match.blue and bots[i] in match.orange:
                    if match.result.blue_goals < match.result.orange_goals:
Exemple #5
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_unretired_bots(ld)
    retired = load_retired_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(exclude=retired)
        cur_rankings = RankingSystem.load(ld).ensure_all(list(bots.keys())).as_sorted_list(exclude=retired)
    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(exclude=retired)
        cur_rankings = n_rankings[-1].ensure_all(list(bots.keys())).as_sorted_list(exclude=retired)

    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)
Exemple #6
0
 def make_test_match(bot_id: BotID) -> MatchDetails:
     allstar_config = get_bot_config_bundle(PackageFiles.psyonix_allstar)
     allstar_id = fmt_bot_name(allstar_config.name)
     team = [bot_id, allstar_id, allstar_id]
     return MatchDetails("", f"test_{bot_id}", team, team, "ChampionsField")
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 run_match(
    ld: LeagueDir, match_details: MatchDetails,
    bots: Mapping[BotID, BotConfigBundle], replay_preference: ReplayPreference
) -> Tuple[MatchResult, Optional[ReplayData]]:
    """
    Run a match, wait for it to finish, and return the result.
    """

    settings = PersistentSettings.load()

    with setup_manager_context(settings.launcher()) as setup_manager:

        # Expose data to overlay
        make_overlay(ld, match_details, bots)

        # Prepare the match exercise
        print(
            f"Starting match: {match_details.blue} vs {match_details.orange}. Waiting for match to finish..."
        )
        match = MatchExercise(name=match_details.name,
                              match_config=match_details.to_config(bots),
                              grader=MatchGrader(replay_monitor=ReplayMonitor(
                                  replay_preference=replay_preference), ))

        # If any bots have signed up for early start, give them 10 seconds.
        # This is typically enough for Scratch.
        setup_manager.early_start_seconds = 10

        # For loop, but should only run exactly once
        with use_or_create(setup_manager,
                           setup_manager_context) as setup_manager:
            wrapped_exercises = [TrainingExerciseAdapter(match)]

            for rlbot_result in run_exercises(setup_manager,
                                              wrapped_exercises,
                                              4,
                                              reload_agent=False):
                exercise_result = ExerciseResult(
                    grade=rlbot_result.grade,
                    exercise=rlbot_result.exercise.
                    exercise,  # unwrap the TrainingExerciseAdapter.
                    reproduction_info=None)

                # Warn if no replay was found
                replay_data = exercise_result.exercise.grader.replay_monitor.replay_data(
                )
                if isinstance(exercise_result.grade,
                              Fail) and replay_data.replay_id is None:
                    print(
                        f"WARNING: No replay was found for the match '{match_details.name}'."
                    )
                else:
                    if replay_preference != ReplayPreference.NONE and replay_data.replay_path is not None:
                        try:
                            dst = ld.replays / f"{replay_data.replay_id}.replay"
                            shutil.copy(replay_data.replay_path, dst)
                            print(
                                "Replay successfully copied to replays directory"
                            )
                        except:
                            pass

                match_result = exercise_result.exercise.grader.match_result
                return match_result, replay_data