Example #1
0
def load_board_from_game(agent_name: str, agent_version: int, game_number: int,
                         agent_file_path: Path) -> np.ndarray:
    """
    Constructs the final board from a game played by an agent.

    Parameters
    ----------
    agent_name : str
    agent_version : int
    game_number : int
    agent_file_path: Path

    Returns
    -------
    board : np.array
    """
    from connectn.game import initialize_game_state, apply_player_action
    from connectn.game import PLAYER1, PLAYER2

    game_record = get_game_for_agent(agent_name, agent_version, game_number,
                                     agent_file_path)
    moves = game_record["moves"].flatten()
    board = initialize_game_state()
    for i, move in enumerate(moves[moves > -1]):
        apply_player_action(board, move, PLAYER2 if i % 2 else PLAYER1)
    return board
Example #2
0
def full_board_p2():
    from connectn.game import initialize_game_state, PLAYER2

    board = initialize_game_state()
    board.fill(PLAYER2)
    return board
Example #3
0
def empty_board():
    from connectn.game import initialize_game_state

    return initialize_game_state()
Example #4
0
def run_single_game(agent_1: str,
                    agent_2: str,
                    game_seed: Optional[int] = None) -> GameResult:
    """
    Likely has to be replaced by separate function runnable via the GridEngine
    """
    from connectn import IS_DEBUGGING
    from queue import Empty as EmptyQueue
    from connectn.game import initialize_game_state, other_player
    from connectn.game import valid_player_action, apply_player_action
    from connectn.game import check_end_state, pretty_print_board
    from connectn.game import PLAYER1, PLAYER2, GameStatus

    logger = logging.getLogger(__name__)
    logger.debug(f"Entered run_single_game for {agent_1} vs {agent_2}")
    rs = np.random.RandomState(game_seed)

    agent_modules = import_agents({})
    agent_names = (agent_1, agent_2)

    def get_name(_player: BoardPiece) -> str:
        return agent_names[_player - 1]

    states = {agent_name: None for agent_name in agent_names}

    winner = player = NO_PLAYER
    agent_name = agent_1
    results = {PLAYER1: AgentResult(agent_1), PLAYER2: AgentResult(agent_2)}
    gr = GameResult(results[PLAYER1], results[PLAYER2])

    gen_move = {}
    for player, agent_name in zip((PLAYER1, PLAYER2), agent_names):
        try:
            gen_move[agent_name]: cu.GenMove = getattr(
                agent_modules[agent_name], "generate_move")
        except AttributeError:
            results[player].stderr.append(
                "\nYou did not define generate_move at the package level")
            gr.winner = other_player(player)
            results[player].outcome = "FAIL"
            results[gr.winner].outcome = "WIN"
            return gr
        except KeyError as e:
            # If this occurs and it isn't for agent_fail, then something has gone terribly wrong.
            # Presumably one of the agents is not defined in users.py
            logger.exception("Something has gone terribly wrong")
            raise e

    game_state = initialize_game_state()
    for player, agent_name in zip((PLAYER1, PLAYER2), agent_names):
        try:
            init = getattr(agent_modules[agent_name], "initialize")
            init(game_state.copy(), player)
        except (Exception, AttributeError):
            pass

    loser_result = "LOSS"
    try:
        logger.info(f"Playing game between {agent_1} and {agent_2}")
        moves_q = mp.Manager().Queue()

        end_state = GameStatus.STILL_PLAYING
        playing = True
        action = PlayerAction(0)
        while playing:
            for player, agent_name in zip((PLAYER1, PLAYER2), agent_names):
                move_seed = rs.randint(2**32)
                results[player].seeds.append(move_seed)

                gma = GenMoveArgs(move_seed, game_state.copy(), player,
                                  states[agent_name])
                moves_q.put(gma)
                if IS_DEBUGGING:
                    generate_move_process(gen_move[agent_name], moves_q)
                else:
                    ap = mp.Process(
                        target=generate_move_process,
                        args=(gen_move[agent_name], moves_q),
                    )
                    t0 = time.time()
                    ap.start()
                    ap.join(cu.MOVE_TIME_MAX)
                    move_time = time.time() - t0
                    if ap.is_alive():
                        ap.terminate()
                        loser_result = "TIMEOUT"
                        msg = f"Agent {agent_name} timed out after {cu.MOVE_TIME_MAX} seconds ({move_time:.1f}s)."
                        raise AgentFailed(msg)

                try:
                    ret: Union[GenMoveSuccess,
                               GenMoveFailure] = moves_q.get(block=True,
                                                             timeout=60.0)
                except EmptyQueue:
                    logger.exception(
                        "Timed out waiting to get move result from queue")
                    raise

                results[player].stdout.append(ret.stdout)
                results[player].stderr.append(ret.stderr)

                if isinstance(ret, GenMoveFailure):
                    loser_result = "EXCEPTION"
                    error_msg = ret.error_msg
                    msg = f"Agent {agent_name} threw an exception:\n {error_msg}"
                    raise AgentFailed(msg)

                assert isinstance(ret, GenMoveSuccess)
                action = ret.action
                state_size = cu.get_size(ret.state)

                results[player].move_times.append(ret.move_time)
                results[player].state_size.append(state_size)

                if state_size > cu.STATE_MEMORY_MAX:
                    loser_result = "MAX_STATE_MEM"
                    msg = f"Agent {agent_name} used {cu.mib(state_size):.2f} MiB > {cu.mib(cu.STATE_MEMORY_MAX)} MiB"
                    raise AgentFailed(msg)

                if not np.issubdtype(type(action), np.integer):
                    loser_result = "NONINT_ACTION"
                    msg = f"Agent {agent_name} returned an invalid type of action {type(action)}"
                    raise AgentFailed(msg)

                action = PlayerAction(action)
                results[player].moves.append(action)
                if not valid_player_action(game_state, action):
                    loser_result = "INVALID_ACTION"
                    msg = f"Agent {agent_name} returned an invalid action {action}"
                    raise AgentFailed(msg)

                apply_player_action(game_state, action, player)
                end_state = check_end_state(game_state, player)
                playing = end_state == GameStatus.STILL_PLAYING
                states[agent_name] = ret.state
                if not playing:
                    break

        if end_state == GameStatus.IS_WIN:
            winner = player
            logger.info(
                f"Game finished, {get_name(player)} beat {get_name(other_player(player))} by playing column {action}."
            )
        elif end_state == GameStatus.IS_DRAW:
            winner = NO_PLAYER
            logger.info("Game finished, no winner")
        else:
            logger.info(
                "Something went wrong, game-play stopped before the end state."
            )

    except AgentFailed as err:
        logger.info(pretty_print_board(game_state))
        logger.info(f"Agent failed: {agent_name}")
        logger.info(err)
        winner = other_player(player)
        results[player].stderr.append(str(err))

    # fig = plt.figure()
    # fig.suptitle('Odds of win')
    # for i, (agent, saved_state) in enumerate(states.items()):
    #     ax = fig.add_subplot(2, 1, i+1)
    #     for odds in saved_state.odds.values():
    #         ax.plot(odds, ('r', 'b')[i])
    #     ax.set_title(agent)
    #     ax.set_ylim(0, 1)
    #
    # fig = plt.figure()
    # fig.suptitle('Odds of draw')
    # for i, (agent, saved_state) in enumerate(states.items()):
    #     ax = fig.add_subplot(2, 1, i+1)
    #     for odds in saved_state.draw.values():
    #         ax.plot(odds, ('r', 'b')[i])
    #     ax.set_title(agent)
    #     ax.set_ylim(0, 1)
    #
    # fig = plt.figure()
    # for i, (agent, saved_state) in enumerate(states.items()):
    #     ax = fig.add_subplot(2, 1, i+1)
    #     ax.plot(saved_state.nodes, label='Nodes')
    #     ax.plot(saved_state.visits, label='Visits')
    #     ax.set_title(agent)
    #     ax.legend()
    #
    # fig = plt.figure()
    # fig.suptitle('Time')
    # for i, (agent, saved_state) in enumerate(states.items()):
    #     ax = fig.add_subplot(2, 1, i+1)
    #     ax.plot(saved_state.time, label=f'{np.mean(saved_state.time):.2f}')
    #     ax.set_title(agent)
    #     ax.legend()
    #
    # plt.show()

    # for i, (agent, saved_state) in enumerate(states.items()):
    #     print(
    #     f'TIME {agent} mu:{np.mean(saved_state.time):.2f},
    #     med:{np.median(saved_state.time):.2f}, max:{np.max(saved_state.time):.2f}'
    #     )

    gr.winner = winner
    if winner == NO_PLAYER:
        results[PLAYER1].outcome = results[PLAYER2].outcome = "DRAW"
    else:
        results[PLAYER1 if winner == PLAYER1 else PLAYER2].outcome = "WIN"
        results[PLAYER2 if winner ==
                PLAYER1 else PLAYER1].outcome = loser_result

    logger.debug(f"Finished run_single_game for {agent_1} vs {agent_2}")

    return gr