def _min(self, board: Board) -> (float, int): """ Evaluate the board position `board` from the Minimizing player's point of view. :param board: The board position to evaluate :return: Tuple of (Best Result, Best Move in this situation). Returns -1 for best move if the game has already finished """ # # First we check if we have seen this board position before, and if yes just return the cached value # board_hash = board.hash_value() if board_hash in self.cache: return self.cache[board_hash] # # Init the min value as well as action. Min value is set to DRAW as this value will pass through in case # of a draw # min_value = self.DRAW_VALUE action = -1 # # If the game has already finished we return. Otherwise we look at possible continuations # winner = board.who_won() if winner == self.side: min_value = self.WIN_VALUE action = -1 elif winner == board.other_side(self.side): min_value = self.LOSS_VALUE action = -1 else: for index in [ i for i, e in enumerate(board.state) if board.state[i] == EMPTY ]: b = Board(board.state) b.move(index, board.other_side(self.side)) res, _ = self._max(b) if res < min_value or action == -1: min_value = res action = index # Shortcut: Can't get better than that, so abort here and return this move if min_value == self.LOSS_VALUE: self.cache[board_hash] = (min_value, action) return min_value, action self.cache[board_hash] = (min_value, action) return min_value, action
def _min(self, board: Board) -> int: """ Evaluate the board position `board` from the Minimizing player's point of view. :param board: The board position to evaluate :return: returns the best Move in this situation. Returns -1 for best move if the game has already finished """ # # First we check if we have seen this board position before, and if yes just return a random choice # from the cached values # board_hash = board.hash_value() if board_hash in self.cache: return random.choice(self.cache[board_hash]) # # If the game has already finished we return. Otherwise we look at possible continuations # winner = board.who_won() if winner == self.side: best_moves = {(self.WIN_VALUE, -1)} elif winner == board.other_side(self.side): best_moves = {(self.LOSS_VALUE, -1)} else: # # Init the min value as well as action. Min value is set to DRAW as this value will pass through in case # of a draw # min_value = self.DRAW_VALUE action = -1 best_moves = {(min_value, action)} for index in [ i for i, e in enumerate(board.state) if board.state[i] == EMPTY ]: b = Board(board.state) b.move(index, board.other_side(self.side)) res, _ = self._max(b) if res < min_value or action == -1: min_value = res action = index best_moves = {(min_value, action)} elif res == min_value: action = index best_moves.add((min_value, action)) best_moves = tuple(best_moves) self.cache[board_hash] = best_moves return random.choice(best_moves)