人工智能导论-搜索策略(pacman.py)吃豆人

实验内容:

实验要求采用且不限于课程第四章内各种搜索算法此编写一系列吃豆人程序解决以下列出的问题1-8,包括到达指定位置以及有效的吃豆等。

简介:

参考网址:http://ai.berkeley.edu/search.html内容,以下为实验简介。

基本代码和支持文件可以从search.zip中获取。其中,一些需要参考的文件如下:

需要编辑的文件:search.py和searchAgents.py

需要参考的文件:

pacman.py

吃豆人游戏的程序。 文件包括一个描述”吃豆人”gamestate的类型。

game.py

吃豆人游戏的运行逻辑. 文件包括以下类型AgentState, Agent, Direction, and Grid.

util.py

搜索策略可以用到的数据结构.

可以忽略的支持性文件:graphicsDisplay.py graphicsUtils.py textDisplay.py ghostAgents.py keyboardAgents.pylayout.pyautograder.py   testParser.pytestClasses.py test_cases/ searchTestClasses.py

解压缩search.zip,在此目录下,运行以下指令可打开吃豆人游戏。

python pacman.py

运行python autograder.py可以帮助你对自己的程序打分。

searchAgents.py中最简单的Agent叫做GoWestAgent,一路向西,偶尔能实现目标:

python pacman.py --layout testMaze --pacman GoWestAgent

但是其不能实现转弯:

python pacman.py --layout tinyMaze --pacman GoWestAgent

如果程序卡死,可通过CTRL-c来终止。

此项目中用到的指令也都储存在commands.txt文件中,可用于复制和粘贴。

问题1:应用深度优先算法找到一个特定的位置的豆

首先,运行一下命令测试SearchAgent是不是正常工作:

python pacman.py -l tinyMaze -p SearchAgent -afn=tinyMazeSearch

然后,完成完整的通用算法帮助吃豆人规划路线。搜索算法的伪代码见附录。注意一个搜索节点不仅包含节点的状态,而且要包含构建搜索路径所需要的信息。

注意:所有的搜索函数必须返回一个从初始状态到目标状态的操作序列。所有操作必须合法(不能翻墙)。

注意:利用util.py文件中提供的Stack, Queue 和 PriorityQueue数据结构!这是自动评分系统的兼容性要求。

你的code应该能顺利解决以下问题:

python pacman.py -l tinyMaze -p SearchAgent

pythonpacman.py -l mediumMaze -p SearchAgent

python pacman.py -l bigMaze -z .5 -p SearchAgent

注意:因为不同的搜索方法的不同之处仅仅在于open表的排序不同,因此请定义一个通用的搜索算法解决问题1-4。提示:问题1-4的不同之处在于用不同的数据结构对open表进行排序。

问题2:宽度优先算法

利用宽度优先算法实现解决以上问题。并利用以下命令测试你的code:

pythonpacman.py -l mediumMaze -p SearchAgent -a fn=bfs

pythonpacman.py -l bigMaze -p SearchAgent -a fn=bfs -z .5

问题3:代价一致算法

很多情况下,路径中的代价是可以改变的。完成代价一致搜索方法(search.py文件中的uniformCostSearch函数),并用以下命令测试你得code:

pythonpacman.py -l mediumMaze -p SearchAgent -a fn=ucs

pythonpacman.py -l mediumDottedMaze -p StayEastSearchAgent

pythonpacman.py -l mediumScaryMaze -p StayWestSearchAgent

问题4:A* 算法

完成A*搜索方法(search.py文件中的aStarSearch函数),利用曼哈顿距离作为启发函数,用以下命令测试你得code:

pythonpacman.py -l bigMaze -z .5 -p SearchAgent -afn=astar,heuristic=manhattanHeuristic

问题5:找到所有的角落

在角落迷宫的四个角上面有四个豆。这个搜索问题要求找到一条访问所有四个角落的最短的路径。

完成searchAgents.py文件中的CornersProblem搜索问题,你需要重新定义状态,使其能够表示角落是否被访问。用以下命令测试你得code:

pythonpacman.py -l tinyCorners -p SearchAgent -a fn=bfs,prob=CornersProblem

