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
def full_board_p2(): from connectn.game import initialize_game_state, PLAYER2 board = initialize_game_state() board.fill(PLAYER2) return board
def empty_board(): from connectn.game import initialize_game_state return initialize_game_state()
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