人工智能:一种现代方法学习笔记(第五章)——对抗搜索

博弈概念

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

MinMax算法

极小极大算法常用于二人博弈游戏,目的是寻找最优的方案使得自己能够利益最大化。基本思想就是假设自己(A)足够聪明,总是能选择最有利于自己的方案,而对手(B)同样足够聪明,总会选择最不利A的方案。

下面举个例子进行说明:
设:正方形代表自己(A),圆代表对手(B),节点的每个孩子节点代表一个候选方案
在这里插入图片描述
上图中显示了所有候选方案。让我们如下分析:(注意:图中的所有数字都是A的利益值,越大越有利于A)
在这里插入图片描述
假设A选择第一个方案,B有两个候选方案,B为了使得A利益最小化,所有在7和3中选择了3,所以A只能获得3

在这里插入图片描述
假设A选择第二个方案,B只有一个选择,A最终可以获得15。
在这里插入图片描述
假设A选择第三个方案,B有4个可选方案,为了使得A利益最小,B选择第一个方案,则A只能获得利益1。
A为了使得自己利益最大,所以A会选择第一个方案,即获得利益15。

从上图可以看出,B总是选择候选方案中的最小值,而A总是选择候选方案中的最大值,极小极大的名字也就源于此。

该算法使用深度优先搜索(Depth First Search)遍历决策树来填充树中间节点的利益值,叶子节点的利益值通常是通过一个利益评估函数算得。

通常决策树的分支呈指数增长,所以基本不可能遍历整棵决策树,所以实际应用中通常会控制决策树深度,从而减少计算量。正因为无法遍历完整的决策树,所以该算法有可能造成误导,即选取的方案可能是局部最优而不是全局最优的。

有时候为了得到较好的效果不得不增加搜索树的深度,这样就增加了大量的计算。为了加快计算速度,减少计算量,可以使用Alpha-Beta剪枝算法(Alpha Beta Pruning)对搜索树进行剪枝。因为搜索树中有很多分支不需要遍历。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
Max是要让自己的利益最大化,Min要让对手的利益最小化
零和博弈:参与博弈的双方,在严格竞争下,一方的收益必然对应另一方的损失,博弈双方的收益和损失相加和永远是零
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5.2.1极小极大算法
递归算法自上而下一直前进到树的叶子节点,递归回溯通过搜索树把极小极大值回传。
每一步都是最小化敌方的最大收益。

5.2.2多人博弈时的最优决策
超过两个人的博弈利用MINIMAX算法,由于之前研究的两人博弈一方得分可以反应另一方得分,故仅用一个数值表示状态得分,对于多人游戏,应该使用向量值替换单一效用值。每个节点的回传至是该选手在节点的后继者效用值向量中选择的结果。多人博弈通常会涉及在游戏选手之间出现正式或非正式联盟的情况。

博弈搜索实验

class MinimaxAgent(MultiAgentSearchAgent):
    """
      Your minimax agent (question 2)
    """
    def getAction(self, gameState):
        "*** YOUR CODE HERE ***"
      #  util.raiseNotDefined()
        return self.MinMaxSearch(gameState,0,1)
    
    def MinMaxSearch(self,gameState,agentIndex,currentdepth):
        if currentdepth > self.depth or gameState.isWin() or gameState.isLose():
              return self.evaluationFunction(gameState)

        legalMoves = [action for action in gameState.getLegalActions(agentIndex) if action != 'Stop']

        # update next depth
        nextIndex = agentIndex + 1
        nextdepth = currentdepth 
        if nextIndex>=gameState.getNumAgents():
              nextIndex = 0
              nextdepth += 1
        results = [self.MinMaxSearch(gameState.generateSuccessor(agentIndex,action),nextIndex,nextdepth) for action in legalMoves]

        if agentIndex==0 and currentdepth==1:
              bestmove = max(results)
              bestIndex = [index for index in range(len(results)) if results[index]==bestmove]
              choose_index = random.choice(bestIndex)
              return legalMoves[choose_index]

        if agentIndex==0:
              bestmove = max(results)
              return bestmove
        else:             
              bestmove = min(results)
              return bestmove

α-β剪枝算法

α-β算法详解
算法详解另一个参考
在这里插入图片描述

Alpha-Beta剪枝用于裁剪搜索树中没有意义的不需要搜索的树枝,以提高运算速度。

假设α为下界,β为上界,对于α ≤ N ≤ β:

若 α ≤ β 则N有解。

若 α > β 则N无解。