pythonpacman.py -l mediumCorners -p SearchAgent -a fn=bfs,prob=CornersProblem

提示:新的状态只包含吃豆人的位置和角落的状态。

问题6:角落问题(启发式)

构建合适的启发函数,完成searchAgents.py文件中的cornersHeuristic角落搜索问题。用以下命令测试你得code:

pythonpacman.py -l mediumCorners -p AStarCornersAgent -z 0.5

问题7:吃掉所有的豆子

用尽可能少的步数吃掉所有的豆子。完成searchAgents.py文件中的FoodSearchProblem豆子搜索问题。此问题利用之前A*算法可以很容易找到解,可用以下命令测试:

pythonpacman.py -l testSearch -p AStarFoodSearchAgent

构建合适的启发函数,完成searchAgents.py文件中的foodHeuristic豆子搜索(启发式)问题。用以下命令测试你得code:

pythonpacman.py -l trickySearch -p AStarFoodSearchAgent

问题8:次最优搜索

定义一个优先吃最近的豆子函数是提高搜索速度的一个好的办法。补充完成searchAgents.py文件中的AnyFoodSearchProblem目标测试函数,并完成searchAgents.py文件中的ClosestDotSearchAgent部分,在此Agent当中缺少一个关键的函数:找到最近豆子的函数。用以下命令测试你得code:

pythonpacman.py -l bigSearch -p ClosestDotSearchAgent -z .5

深度优先搜索:

   深度优先搜索采用堆栈寻找路径,首先从起始结点出发,判断是否为目标结点,若否,寻找与该结点的邻接点,先搜索一条分支上的所有节点,然后再去搜索起始节点的其它分支结点,找出并存进待扩展结点表,等待扩展,每次先判断待扩展结点表是否为空,若否,则从待扩展结点表中取出一个结点进行扩展,并将扩展后的结点存进该表,若是,则返回失败。

 

广度优先搜索:

属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止,且搜索出来的路径为最短路径。

 

代价一致算法:

扩展的是路径消耗g(n)最小的节点n,用优先队列来实现,对解的路径步数不关心,只关心路径总代价。即使找到目标节点也不会结束,而是再检查新路径是不是要比老路径好,确实好,则丢弃老路径。

 

A*算法:

公式表示为: f(n)=g(n)+h(n),其中 f(n) 是从初始点经由节点n到目标点的估价函数,g(n) 是在状态空间中从初始节点到n节点的实际代价,h(n) 是从n到目标节点最佳路径的估计代价。保证找到最短路径(最优解的)条件,关键在于估价函数f(n)的选取:首先将起始结点S放入OPEN表,CLOSE表置空,算法开始时:

1、如果OPEN表不为空,从表头取一个结点n,如果为空算法失败。

2、n是目标解吗?是,找到一个解(继续寻找,或终止算法)。

3、将n的所有后继结点展开,就是从n可以直接关联的结点(子结点),如果不在CLOSE表中,就将它们放入OPEN表,并把S放入CLOSE表,同时计算每一个后继结点的估价值f(n),将OPEN表按f(x)排序,最小的放在表头,重复算法,回到1。


search.py

# -*- coding:utf-8 -*-  
# search.py
# ---------
# Licensing Information:  You are free to use or extend these projects for
# educational purposes provided that (1) you do not distribute or publish
# solutions, (2) you retain this notice, and (3) you provide clear
# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
# 
# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
# The core projects and autograders were primarily created by John DeNero
# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
# Student side autograding was added by Brad Miller, Nick Hay, and
# Pieter Abbeel (pabbeel@cs.berkeley.edu).


"""
In search.py, you will implement generic search algorithms which are called by
Pacman agents (in searchAgents.py).
"""

import util

class SearchProblem:
    """
    This class outlines the structure of a search problem, but doesn't implement
    any of the methods (in object-oriented terminology: an abstract class).

    You do not need to change anything in this class, ever.
    """

    def getStartState(self):
        """
        Returns the start state for the search problem.
        """
        util.raiseNotDefined()

    def isGoalState(self, state):
        """
          state: Search state

        Returns True if and only if the state is a valid goal state.
        """
        util.raiseNotDefined()

    def getSuccessors(self, state):
        """
          state: Search state

        For a given state, this should return a list of triples, (successor,
        action, stepCost), where 'successor' is a successor to the current
        state, 'action' is the action required to get there, and 'stepCost' is
        the incremental cost of expanding to that successor.
        """
        util.raiseNotDefined()

    def getCostOfActions(self, actions):
        """
         actions: A list of actions to take

        This method returns the total cost of a particular sequence of actions.
        The sequence must be composed of legal moves.
        """
        util.raiseNotDefined()


