人工智能-CS188 Project 2: Multi-agents

一、项目介绍

  • 项目介绍网页
  • 项目代码下载
  • 本项目是采用Berkeley的CS188课程内容实习二的内容,在这个项目中,我们将为经典版本的Pacman 设计自动算法,包括幽灵。在此过程中,我们将实现 minimax 和 expectimax 搜索并尝试评估函数设计
  • 完成作业只需要完成5个题目,按照项目介绍的步骤进行完成,主要是在multiAgents.py文件中进行补充代码

二、代码详情

1、Question1:Reflex Agent

2、Question2:Minimax

  • 套用ppt上的minmax算法伪代码。
  • pacman作为max玩家,要在各ghost做出对于ghost最优的action下找到最优应对。
  • 核心的是min_value和max_value函数互相递归调用。
  • 麻烦的是本游戏中ghost可能不止一个,min_value函数中我采用递归的方式先得到每个ghost各走一步后的所有state,并对每个state评max_value,选出最小者。
  • 另外要注意pacman不应该采取"stop"动作,否则无法通过测试(因为autograder认为总有比stop更优的解)
class MinimaxAgent(MultiAgentSearchAgent):
    """
    Your minimax agent (question 2)
    """

    def getAction(self, gameState):
        """
        Returns the minimax action from the current gameState using self.depth
        and self.evaluationFunction.

        Here are some method calls that might be useful when implementing minimax.

        gameState.getLegalActions(agentIndex):
        Returns a list of legal actions for an agent
        agentIndex=0 means Pacman, ghosts are >= 1

        gameState.generateSuccessor(agentIndex, action):
        Returns the successor game state after an agent takes an action

        gameState.getNumAgents():
        Returns the total number of agents in the game

        gameState.isWin():
        Returns whether or not the game state is a winning state

        gameState.isLose():
        Returns whether or not the game state is a losing state
        """
        "*** YOUR CODE HERE ***"

        GhostIndex = [i for i in range(1, gameState.getNumAgents())]

#pacman作为max玩家,要在各ghost做出对于ghost最优的action下找到最优应对。
#核心的minvalue和maxvalue函数互相递归调用。
#麻烦的是本游戏中ghost可能不止一个,
#minvalue函数中我采用递归的方式先得到每个ghost各走一步后的所有state,并对每个state评maxvalue,选出最小者。
        # 根据当前状态,判断游戏是否胜利或者结束
        def term(state, d):
            return state.isWin() or state.isLose() or d == self.depth

        # 采用递归方式把ghost每个走过的状态检查一遍
        def min_value(state, d, ghost):  # minimizer

            if term(state, d):
                return self.evaluationFunction(state)

            v = 10000000000000000   # β初始值为无穷大
            for action in state.getLegalActions(ghost):
                if ghost == GhostIndex[-1]: # 递归的查找最小值,如果ghost==ghostindex[-1]的话,则在大数中进行查找,反之
                    v = min(v, max_value(state.generateSuccessor(ghost, action), d + 1))
                else:
                    v = min(v, min_value(state.generateSuccessor(ghost, action), d, ghost + 1))
            # print(v)
            return v

        def max_value(state, d):  # maximizer

            if term(state, d):
                return self.evaluationFunction(state)

            v = -10000000000000000  # α初始值为无穷小
            for action in state.getLegalActions(0):
                # 递归查找最大值
                v = max(v, min_value(state.generateSuccessor(0, action), d, 1))
            # print(v)
            return v

        res = [(action, min_value(gameState.generateSuccessor(0, action), 0, 1)) for action in
               gameState.getLegalActions(0)]
        res.sort(key=lambda k: k[1])

        return res[-1][0]

        # util.raiseNotDefined()

3、Question3: Alpha-Beta Pruning

  • 在minimax基础上加入减枝操作。
  • 注意不能先把每个ghost各走一步后的所有state都找出来后再排查,因为这样会展开大量多余结点。
  • 应该得到一个state后立即判断是否需要剪枝,如果剪枝了则不要做后面的展开了,会省很多资源。
  • 注意剪纸比较的条件中没有等号。
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 ***"

        GhostIndex = [i for i in range(1, gameState.getNumAgents())]
        inf = 1e100 # 无穷大
