def value(game_state: Othello, depth, heuristic, alpha=-1, beta=1): """ Get value for game_state according to alpha beta pruning :param game_state: The state to evaluate :param depth: do alpha beta pruning until this depth is reached :param heuristic: Function reference for the heuristic used to score game state after maximum search depth is reached :param alpha: value of alpha :param beta: value of beta :return: value of move Compare https://github.com/karlstroetmann/Artificial-Intelligence/blob/master/SetlX/game-alpha-beta.stlx """ if game_state.game_is_over(): return game_state.utility(game_state.get_current_player()) if depth == 0: # return heuristic of game state return heuristic(game_state.get_current_player(), game_state) val = alpha for move in game_state.get_available_moves(): next_state = game_state.deepcopy() next_state.play_position(move) val = max({ val, -1 * AlphaBetaPruning.value(next_state, depth - 1, heuristic, -beta, -alpha) }) if val >= beta: return val alpha = max({val, alpha}) return val
def get_move(self, game_state: Othello): """ Will select the best move according to the value of the resulting game_state according to monte carlo :param game_state: current game state :return: best move in available moves """ # Use start library if it is selected and still included if self._use_start_lib and game_state.get_turn_nr( ) < 21: # check whether start move match moves = self._start_tables.get_available_moves_of_start_tables( game_state) if len(moves) > 0: return util.translate_move_to_pair(moves[random.randrange( len(moves))]) # According to experience the number of moves to consider decreases relevantly after reaching a certain # turn number. Therefore it is possible to increase the search depth without loosing to much time. # We dynamically increase the search depth after reaching turn_number 40 search_depth = self._search_depth turn_number = game_state.get_turn_nr() if turn_number > 40: search_depth += turn_number // 10 # Dict used to store a list of the moves resulting in a state with the respective value best_moves = dict() # Evaluate each available move for move in game_state.get_available_moves(): # Play the move to get the resulting state next_state = game_state.deepcopy() next_state.play_position(move) # Evaluate the state using the selected function if self._use_monte_carlo: result = -AlphaBetaPruning.value_monte_carlo( next_state, search_depth - 1, self._heuristic, mc_count=self._mc_count) else: result = -AlphaBetaPruning.value( next_state, self._search_depth - 1, self._heuristic) # Append the move to the list of states with that value if result not in best_moves.keys(): best_moves[result] = [] best_moves[result].append(move) # Determine the best result best_result = max(best_moves.keys()) if self._use_monte_carlo: print(AlphaBetaPruning.value_monte_carlo.cache_info()) AlphaBetaPruning.value_monte_carlo.cache_clear() else: print(AlphaBetaPruning.value.cache_info()) AlphaBetaPruning.value.cache_clear() # Play one random move with the best possible result return best_moves[best_result][random.randrange( len(best_moves[best_result]))]
def heuristic(current_player, game_state: Othello): """ Calculates the value of game_state for current_player according to the Stored MonteCarlo Heuristic current_player is coded as the constants EMPTY_CELL, PLAYER_ONE and PLAYER_TWO form constants.py. Therefore the parameter is an integer values. """ moves = game_state.get_available_moves() turn_nr = game_state.get_turn_nr() # get maximum of likelihood values return max([database.db.get_change_of_winning(move, turn_nr, current_player) for move in moves])
def get_move(game_state: Othello): """ interface function of all players :param game_state: actual game state :return: random move in available moves """ # Get the legal moves possible_moves = game_state.get_available_moves() # As the dict_keys Object returned by the function does not support indexing and Indexing is required here # Convert it to a list possible_moves = list(possible_moves) # Return a Random move return rnd.choice(possible_moves)
def get_move(game_state: Othello): """ interface function of all players Asks the user for a move and returns the selection :param game_state: actual game state :return: best move in available moves """ # Create a data structure to use with util.select_one possibilities = [] for move in game_state.get_available_moves(): (row, col) = move description = f"({COLUMN_NAMES[col]}{row + 1})" possibilities.append((description, move)) # Return the users selection return util.select_one(possibilities, "Select your move:")
def value_monte_carlo(game_state: Othello, depth, heuristic, alpha=-1, beta=1, mc_count=100): """ get score for alpha beta pruning :param game_state: actual game state :param depth: do alpha beta pruning this depth :param heuristic: score game state after alpha beta pruning with this heuristic :param mc_count: number of games which are played in each terminal node after alpha beta pruning :param alpha: value of alpha :param beta: value of beta :return: score of move Compare https://github.com/karlstroetmann/Artificial-Intelligence/blob/master/SetlX/game-alpha-beta.stlx """ if game_state.game_is_over(): return game_state.utility(game_state.get_current_player()) if depth == 0: # use monte carlo player if enabled # mc_count = number of played games mc = MonteCarlo(big_number=mc_count, use_start_libs=False, preprocessor_n=-1, heuristic=heuristic, use_multiprocessing=True) # get best move move = mc.get_move(game_state) # return winnings stats of best move prob = mc.get_move_probability(move) return prob val = alpha for move in game_state.get_available_moves(): next_state = game_state.deepcopy() next_state.play_position(move) val = max({ val, -1 * AlphaBetaPruning.value_monte_carlo(next_state, depth - 1, heuristic, -beta, -alpha, mc_count=mc_count) }) if val >= beta: return val alpha = max({val, alpha}) return val