def tinyMazeSearch(problem):
    """
    Returns a sequence of moves that solves tinyMaze.  For any other maze, the
    sequence of moves will be incorrect, so only use this for tinyMaze.
    """
    from game import Directions
    s = Directions.SOUTH
    w = Directions.WEST
    return  [s, s, w, s, w, w, s, w]

def depthFirstSearch(problem):
    """
    Search the deepest nodes in the search tree first.

    Your search algorithm needs to return a list of actions that reaches the
    goal. Make sure to implement a graph search algorithm.

    To get started, you might want to try some of these simple commands to
    understand the search problem that is being passed in:

    print "Start:", problem.getStartState()
    print "Is the start a goal?", problem.isGoalState(problem.getStartState())
    print "Start's successors:", problem.getSuccessors(problem.getStartState())
    """
    "*** YOUR CODE HERE ***"
    from util import Stack
    from game import Directions
 
    # fringe 候选, closed 走过的节点,path 记录路径
    # 深度搜索选择栈
    fringe = Stack()
    closed = []
 
    # 加入起始状态节点
    fringe.push((problem.getStartState(), []))
 
    # 如果候选不为空,则循环搜索
    while not fringe.isEmpty():
        
        # 当前节点
        cur_node, actions = fringe.pop()

        # 如果当前节点到达目标位置
        if problem.isGoalState(cur_node):
            return actions
 
        if cur_node not in closed:
            expand = problem.getSuccessors(cur_node)
            closed.append(cur_node)
            for location, direction, cost in expand:
                if (location not in closed):
                    fringe.push((location, actions + [direction]))

    util.raiseNotDefined()

def breadthFirstSearch(problem):
    """Search the shallowest nodes in the search tree first."""
    "*** YOUR CODE HERE ***"

    from util import Queue
    from game import Directions
    # fringe 候选, closed 走过的节点
    # 广度搜索选择栈
    fringe = Queue()
    closed = []
    
    # 加入起始状态节点
    fringe.push((problem.getStartState(), []))
    
    # 如果候选不为空,则循环搜索
    while not fringe.isEmpty():
        
        # 当前节点
        cur_node, actions = fringe.pop()

        # 如果当前节点到达目标位置
        if problem.isGoalState(cur_node):
            return actions
 
        if cur_node not in closed:
            # 寻找后继节点
            expand = problem.getSuccessors(cur_node)
            # 当前节点加入到走过路程中
            closed.append(cur_node)

            for location, direction, cost in expand:
                # 如果后继节点不在走过路程中,就新建一个候选,这个候选的路径是当前节点路径加上此次方向
                if (location not in closed):
                    fringe.push((location, actions + [direction]))

    util.raiseNotDefined()

def uniformCostSearch(problem):
    #author junruitian
    """Search the node of least total cost first."""
    """ Dijkstra shorest path with null heuristic"""
    #扩展的是路径消耗g(n)最小的节点n,用优先队列来实现,对解的路径步数不关心,只关心路径总代价。
    #即使找到目标节点也不会结束,而是再检查新路径是不是要比老路径好,确实好,则丢弃老路径。

    
    start_point = problem.getStartState()                           #点
    queue = util.PriorityQueueWithFunction(lambda x: x[2])         #记录当前队列
    queue.push((start_point,None,0))                               #加入队列
    cost=0                                                          #现在的代价.
    visited = []                                                    #标记是否记录
    path = []                                                       #记录路径
    parentSeq = {}
    parentSeq[(start_point,None,0)]=None
    while queue.isEmpty() == False:
        current_fullstate = queue.pop()                            #当前点
        #print current_fullstate
        if (problem.isGoalState(current_fullstate[0])):             #目标状态
            break
        else:
            current_state = current_fullstate[0]
            if current_state not in visited:
                visited.append(current_state)
            else:
                continue
            successors = problem.getSuccessors(current_state)           #继承表后继
            for state in successors:
                cost= current_fullstate[2] + state[2];
                #print state,cost
                if state[0] not in visited:
                    queue.push((state[0],state[1],cost))
                    #parentSeq[state] = current_fullstate
                    parentSeq[(state[0],state[1])] = current_fullstate

    child = current_fullstate

    while (child != None):
        path.append(child[1])
        if child[0] != start_point:
            child = parentSeq[(child[0],child[1])]
        else:
            child = None
    path.reverse()
    return path[1:]

    util.raiseNotDefined()


