def alpha_beta_result(game_state: GameState, max_depth: int, best_black: int, best_white: int, eval_fn: Callable) -> int: if game_state.is_over(): return MAX_SCORE if game_state.winner( ) == game_state.next_player else MIN_SCORE if max_depth == 0: return eval_fn(game_state) best_so_far = MIN_SCORE for candidate_move in game_state.legal_moves(): next_state = game_state.apply_move(candidate_move) opponent_best_result = alpha_beta_result(next_state, max_depth - 1, best_black, best_white, eval_fn) our_result = -opponent_best_result if our_result > best_so_far: best_so_far = our_result if game_state.next_player == Player.WHITE: if best_so_far > best_white: best_white = best_so_far outcome_for_black = -best_so_far if outcome_for_black < best_black: return best_so_far elif game_state.next_player == Player.BLACK: if best_so_far > best_black: best_black = best_so_far outcome_for_white = -best_so_far if outcome_for_white < best_white: return best_so_far return best_so_far
def select_move(self, game_state: GameState): best_moves: List[Move] = [] best_score = MIN_SCORE best_black = MIN_SCORE best_white = MIN_SCORE for possible_move in game_state.legal_moves(): next_state = game_state.apply_move(possible_move) # Since our opponent plays next, figure out their best # possible outcome from there. opponent_best_outcome = alpha_beta_result(next_state, self.max_depth, best_black, best_white, self.eval_fn) # Our outcome is the opposite of our opponent's outcome. our_best_outcome = -opponent_best_outcome if len(best_moves) == 0 or our_best_outcome > best_score: # This is the best move so far. best_moves = [possible_move] best_score = our_best_outcome if game_state.next_player == Player.BLACK: best_black = best_score elif game_state.next_player == Player.WHITE: best_white = best_score elif our_best_outcome == best_score: # This is as good as our previous best move. best_moves.append(possible_move) # For variety, randomly select among all equally good moves. return random.choice(best_moves)
def best_result(game_state: GameState, max_depth: int, eval_fn: Callable): if game_state.is_over(): return MAX_SCORE if game_state.winner( ) == game_state.next_player else MIN_SCORE if max_depth == 0: return eval_fn(game_state) best_so_far = MIN_SCORE for candidate_move in game_state.legal_moves(): next_state = game_state.apply_move(candidate_move) opponent_best_result = best_result(next_state, max_depth - 1, eval_fn) our_result = -1 * opponent_best_result if our_result > best_so_far: best_so_far = our_result return best_so_far
def best_result(game_state: GameState) -> GameResult: if game_state.is_over(): if game_state.winner() == game_state.next_player: return GameResult.Win elif game_state.winner() is None: return GameResult.Draw else: return GameResult.Loss best_result_so_far = GameResult.Loss for candidate_move in game_state.legal_moves(): next_state = game_state.apply_move(candidate_move) opponent_best_result = best_result(next_state) our_result = reverse_game_result(opponent_best_result) if our_result.value > best_result_so_far.value: best_result_so_far = our_result return best_result_so_far
def select_move(self, game_state: GameState) -> Move: best_moves: List[Move] = [] best_score = None # Loop over all legal moves. for possible_move in game_state.legal_moves(): # Calculate the game state if we select this move. next_state = game_state.apply_move(possible_move) # Since our opponent plays next, figure out their best # possible outcome from there. opponent_best_outcome = best_result(next_state, self.max_depth, self.eval_fn) # Our outcome is the opposite of our opponent's outcome. our_best_outcome = -1 * opponent_best_outcome if (not best_moves) or our_best_outcome > best_score: # This is the best move so far. best_moves = [possible_move] best_score = our_best_outcome elif our_best_outcome == best_score: # This is as good as our previous best move. best_moves.append(possible_move) # For variety, randomly select among all equally good moves. return random.choice(best_moves)
def select_move(self, game_state: GameState) -> Move: winning_moves: List[Move] = [] draw_moves: List[Move] = [] losing_moves: List[Move] = [] for possible_move in game_state.legal_moves(): next_state = game_state.apply_move(possible_move) opponent_best_outcome = best_result(next_state) our_best_outcome = reverse_game_result(opponent_best_outcome) if our_best_outcome == GameResult.Win: winning_moves.append(possible_move) elif our_best_outcome == GameResult.Draw: draw_moves.append(possible_move) else: losing_moves.append(possible_move) if len(winning_moves) > 0: return random.choice(winning_moves) elif len(draw_moves) > 0: return random.choice(draw_moves) else: return random.choice(losing_moves)
def main(): game = GameState.new_game(BOARD_SIZE) bot = DepthPrunedAgent(2, capture_diff) while not game.is_over(): print_board(game.board) if game.next_player == Player.BLACK: human_move = input("-- ") point = point_from_coordinate(human_move.strip()) move = Move.play(point) else: move = bot.select_move(game) print_move(game.next_player, move) game = game.apply_move(move)
def select_move(self, game_state: GameState) -> Move: """ Choose a random valid move that preserves our own eyes. """ candidates = [] for r in range(1, game_state.board.num_rows + 1): for c in range(1, game_state.board.num_cols + 1): candidate = Point(row=r, col=c) if game_state.is_valid_move(Move.play(candidate)) and not is_point_an_eye( game_state.board, candidate, game_state.next_player ): candidates.append(candidate) if len(candidates) == 0: return Move.pass_turn() return Move.play(random.choice(candidates))
def main(): board_size = 9 game = GameState.new_game(board_size) bots = { Player.BLACK: agent.naive.RandomBot(), Player.WHITE: agent.naive.RandomBot(), } while not game.is_over(): time.sleep(0.3) print(chr(27) + "[2J") print_board(game.board) bot_move = bots[game.next_player].select_move(game) print_move(game.next_player, bot_move) game = game.apply_move(bot_move)