下面通过一个例子来说明Alpha-Beta剪枝算法。
在这里插入图片描述
上图为整颗搜索树。这里使用极小极大算法配合Alpha-Beta剪枝算法,正方形为自己(A),圆为对手(B)。
初始设置α为负无穷大,β为正无穷大
在这里插入图片描述
对于B(第四层)而已,尽量使得A获利最小,因此当遇到使得A获利更小的情况,则需要修改β。这里3小于正无穷大,所以β修改为3。
在这里插入图片描述
(第四层)这里17大于3,不用修改β
在这里插入图片描述
对于A(第三层)而言,自己获利越大越好,因此遇到利益值大于α的时候,需要α进行修改,这里3大于负无穷大,所以α修改为3
在这里插入图片描述
B(第四层)拥有一个方案使得A获利只有2,α=3, β=2, α > β, 说明A(第三层)只要选择第二个方案, 则B必然可以使得A的获利少于A(第三层)的第一个方案,这样就不再需要考虑B(第四层)的其他候选方案了,因为A(第三层)根本不会选取第二个方案,多考虑也是浪费.
在这里插入图片描述
B(第二层)要使得A利益最小,则B(第二层)的第二个方案不能使得A的获利大于β, 也就是3. 但是若B(第二层)选择第二个方案, A(第三层)可以选择第一个方案使得A获利为15, α=15, β=3, α > β, 故不需要再考虑A(第三层)的第二个方案, 因为B(第二层)不会选择第二个方案.
在这里插入图片描述
A(第一层)使自己利益最大,也就是A(第一层)的第二个方案不能差于第一个方案, 但是A(第三层)的一个方案会导致利益为2, 小于3, 所以A(第三层)不会选择第一个方案, 因此B(第四层)也不用考虑第二个方案.
在这里插入图片描述
当A(第三层)考虑第二个方案时,发现获得利益为3,和A(第一层)使用第一个方案利益一样.如果根据上面的分析A(第一层)优先选择了第一个方案,那么B不再需要考虑第二种方案,如果A(第一层)还想进一步评估两个方案的优劣的话, B(第二层)则还需要考虑第二个方案,若B(第二层)的第二个方案使得A获利小于3,则A(第一层)只能选择第一个方案,若B(第二层)的第二个方案使得A获利大于3,则A(第一层)还需要根据其他因素来考虑最终选取哪种方案.

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
α值:Max节点目前可以得到的最高收益
β值:Min节点目前可以给对手的最小收益
α和β的初始化分别设置为 -∞和+∞
在这里插入图片描述

import sys
class AlphaBetaAgent(MultiAgentSearchAgent):
    """
      Your minimax agent with alpha-beta pruning (question 3)
    """

    def getAction(self, gameState):
        """
          Returns the minimax action using self.depth and self.evaluationFunction
        """
        "*** YOUR CODE HERE ***"
        #util.raiseNotDefined()
        return self.AlphaBeta(gameState,0,1,-sys.maxint,sys.maxint)
    
    def AlphaBeta(self,gameState,currentAgent,currentDepth,Alpha,Beta):
          if currentDepth > self.depth or gameState.isWin() or gameState.isLose():
                return self.evaluationFunction(gameState)
          
          legalMoves = [action for action in gameState.getLegalActions(currentAgent) if action!='Stop']
          nextAgent = currentAgent + 1
          nextDepth = currentDepth
          if nextAgent >= gameState.getNumAgents():
                nextAgent = 0
                nextDepth += 1
          

          if currentAgent == 0 and currentDepth == 1:
                results = [self.AlphaBeta(gameState.generateSuccessor(currentAgent,action),nextAgent,nextDepth,Alpha,Beta) for action in legalMoves]
                bestMove = max(results)
                bestIndex = [index for index in range(len(results)) if results[index]==bestMove]
                ultimate_index = random.choice(bestIndex)
                return legalMoves[ultimate_index]
          
          if currentAgent == 0:
                bestMove = -sys.maxint
                for action in legalMoves:
                      bestMove = max(bestMove,self.AlphaBeta(gameState.generateSuccessor(currentAgent,action),nextAgent,nextDepth,Alpha,Beta))
                      if bestMove >= Beta:
                            return bestMove
                      Alpha = max(Alpha,bestMove)
                      return bestMove
          else:
                bestMove = sys.maxint
                for action in legalMoves:
                      bestMove = min(bestMove,self.AlphaBeta(gameState.generateSuccessor(currentAgent,action),nextAgent,nextDepth,Alpha,Beta))
                      if bestMove <= Alpha:
                            return bestMove
                      Beta = min(bestMove,Beta)
                      return bestMove

猜你喜欢

转载自blog.csdn.net/weixin_44972129/article/details/108861517