def nullHeuristic(state, problem=None):
    """
    A heuristic function estimates the cost from the current state to the nearest
    goal in the provided SearchProblem.  This heuristic is trivial.
    """
    return 0

def aStarSearch(problem, heuristic=nullHeuristic):
    """Search the node that has the lowest combined cost and heuristic first."""
    "*** YOUR CODE HERE ***"

    from sets import Set
    fringe = util.PriorityQueue()                        # 使用优先队列,每次扩展都是选择当前代价最小的方向,即队头
    actions = []                                    # 选择的操作
    fringe.push((problem.getStartState(),actions),0)   # 把初始化点加入队列,开始扩展
    visited = []                                # 标记已经走过的点
    tmpActions = []
    while fringe:
        currState,actions = fringe.pop()      # 当前状态
        if problem.isGoalState(currState):
            break
        if currState not in visited:
            visited.append(currState)
            successors = problem.getSuccessors(currState)
            for successor, action, cost in successors:
                tempActions = actions + [action]
                nextCost = problem.getCostOfActions(tempActions) + heuristic(successor,problem)      # 对可选的几个方向,计算代价
                if successor not in visited:
                    fringe.push((successor,tempActions),nextCost)
    return actions                # 返回到达终点的操作顺序

# Abbreviations
bfs = breadthFirstSearch
dfs = depthFirstSearch
astar = aStarSearch
ucs = uniformCostSearch


searchAgent.py

# -*- coding:utf-8 -*-  
# searchAgents.py
# ---------------
# Licensing Information:  You are free to use or extend these projects for
# educational purposes provided that (1) you do not distribute or publish
# solutions, (2) you retain this notice, and (3) you provide clear
# attribution to UC Berkeley, including a link to http://ai.berkeley.edu.
# 
# Attribution Information: The Pacman AI projects were developed at UC Berkeley.
# The core projects and autograders were primarily created by John DeNero
# (denero@cs.berkeley.edu) and Dan Klein (klein@cs.berkeley.edu).
# Student side autograding was added by Brad Miller, Nick Hay, and
# Pieter Abbeel (pabbeel@cs.berkeley.edu).


"""
This file contains all of the agents that can be selected to control Pacman.  To
select an agent, use the '-p' option when running pacman.py.  Arguments can be
passed to your agent using '-a'.  For example, to load a SearchAgent that uses
depth first search (dfs), run the following command:

> python pacman.py -p SearchAgent -a fn=depthFirstSearch

Commands to invoke other search strategies can be found in the project
description.

Please only change the parts of the file you are asked to.  Look for the lines
that say

"*** YOUR CODE HERE ***"

The parts you fill in start about 3/4 of the way down.  Follow the project
description for details.

Good luck and happy searching!
"""

from game import Directions
from game import Agent
from game import Actions
import util
import time
import search

class GoWestAgent(Agent):
    "An agent that goes West until it can't."

    def getAction(self, state):
        "The agent receives a GameState (defined in pacman.py)."
        if Directions.WEST in state.getLegalPacmanActions():
            return Directions.WEST
        else:
            return Directions.STOP

#######################################################
# This portion is written for you, but will only work #
#       after you fill in parts of search.py          #
#######################################################