# 不能先把每个ghost各走一步后的所有state都找出来后再排查,因为这样会展开大量多余结点。
# 应该得到一个state后立即判断是否需要剪枝,如果剪枝了则不要做后面的展开了,会省很多资源
        # 根据当前状态,判断游戏是否胜利或者结束
        def term(state, d):
            return state.isWin() or state.isLose() or d == self.depth

        def min_value(state, d, ghost, A, B):  # minimizer

            if term(state, d):
                return self.evaluationFunction(state)

            v = inf # β初始值为无穷大
            for action in state.getLegalActions(ghost):
                # 需要在递归过程中一边展开一遍检查,及时剪枝
                if ghost == GhostIndex[-1]:  # 下一个是的pacman最大值
                    v = min(v, max_value(state.generateSuccessor(ghost, action), d + 1, A, B))
                else:  # 下一个是的next-ghost最小值
                    v = min(v, min_value(state.generateSuccessor(ghost, action), d, ghost + 1, A, B))

                if v < A:  # 剪枝
                    return v
                B = min(B, v)

            return v

        def max_value(state, d, A, B):  # maximizer

            if term(state, d):
                return self.evaluationFunction(state)

            v = -inf    # α初始值为无穷小
            for action in state.getLegalActions(0):
                v = max(v, min_value(state.generateSuccessor(0, action), d, 1, A, B))

                if v > B:
                    return v
                A = max(A, v)

            return v

        def alphabeta(state):

            v = -inf
            act = None
            A = -inf
            B = inf

            for action in state.getLegalActions(0):  # 求最大值
                tmp = min_value(gameState.generateSuccessor(0, action), 0, 1, A, B)

                if v < tmp:  # 和 v = max(v, tmp) 相同
                    v = tmp
                    act = action

                if v > B:  # 剪枝
                    return v
                A = max(A, tmp)

            return act

        return alphabeta(gameState)

        util.raiseNotDefined()

4、Question4:Expectimax

  • 本题考虑了不是每一次ghost都能做出对ghost最好的动作,因此不是对ghost采取action后所有state的各值取最小,而是对他们求期望。
  • 由题意,ghost采取各action概率相同,所以只需要对各state的值求平均即可,其他部分和minimax中的一致。
class ExpectimaxAgent(MultiAgentSearchAgent):
    """
      Your expectimax agent (question 4)
    """

    def getAction(self, gameState):
        """
        Returns the expectimax action using self.depth and self.evaluationFunction

        All ghosts should be modeled as choosing uniformly at random from their
        legal moves.
        """
        "*** YOUR CODE HERE ***"

        GhostIndex = [i for i in range(1, gameState.getNumAgents())]

        # 本题考虑了不是每一次ghost都能做出对ghost最好的动作,因此不是对ghost采取action后所有state的各值取最小,而是对他们求期望。
        # 由题意,ghost采取各action概率相同,所以只需要对各state的值求平均即可。其他部分和minimax中的一致。
        def term(state, d):
            return state.isWin() or state.isLose() or d == self.depth

        def exp_value(state, d, ghost):  # minimizer

            if term(state, d):
                return self.evaluationFunction(state)

            v = 0
            # 每一种概率为1/count
            # count为pacam走了一步之后,ghost可以走成多少种状态
            # 有可能pacman走完游戏就结束了,此时count = 0,此时只需要直接取各sumvalue最大值即可
            prob = 1 / len(state.getLegalActions(ghost))

            for action in state.getLegalActions(ghost):
                if ghost == GhostIndex[-1]:
                    v += prob * max_value(state.generateSuccessor(ghost, action), d + 1)
                else:
                    v += prob * exp_value(state.generateSuccessor(ghost, action), d, ghost + 1)
            # print(v)
            return v

        def max_value(state, d):  # maximizer

            if term(state, d):
                return self.evaluationFunction(state)

            v = -10000000000000000
            for action in state.getLegalActions(0):
                v = max(v, exp_value(state.generateSuccessor(0, action), d, 1))
            # print(v)
            return v

        res = [(action, exp_value(gameState.generateSuccessor(0, action), 0, 1)) for action in
               gameState.getLegalActions(0)]
        res.sort(key=lambda k: k[1])

        return res[-1][0]

        util.raiseNotDefined()

5、Question5:Evaluation Function

  • 题目要求不是简单地用getSocre()函数作为评分标准。
  • 进过反复调参进行测试,最后测试出一种能够通过q5的评价函数