class SearchAgent(Agent):
    """
    This very general search agent finds a path using a supplied search
    algorithm for a supplied search problem, then returns actions to follow that
    path.

    As a default, this agent runs DFS on a PositionSearchProblem to find
    location (1,1)

    Options for fn include:
      depthFirstSearch or dfs
      breadthFirstSearch or bfs


    Note: You should NOT change any code in SearchAgent
    """

    def __init__(self, fn='depthFirstSearch', prob='PositionSearchProblem', heuristic='nullHeuristic'):
        # Warning: some advanced Python magic is employed below to find the right functions and problems

        # Get the search function from the name and heuristic
        if fn not in dir(search):
            raise AttributeError, fn + ' is not a search function in search.py.'
        func = getattr(search, fn)
        if 'heuristic' not in func.func_code.co_varnames:
            print('[SearchAgent] using function ' + fn)
            self.searchFunction = func
        else:
            if heuristic in globals().keys():
                heur = globals()[heuristic]
            elif heuristic in dir(search):
                heur = getattr(search, heuristic)
            else:
                raise AttributeError, heuristic + ' is not a function in searchAgents.py or search.py.'
            print('[SearchAgent] using function %s and heuristic %s' % (fn, heuristic))
            # Note: this bit of Python trickery combines the search algorithm and the heuristic
            self.searchFunction = lambda x: func(x, heuristic=heur)

        # Get the search problem type from the name
        if prob not in globals().keys() or not prob.endswith('Problem'):
            raise AttributeError, prob + ' is not a search problem type in SearchAgents.py.'
        self.searchType = globals()[prob]
        print('[SearchAgent] using problem type ' + prob)

    def registerInitialState(self, state):
        """
        This is the first time that the agent sees the layout of the game
        board. Here, we choose a path to the goal. In this phase, the agent
        should compute the path to the goal and store it in a local variable.
        All of the work is done in this method!

        state: a GameState object (pacman.py)
        """
        if self.searchFunction == None: raise Exception, "No search function provided for SearchAgent"
        starttime = time.time()
        problem = self.searchType(state) # Makes a new search problem
        self.actions  = self.searchFunction(problem) # Find a path
        totalCost = problem.getCostOfActions(self.actions)
        print('Path found with total cost of %d in %.1f seconds' % (totalCost, time.time() - starttime))
        if '_expanded' in dir(problem): print('Search nodes expanded: %d' % problem._expanded)

    def getAction(self, state):
        """
        Returns the next action in the path chosen earlier (in
        registerInitialState).  Return Directions.STOP if there is no further
        action to take.

        state: a GameState object (pacman.py)
        """
        if 'actionIndex' not in dir(self): self.actionIndex = 0
        i = self.actionIndex
        self.actionIndex += 1
        if i < len(self.actions):
            return self.actions[i]
        else:
            return Directions.STOP

class PositionSearchProblem(search.SearchProblem):
    """
    A search problem defines the state space, start state, goal test, successor
    function and cost function.  This search problem can be used to find paths
    to a particular point on the pacman board.

    The state space consists of (x,y) positions in a pacman game.

    Note: this search problem is fully specified; you should NOT change it.
    """

    def __init__(self, gameState, costFn = lambda x: 1, goal=(1,1), start=None, warn=True, visualize=True):
        """
        Stores the start and goal.

        gameState: A GameState object (pacman.py)
        costFn: A function from a search state (tuple) to a non-negative number
        goal: A position in the gameState
        """
        self.walls = gameState.getWalls()
        self.startState = gameState.getPacmanPosition()
        if start != None: self.startState = start
        self.goal = goal
        self.costFn = costFn
        self.visualize = visualize
        if warn and (gameState.getNumFood() != 1 or not gameState.hasFood(*goal)):
            print 'Warning: this does not look like a regular search maze'

        # For display purposes
        self._visited, self._visitedlist, self._expanded = {}, [], 0 # DO NOT CHANGE

    def getStartState(self):
        return self.startState

    def isGoalState(self, state):
        isGoal = state == self.goal

        # For display purposes only
        if isGoal and self.visualize:
            self._visitedlist.append(state)
            import __main__
            if '_display' in dir(__main__):
                if 'drawExpandedCells' in dir(__main__._display): #@UndefinedVariable
                    __main__._display.drawExpandedCells(self._visitedlist) #@UndefinedVariable

        return isGoal

    def getSuccessors(self, state):
        """
        Returns successor states, the actions they require, and a cost of 1.

         As noted in search.py:
             For a given state, this should return a list of triples,
         (successor, action, stepCost), where 'successor' is a
         successor to the current state, 'action' is the action
         required to get there, and 'stepCost' is the incremental
         cost of expanding to that successor
        """

        successors = []
        for action in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]:
            x,y = state
            dx, dy = Actions.directionToVector(action)
            nextx, nexty = int(x + dx), int(y + dy)
            if not self.walls[nextx][nexty]:
                nextState = (nextx, nexty)
                cost = self.costFn(nextState)
                successors.append( ( nextState, action, cost) )

        # Bookkeeping for display purposes
        self._expanded += 1 # DO NOT CHANGE
        if state not in self._visited:
            self._visited[state] = True
            self._visitedlist.append(state)

        return successors

    def getCostOfActions(self, actions):
        """
        Returns the cost of a particular sequence of actions. If those actions
        include an illegal move, return 999999.
        """
        if actions == None: return 999999
        x,y= self.getStartState()
        cost = 0
        for action in actions:
            # Check figure out the next state and see whether its' legal
            dx, dy = Actions.directionToVector(action)
            x, y = int(x + dx), int(y + dy)
            if self.walls[x][y]: return 999999
            cost += self.costFn((x,y))
        return cost

class StayEastSearchAgent(SearchAgent):
    """
    An agent for position search with a cost function that penalizes being in
    positions on the West side of the board.

    The cost function for stepping into a position (x,y) is 1/2^x.
    """
    def __init__(self):
        self.searchFunction = search.uniformCostSearch
        costFn = lambda pos: .5 ** pos[0]
        self.searchType = lambda state: PositionSearchProblem(state, costFn, (1, 1), None, False)

class StayWestSearchAgent(SearchAgent):
    """
    An agent for position search with a cost function that penalizes being in
    positions on the East side of the board.

    The cost function for stepping into a position (x,y) is 2^x.
    """
    def __init__(self):
        self.searchFunction = search.uniformCostSearch
        costFn = lambda pos: 2 ** pos[0]
        self.searchType = lambda state: PositionSearchProblem(state, costFn)

def manhattanHeuristic(position, problem, info={}):
    "The Manhattan distance heuristic for a PositionSearchProblem"
    xy1 = position
    xy2 = problem.goal
    return abs(xy1[0] - xy2[0]) + abs(xy1[1] - xy2[1])

def euclideanHeuristic(position, problem, info={}):
    "The Euclidean distance heuristic for a PositionSearchProblem"
    xy1 = position
    xy2 = problem.goal
    return ( (xy1[0] - xy2[0]) ** 2 + (xy1[1] - xy2[1]) ** 2 ) ** 0.5

#####################################################
# This portion is incomplete.  Time to write code!  #
#####################################################