def betterEvaluationFunction(currentGameState):
    """
    Your extreme ghost-hunting, pellet-nabbing, food-gobbling, unstoppable
    evaluation function (question 5).

    DESCRIPTION: based on number 1, added situation values about closestghostdistance, capsules, etc.

    """
    "*** YOUR CODE HERE ***"

    newPos = currentGameState.getPacmanPosition()
    newFood = currentGameState.getFood()
    newGhostStates = currentGameState.getGhostStates()
    newScaredTimes = [ghostState.scaredTimer for ghostState in newGhostStates]
    walls = currentGameState.getWalls()

    # 如果不是新的ScaredTimes,则新状态为ghost:返回最低值

    newFood = newFood.asList()
    ghostPos = [(G.getPosition()[0], G.getPosition()[1]) for G in newGhostStates]
    scared = min(newScaredTimes) > 0


    if currentGameState.isLose():
        return float('-inf')

    if newPos in ghostPos:
        return float('-inf')


    # 如果不是新的ScaredTimes,则新状态为ghost:返回最低值

    closestFoodDist = sorted(newFood, key=lambda fDist: util.manhattanDistance(fDist, newPos))
    closestGhostDist = sorted(ghostPos, key=lambda gDist: util.manhattanDistance(gDist, newPos))

    score = 0

    fd = lambda fDis: util.manhattanDistance(fDis, newPos)
    gd = lambda gDis: util.manhattanDistance(gDis, newPos)

    if gd(closestGhostDist[0]) <3:
        score-=300
    if gd(closestGhostDist[0]) <2:
        score-=1000
    if gd(closestGhostDist[0]) <1:
        return float('-inf')

    if len(currentGameState.getCapsules()) < 2:
        score+=100

    if len(closestFoodDist)==0 or len(closestGhostDist)==0 :
        score += scoreEvaluationFunction(currentGameState) + 10
    else:
        score += (   scoreEvaluationFunction(currentGameState) + 10/fd(closestFoodDist[0]) + 1/gd(closestGhostDist[0]) + 1/gd(closestGhostDist[-1])  )

    return score

    # util.raiseNotDefined()

三、测试

1、Reflex Agent

输入如下指令进行测试:

python autograder.py -q q1 --no-graphics

测试结果:
在这里插入图片描述

可以看到10个测试案例都通过了,平均分为:1218.3
在这里插入图片描述

2、Minimax

输入如下指令:

python autograder.py -q q2 --no-graphics

测试结果:
在这里插入图片描述
在这里插入图片描述
可以看到测试案例都通过了,但是由于MinimaxAgent测试还是有缺陷
所以最终得分只有:84
在这里插入图片描述

3、Alpha-Beta Pruning

输入如下指令:

python autograder.py -q q3 --no-graphics

测试结果:
在这里插入图片描述
在这里插入图片描述
可以看到测试案例都通过了,但是由于smallClassic测试还是有缺陷
所以最终得分只有:84
在这里插入图片描述

4、Expectimax

输入如下指令:

python autograder.py -q q4 --no-graphics

测试结果:
在这里插入图片描述
最终得分:84
在这里插入图片描述

5、Evaluation Function

输入如下指令:

python autograder.py -q q5 --no-graphics

测试结果:
在这里插入图片描述
最终平均得分:1107.4
在这里插入图片描述

四、算法对比

1、在smallClassic、 depth=4情况下分别使用 MiniMax、 Alpha-Beta
Pruning、 Expectimax进行游戏(比较同一运行规模下,运行的时间)。

  • (1)MinMax算法表现:
python pacman.py -p MinimaxAgent -l minimaxClassic -a depth=4

在这里插入图片描述

  • (2)Alpha-Beta Pruning算法表现:
python pacman.py -p AlphaBetaAgent -l smallClassic -a depth=4

在这里插入图片描述

  • (3)Expectimax算法表现:
python pacman.py -p ExpectimaxAgent -l smallClassic -a depth=4

在这里插入图片描述

发现:

  • 在运行时间上面,同样深度情况下 MiniMax和 Expectimax展开结点数和时间基本持平,三种算法的运行时间很明显能感到Alpha- Beta Pruning要快于其他两个,说明剪枝的重要性。

2、在smallClassic、 depth=2(由于选择depth=4会花费很长时间)情况下分别使用 MiniMax、 Alpha-Beta Pruning、 Expectimax算法各进行10次游戏,然后比较胜率(比较同一运行规模下,同一运行次数,比较成功率)。

  • (1)MinMax算法表现:
python pacman.py --frameTime 0 -p MinimaxAgent -a depth=0 -l smallClassic -n 10

在这里插入图片描述

  • (2)Alpha-Beta Pruning算法表现:
python pacman.py --frameTime 0 -p AlphaBetaAgent -a depth=0 -l smallClassic -n 10

在这里插入图片描述

  • (3)Expectimax算法表现:
python pacman.py --frameTime 0 -p ExpectimaxAgent -a depth=0 -l smallClassic -n 10

在这里插入图片描述
发现:

  • 1.它们表现都不大好。
  • 2.ExpectimaxAgent在胜率和均分上表现稍微好一点,但几乎没什么区别。

3、在trappedClass问题中比较:

  • Alpha-Beta Pruning Agent在 trappedClassic 10 次胜负情况:
    在这里插入图片描述
  • Expectimax Agent在 trappedClassic10次胜负情况:
    在这里插入图片描述

发现:

  • 1.在 trappedClassic问题中ExpectimaxAgent体现出了巨大的优势。
  • 2.Alpha- Beta Pruning Agent总是输,而 Expectimax Agent有相当大概率赢。这是因为, Alpha- Beta Pruning Agent总是认为 ghost会采取最佳对于 ghost策略,即 pacman一定会被 ghost吃掉,于是 pacman干脆就撞向最近的 ghost尽早结束游戏减少时间扣分项,而实际上图中蓝色 ghost有一定几率往右下角走。
    在这里插入图片描述

五、总结

  • Alpha- Beta Pruning Agent能在与 Minimax Agent得出同样结果情况下大大减少了需要展开的结点数,但是两者都假设了对面总做出最好的选择,因此大大限制了自己所能采取的步骤。而 Expectimax Agent能比较好地处理对面不是总 optima1的情况,但是相比Alpha- Beta Pruning Agent所消耗的资源就大得多。除了 Agent本身的设计外评分函数对 Agent的表现起了至关重要的作用,设计评分函数时要考虑“趋利避害”之间的平衡,核心问題是对于玩家说什么是“好的”.遗憾的是我设计的函数比较简单粗暴,因此表现不是很好。

参考博客和网页:
https://www.bilibili.com/read/cv7123775/
https://inst.eecs.berkeley.edu/~cs188/fa21/project2/
https://github.com/DylanCope/CS188-Multi-Agent

  • 7
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
ML-Agents报错"AttributeError: 'str' object has no attribute '_key'"通常是由于对象没有定义"_key"属性导致的。根据引用中的信息,我们可以推断出可能是在比较两个对象时使用了"_key"方法,而其中一个对象是字符串类型而不是一个带有"_key"属性的对象。 为了解决这个问题,我们可以检查代码中的比较操作,确保在比较之前两个对象都是正确的类型。特别是,检查涉及到"_key"属性的代码部分,确保它们正确使用并且预期的对象类型是正确的。 如果问题仍然存在,我们可以尝试使用调试工具来进一步检查代码执行过程中的变量值和对象类型。这可以帮助我们确定问题所在并找到解决方法。 另外,根据引用中的信息,还有可能在运行过程中遇到了Unity环境响应超时的问题。这可能导致与ML-Agents相关的操作无法顺利进行。要解决这个问题,可以检查Unity环境是否需要用户交互才能启动,确保代理与脑部的链接正确,以及环境和Python接口的版本是否兼容。 最后,引用中提到了一些可能导致问题的原因和解决方法,例如ML-Agents安装不完全或防火墙阻止了通信端口。如果以上解决方法不起作用,您可以尝试重新下载并安装ML-Agents,确保按照正确的方式进行安装,并且关闭防火墙再次尝试。 综上所述,要解决ML-Agents报错"AttributeError: 'str' object has no attribute '_key'",我们可以按照以下步骤进行操作: 1. 检查比较操作的代码,确保涉及"_key"属性的部分使用正确并且对象类型正确。 2. 使用调试工具检查变量值和对象类型,以确定问题所在。 3. 检查Unity环境响应超时问题,确保环境启动不需要用户交互,代理与脑部的链接正确,以及环境和Python接口的版本兼容。 4. 尝试重新下载并安装ML-Agents,确保按照正确的方式进行安装。 5. 如果防火墙阻止了通信端口,关闭防火墙再次尝试。 希望以上信息对您有帮助!如果问题仍然存在,请提供更多详细信息,以便我们能够更准确地为您解答。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值