class CornersProblem(search.SearchProblem):
    """
    This search problem finds paths through all four corners of a layout.
    You must select a suitable state space and successor function
    """

    def __init__(self, startingGameState):
        """
        Stores the walls, pacman's starting position and corners.
        """
        self.walls = startingGameState.getWalls()
        self.startingPosition = startingGameState.getPacmanPosition()
        top, right = self.walls.height-2, self.walls.width-2
        self.corners = ((1,1), (1,top), (right, 1), (right, top))
        for corner in self.corners:
            if not startingGameState.hasFood(*corner):
                print 'Warning: no food in corner ' + str(corner)
        self._expanded = 0 # DO NOT CHANGE; Number of search nodes expanded
        # Please add any code here which you would like to use
        # in initializing the problem
        "*** YOUR CODE HERE ***"


    def getStartState(self):
        """
        Returns the start state (in your state space, not the full Pacman state
        space)
        """
        "*** YOUR CODE HERE ***"
        return (self.startingPosition, [])  #返回初始位置,以及所经过的角落位置
        #util.raiseNotDefined()

    def isGoalState(self, state):
        """
        Returns whether this search state is a goal state of the problem.
        """
        #如果当前位置是角落,并且不在已经经过的表中,将其加入,判断是否是否已经经过四个角落
        "*** YOUR CODE HERE ***"
        pos = state[0]
        Visited_Corners = state[1]

        return len(Visited_Corners)==4


        #util.raiseNotDefined()

    def getSuccessors(self, state):
        """
        Returns successor states, the actions they require, and a cost of 1.
         As noted in search.py:
            For a given state, this should return a list of triples, (successor,
            action, stepCost), where 'successor' is a successor to the current
            state, 'action' is the action required to get there, and 'stepCost'
            is the incremental cost of expanding to that successor
        """
        x,y = state[0]
        vis_corner = state[1]
        successors = []
        for action in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]:

            "*** YOUR CODE HERE ***"
            dx, dy = Actions.directionToVector(action) #下一步的行动方向
            nextx, nexty = int(x + dx), int(y + dy)
            next_node = (nextx, nexty)  #下一个点坐标
            hitsWall = self.walls[nextx][nexty]
            if not hitsWall:   #如果前方不是墙,则可以移动,否则跳过
                list_vis_corner = list(vis_corner)
                if next_node in self.corners:    #如果下一个节点是角落但未经过,将他加入,返回后继节点
                    if next_node not in list_vis_corner:
                        list_vis_corner.append( next_node )
                successor = ((next_node, list_vis_corner), action, 1)
                successors.append(successor)

        self._expanded += 1 # DO NOT CHANGE
        return successors

    def getCostOfActions(self, actions):
        """
        Returns the cost of a particular sequence of actions.  If those actions
        include an illegal move, return 999999.  This is implemented for you.
        """
        if actions == None: return 999999
        x,y= self.startingPosition
        for action in actions:
            dx, dy = Actions.directionToVector(action)
            x, y = int(x + dx), int(y + dy)
            if self.walls[x][y]: return 999999
        return len(actions)


def cornersHeuristic(state, problem):
    
    corners = problem.corners # These are the corner coordinates
    walls = problem.walls # These are the walls of the maze, as a Grid (game.py)


    node = state[0]
    un_viscorner = [item for item in corners if item not in state[1]]
    hn = minmanhattan(un_viscorner, state[0])#计算所有未经过的角落的到现在距离的最小曼哈顿值,一定比实际距离小

    return hn
def minmanhattan(corners, pos):
    #遍历所有corner的豆子,选择最小的曼哈顿距离作为启发函数
    if len(corners) == 0:
        return 0

    hn = []
    for loc in corners:
        dis = abs(loc[0] - pos[0]) + abs(loc[1] - pos[1])+ minmanhattan([c for c in corners if c != loc], loc)
        hn.append(dis)

    return min(hn)


class AStarCornersAgent(SearchAgent):
    "A SearchAgent for FoodSearchProblem using A* and your foodHeuristic"
    def __init__(self):
        self.searchFunction = lambda prob: search.aStarSearch(prob, cornersHeuristic)
        self.searchType = CornersProblem

class FoodSearchProblem:
    """
    A search problem associated with finding the a path that collects all of the
    food (dots) in a Pacman game.

    A search state in this problem is a tuple ( pacmanPosition, foodGrid ) where
      pacmanPosition: a tuple (x,y) of integers specifying Pacman's position
      foodGrid:       a Grid (see game.py) of either True or False, specifying remaining food
    """
    def __init__(self, startingGameState):
        self.start = (startingGameState.getPacmanPosition(), startingGameState.getFood())
        self.walls = startingGameState.getWalls()
        self.startingGameState = startingGameState
        self._expanded = 0 # DO NOT CHANGE
        self.heuristicInfo = {} # A dictionary for the heuristic to store information

    def getStartState(self):
        return self.start

    def isGoalState(self, state):
        return state[1].count() == 0

    def getSuccessors(self, state):
        "Returns successor states, the actions they require, and a cost of 1."
        successors = []
        self._expanded += 1 # DO NOT CHANGE
        for direction in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]:
            x,y = state[0]
            dx, dy = Actions.directionToVector(direction)
            nextx, nexty = int(x + dx), int(y + dy)
            if not self.walls[nextx][nexty]:
                nextFood = state[1].copy()
                nextFood[nextx][nexty] = False
                successors.append( ( ((nextx, nexty), nextFood), direction, 1) )
        return successors

    def getCostOfActions(self, actions):
        """Returns the cost of a particular sequence of actions.  If those actions
        include an illegal move, return 999999"""
        x,y= self.getStartState()[0]
        cost = 0
        for action in actions:
            # figure out the next state and see whether it's legal
            dx, dy = Actions.directionToVector(action)
            x, y = int(x + dx), int(y + dy)
            if self.walls[x][y]:
                return 999999
            cost += 1
        return cost

class AStarFoodSearchAgent(SearchAgent):
    "A SearchAgent for FoodSearchProblem using A* and your foodHeuristic"
    def __init__(self):
        self.searchFunction = lambda prob: search.aStarSearch(prob, foodHeuristic)
        self.searchType = FoodSearchProblem

def foodHeuristic(state, problem):
    position, foodGrid = state
    food_coordinates = foodGrid.asList()
    if not food_coordinates:
        return 0
    res = -1
    for tmp in food_coordinates:
        dist = mazeDistance(tmp, position, problem.startingGameState)
        res = max(res,dist)
    return res
class ClosestDotSearchAgent(SearchAgent):
    "Search for all food using a sequence of searches"
    def registerInitialState(self, state):
        self.actions = []
        currentState = state
        while(currentState.getFood().count() > 0):
            nextPathSegment = self.findPathToClosestDot(currentState) # The missing piece
            self.actions += nextPathSegment
            for action in nextPathSegment:
                legal = currentState.getLegalActions()
                if action not in legal:
                    t = (str(action), str(currentState))
                    raise Exception, 'findPathToClosestDot returned an illegal move: %s!\n%s' % t
                currentState = currentState.generateSuccessor(0, action)
        self.actionIndex = 0
        print 'Path found with cost %d.' % len(self.actions)

    def findPathToClosestDot(self, gameState):
        """
        Returns a path (a list of actions) to the closest dot, starting from
        gameState.
        """
        # Here are some useful elements of the startState
        startPosition = gameState.getPacmanPosition()
        food = gameState.getFood()
        walls = gameState.getWalls()
        problem = AnyFoodSearchProblem(gameState)

        "*** YOUR CODE HERE ***"
        util.raiseNotDefined()

class AnyFoodSearchProblem(PositionSearchProblem):
    """
    A search problem for finding a path to any food.

    This search problem is just like the PositionSearchProblem, but has a
    different goal test, which you need to fill in below.  The state space and
    successor function do not need to be changed.

    The class definition above, AnyFoodSearchProblem(PositionSearchProblem),
    inherits the methods of the PositionSearchProblem.

    You can use this search problem to help you fill in the findPathToClosestDot
    method.
    """

    def __init__(self, gameState):
        "Stores information from the gameState.  You don't need to change this."
        # Store the food for later reference
        self.food = gameState.getFood()

        # Store info for the PositionSearchProblem (no need to change this)
        self.walls = gameState.getWalls()
        self.startState = gameState.getPacmanPosition()
        self.costFn = lambda x: 1
        self._visited, self._visitedlist, self._expanded = {}, [], 0 # DO NOT CHANGE

    def isGoalState(self, state):
        """
        The state is Pacman's position. Fill this in with a goal test that will
        complete the problem definition.
        """
        x,y = state

        "*** YOUR CODE HERE ***"
        util.raiseNotDefined()

def mazeDistance(point1, point2, gameState):
    """
    Returns the maze distance between any two points, using the search functions
    you have already built. The gameState can be any game state -- Pacman's
    position in that state is ignored.

    Example usage: mazeDistance( (2,4), (5,6), gameState)

    This might be a useful helper function for your ApproximateSearchAgent.
    """
    x1, y1 = point1
    x2, y2 = point2
    walls = gameState.getWalls()
    assert not walls[x1][y1], 'point1 is a wall: ' + str(point1)
    assert not walls[x2][y2], 'point2 is a wall: ' + str(point2)
    prob = PositionSearchProblem(gameState, start=point1, goal=point2, warn=False, visualize=False)
    return len(search.bfs(prob))

每一小实验对应1-2个函数来进行完成,感兴趣的可以在github上搜索ucb pacman,会有一些其他人更加详细的代码解答



  • 66
    点赞
  • 330
    收藏
    觉得还不错? 一键收藏
  • 17
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值