人工智能实验 搜索策略(pacman)吃豆人 您所在的位置:网站首页 astar算法代码 人工智能实验 搜索策略(pacman)吃豆人

人工智能实验 搜索策略(pacman)吃豆人

2023-08-21 13:42| 来源: 网络整理| 查看: 265

目录

问题1:深度优先算法

问题2:广度优先搜索

问题3:不同的费用

问题4:A*搜索

问题5:查找所有角落

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

问题7:吃掉所有的“豆”

对象总览

具体代码

具体项目见

https://github.com/chunxi-alpc/gcx_pacman

问题1:深度优先算法

在search.py中depthFirstSearch函数中实现深度优先算法。

在cmd 输入 Python2 pacman.py -l mediumMaze -p SearchAgent -a fn=dfs

 

[SearchAgent] using function dfs

[SearchAgent] using problem type PositionSearchProblem

Path found with total cost of 130 in 0.0 seconds

Search nodes expanded: 146

Pacman emerges victorious! Score: 380

Average Score: 380.0

Scores:        380.0

Win Rate:      1/1 (1.00)

Record:        Win

对于已经搜索过的状态Pacman棋盘上将显示一个叠加物(overlay),并显示出访问的顺序(红色由深到浅). Pacman 在到达目的地的过程中,并不是遍访每个正方形,而是把一种走法显示出来。

使用栈Stack数据结构, 则通过DFS算法求得的mediumMaze的解长度应该为130 (假定你将后继元素按getSuccessors得到的顺序压栈; 如果按相反顺序压栈,则可能是244). 这可能不是最短的路径。因为为了时间和效率,我们只追求搜索到满足目标测试的情况,DFS扩展深度最大的节点,因此第一次满足目标测试的动作序列不一定是最短的路径。

问题2:广度优先搜索

在search.py中breadthFirstSearch函数中,实现广度优先搜索 (BFS) 算法。

在cmd 输入 Python2 pacman.py -l mediumMaze -p SearchAgent -a fn=bfs

[SearchAgent] using function bfs

[SearchAgent] using problem type PositionSearchProblem

Path found with total cost of 68 in 0.0 seconds

Search nodes expanded: 269

Pacman emerges victorious! Score: 442

Average Score: 442.0

Scores:        442.0

Win Rate:      1/1 (1.00)

Record:        Win

提示: 如Pacman移动太慢,可以试一下选项--frameTime 0

注意: 如果你的搜索代码具有通用性, 则不用做任何修改,该代码将同样能对eight-puzzle搜索问题适用。

问题3:不同的费用

通过修改代价函数,我们鼓励Pacman发现不同路径。例如,有恶魔的区域,我们增加每步的代价,而在食物丰富的区域减少每步的代价,一个理性的Pacman应该相应地调整它的行为。

在search.py的uniformCostSearch函数中,实现一致代价图搜索算法。util.py中有一些数据结构,也许会对你的实现有用。现在你应该能观察到在下面三个样板中的成功行为,所使用的智能体都是UCS(uniform cost search)智能体,其唯一区别是所使用的费用函数(其智能体和费用函数已经帮你写好了):

Python2 pacman.py -l mediumMaze -p SearchAgent -a fn=ucs

Python2 pacman.py -l mediumDottedMaze -p StayEastSearchAgent

Python2 pacman.py -l mediumScaryMaze -p StayWestSearchAgent

注: 由于其指数费用函数,在StayEastSearchAgent 和 StayWestSearchAgent中,你将分别看到很低的和很高的路径费用total  cost(详细细节可见searchAgents.py).

[SearchAgent] using function ucs

[SearchAgent] using problem type PositionSearchProblem

Path found with total cost of 68 in 0.0 seconds

Search nodes expanded: 269

Pacman emerges victorious! Score: 442

Average Score: 442.0

Scores:        442.0

Win Rate:      1/1 (1.00)

Record:        Win

问题4:A*搜索

在search.py的aStarSearch函数中实现A*图搜索。 A*输入参数包括一个启发式函数。启发式函数有两个输入变量:搜索问题的状态 (主参数), 和问题本身(相关参考信息). search.py中的nullHeuristic 启发函数是一个普通的实例.可以针对求通过迷宫到达固定点的原问题来测试A*实现,具体可使用Manhattan距离启发(已经在searchAgents.py中实现为 manhattanHeuristic).

Python2 pacman.py -l bigMaze -z .5 -p SearchAgent -a fn=astar,heuristic=manhattanHeuristic

[SearchAgent] using function astar and heuristic manhattanHeuristic

[SearchAgent] using problem type PositionSearchProblem

Path found with total cost of 210 in 0.1 seconds

Search nodes expanded: 549

Pacman emerges victorious! Score: 300

Average Score: 300.0

Scores:        300.0

Win Rate:      1/1 (1.00)

Record:        Win

问题5:查找所有角落

注意:确保你已经完成问题2,然后再来完成问题5,因为问题5依赖于问题2的答案。

A*搜索的真正强大之处,在具有更大挑战性的问题上才能显现。下面,我们需要先构造一个新问题,然后为其设计一个启发式的算法。

在角落迷宫corner mazes中, 四个角上各有一颗豆。我们新的搜索问题是找到穿过迷宫碰到所有四个角的最短路径(不论在迷宫中是否真有食物).  注意,对于象tinyCorners这样的迷宫, 最短路径不一定总是先找最近的食物! 提示: 通过tinyCorners的最短路径需要28步.

在searchAgents.py中实现CornersProblem搜索问题。你需要选择一种状态表示方法,该方法可以对所有必要的信息编码,以便测定所有四个角点是否达到。现在, 搜索智能体应该可解下面的问题:

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

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

进一步,需要定义一个抽象的状态表示,该表示不对无关信息编码(如恶魔的位置, 其他食物的位置等)。特别是不要使用Pacman的GameState作为搜索状态。如果这样,你的代码会非常、非常慢(还出错).

提示: 在实现中,你需要访问的唯一游戏状态是Pacman的起始位置和四个角点的位置。

[SearchAgent] using function bfs

[SearchAgent] using problem type CornersProblem

Path found with total cost of 106 in 0.2 seconds

Search nodes expanded: 1966

Pacman emerges victorious! Score: 434

Average Score: 434.0

Scores:        434.0

Win Rate:      1/1 (1.00)

Record:        Win

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

注意:确保你已经完成问题4,然后再来完成问题6,因为问题6依赖于问题4的答案。   

对CornersProblem实现一个启发式搜索cornersHeuristic。请在你的实现前面加上必要的备注。

Python2 pacman.py -l mediumCorners -p AStarCornersAgent -z 0.5

注意:AStarCornersAgent 是 -p SearchAgent -a fn=aStarSearch,prob=CornersProblem,heuristic=cornersHeuristic的缩写。

Path found with total cost of 106 in 0.1 seconds

Search nodes expanded: 692

Pacman emerges victorious! Score: 434

Average Score: 434.0

Scores:        434.0

Win Rate:      1/1 (1.00)

Record:        Win

 

 

问题7:吃掉所有的“豆”

接下来,我们求解一个困难的搜索问题: 使用尽量少的步骤吃掉所有的食物。对此次作业,我们需要定义一个新的搜索问题,在该定义中正确描述吃掉所有食物的问题: 在searchAgents.py中的FoodSearchProblem (已经实现好了). 问题的解定义为一条收集到世界中所有食物的路径。在现在的项目中,不考虑”魔鬼“或"能量药“的存在; 解仅依赖于墙和正常食物在Pacman中的位置(当然,“魔鬼”会损坏解!) 。如果你已经正确地完成了通用搜索算法, 使用null heuristic (等价于一致费用搜索UCS) 的A* 将很快求得testSearch问题的最优解,而不用大家写任何代码(总费用7).

Python2 pacman.py -l testSearch -p AStarFoodSearchAgent

注: AStarFoodSearchAgent是-p SearchAgent -a fn=astar,prob=FoodSearchProblem,heuristic=foodHeuristic的缩写.

你将看到UCS开始慢下来,即使对看起来简单的tinySearch问题。

注意:确保你已经完成问题4,然后再来完成问题7,因为问题7依赖于问题4的答案。

针对FoodSearchProblem,使用一致性启发式函数,在searchAgents.py中完成foodHeuristic。在函数开头添加必要的注释描述你的启发式函数。测试你的Agent:

Python2 pacman.py -l trickySearch -p AStarFoodSearchAgent

问题8:次优搜索

有的时候,即使使用 A* 加上好的启发式,求通过所有“豆”的最优路径也是困难的。此时,我们还是希望能尽快地求得一个足够好的路径。在本节中,你需要写出一个智能体,它总是吃掉最近的豆. 在searchAgents.py中已经实现了ClosestDotSearchAgent, 但缺少一个关键函数,该函数搜索到最近豆的路径。

在文件searchAgents.py中实现findPathToClosestDot函数。

python pacman.py -l bigSearch -p ClosestDotSearchAgent -z .5

提示: 完成 findPathToClosestDot 的最快方式是填满AnyFoodSearchProblem, 该问题缺少目标测试。然后,使用合适的搜索函数来求解问题。解会非常短!

你的ClosestDotSearchAgent 并不总能找到通过迷宫的可能的最短路径。事实上,如果你尝试,你可以做得更好。

对象总览

下面是基础代码中与搜索问题有关的重要对象的总览,供大家参考:

SearchProblem (search.py)

SearchProblem是一个抽象对象,该对象表示状态空间,费用,和问题的目标状态。你只能通过定义在search.py顶上的方法来与SearchProblem交互

PositionSearchProblem (searchAgents.py)

需要处理的一种特别的SearchProblem类型 --- 对应于在迷宫中搜索单个肉丸pellet.

CornersProblem (searchAgents.py)

一种需要定义的特别的SearchProblem问题 --- 目的是搜索出一条到达迷宫中所有四个角点的路径.

FoodSearchProblem (searchAgents.py)

一个特定的需要解决的搜索问题。

Search Function

搜索函数是一个函数,该函数以SearchProblem的一个实例作为输入 , 运行一些算法, 返回值一列到达目标的行为. 搜索函数的实例有depthFirstSearch 和 breadthFirstSearch, 这些都要你编写。我们提供了tinyMazeSearch函数,该函数是一个非常差的函数,只能对tinyMaze得到正确结果

SearchAgent

SearchAgent是实现智能体Agent的类(它与世界交互) 且通过搜索函数做出规划。SearchAgent首先使用所提供的搜索函数规划出到达目标状态的行为,然后一次执行一个动作。

具体代码 # coding=UTF-8 # search.py """ 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): #初始状态 s = problem.getStartState() #标记已经搜索过的状态集合exstates exstates = [] #用栈实现dfs states = util.Stack() states.push((s, [])) #循环终止条件:遍历完毕/目标测试成功 while not states.isEmpty() and not problem.isGoalState(s): state, actions = states.pop() exstates.append(state) successor = problem.getSuccessors(state) for node in successor: coordinates = node[0] direction = node[1] #判断状态是否重复 if not coordinates in exstates: states.push((coordinates, actions + [direction])) #把最后搜索的状态赋值到s,以便目标测试 s = coordinates #返回动作序列 return actions + [direction] util.raiseNotDefined() def breadthFirstSearch(problem): #初始状态 s = problem.getStartState() #标记已经搜索过的状态集合exstates exstates = [] #用队列queue实现bfs states = util.Queue() states.push((s, [])) while not states.isEmpty(): state, action = states.pop() #目标测试 if problem.isGoalState(state): return action #检查重复 if state not in exstates: successor = problem.getSuccessors(state) exstates.append(state) #把后继节点加入队列 for node in successor: coordinates = node[0] direction = node[1] if coordinates not in exstates: states.push((coordinates, action + [direction])) #返回动作序列 return action util.raiseNotDefined() def uniformCostSearch(problem): #初始状态 start = problem.getStartState() #标记已经搜索过的状态集合exstates exstates = [] #用优先队列PriorityQueue实现ucs states = util.PriorityQueue() states.push((start, []) ,0) while not states.isEmpty(): state, actions = states.pop() #目标测试 if problem.isGoalState(state): return actions #检查重复 if state not in exstates: #扩展 successors = problem.getSuccessors(state) for node in successors: coordinate = node[0] direction = node[1] if coordinate not in exstates: newActions = actions + [direction] #ucs比bfs的区别在于getCostOfActions决定节点扩展的优先级 states.push((coordinate, actions + [direction]), problem.getCostOfActions(newActions)) exstates.append(state) return actions 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 f(n) and heuristic g(n) first." start = problem.getStartState() exstates = [] # 使用优先队列,每次扩展都是选择当前代价最小的方向 states = util.PriorityQueue() states.push((start, []), nullHeuristic(start, problem)) nCost = 0 while not states.isEmpty(): state, actions = states.pop() #目标测试 if problem.isGoalState(state): return actions #检查重复 if state not in exstates: #扩展 successors = problem.getSuccessors(state) for node in successors: coordinate = node[0] direction = node[1] if coordinate not in exstates: newActions = actions + [direction] #计算动作代价和启发式函数值得和 newCost = problem.getCostOfActions(newActions) + heuristic(coordinate, problem) states.push((coordinate, actions + [direction]), newCost) exstates.append(state) #返回动作序列 return actions util.raiseNotDefined() # Abbreviations bfs = breadthFirstSearch dfs = depthFirstSearch astar = aStarSearch ucs = uniformCostSearch # coding=UTF-8 # searchAgents.py # --------------- """ 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 import sys 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='uniformCostSearch', 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' self._visited, self._visitedlist, self._expanded = {}, [], 0 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 # Number of search nodes expanded # Please add any code here which you would like to use # in initializing the problem "*** YOUR CODE HERE ***" self.right = right self.top = top def getStartState(self): """ Returns the start state (in your state space, not the full Pacman state space) """ "*** YOUR CODE HERE ***" #初始节点(开始位置,角落情况) allCorners = (False, False, False, False) start = (self.startingPosition, allCorners) return start util.raiseNotDefined() def isGoalState(self, state): """ Returns whether this search state is a goal state of the problem. """ "*** YOUR CODE HERE ***" #目标测试:四个角落都访问过 corners = state[1] boolean = corners[0] and corners[1] and corners[2] and corners[3] return boolean 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 """ successors = [] #遍历能够做的后续动作 for action in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]: # Add a successor state to the successor list if the action is legal "*** YOUR CODE HERE ***" # x,y = currentPosition x,y = state[0] holdCorners = state[1] # dx, dy = Actions.directionToVector(action) dx, dy = Actions.directionToVector(action) nextx, nexty = int(x + dx), int(y + dy) hitsWall = self.walls[nextx][nexty] newCorners = () nextState = (nextx, nexty) #不碰墙 if not hitsWall: #能到达角落,四种情况判断 if nextState in self.corners: if nextState == (self.right, 1): newCorners = [True, holdCorners[1], holdCorners[2], holdCorners[3]] elif nextState == (self.right, self.top): newCorners = [holdCorners[0], True, holdCorners[2], holdCorners[3]] elif nextState == (1, self.top): newCorners = [holdCorners[0], holdCorners[1], True, holdCorners[3]] elif nextState == (1,1): newCorners = [holdCorners[0], holdCorners[1], holdCorners[2], True] successor = ((nextState, newCorners), action, 1) #去角落的中途 else: successor = ((nextState, holdCorners), action, 1) successors.append(successor) self._expanded += 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. 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): """ A heuristic for the CornersProblem that you defined. state: The current search state (a data structure you chose in your search problem) problem: The CornersProblem instance for this layout. This function should always return a number that is a lower bound on the shortest path from the state to a goal of the problem; i.e. it should be admissible (as well as consistent). """ corners = problem.corners # These are the corner coordinates walls = problem.walls # These are the walls of the maze, as a Grid (game.py) "*** YOUR CODE HERE ***" position = state[0] stateCorners = state[1] corners = problem.corners top = problem.walls.height-2 right = problem.walls.width-2 node = [] for c in corners: if c == (1,1): if not stateCorners[3]: node.append(c) if c == (1, top): if not stateCorners[2]: node.append(c) if c == (right, top): if not stateCorners[1]: node.append(c) if c == (right, 1): if not stateCorners[0]: node.append(c) cost = 0 currPosition = position while len(node) > 0: distArr= [] for i in range(0, len(node)): dist = util.manhattanDistance(currPosition, node[i]) distArr.append(dist) mindist = min(distArr) cost += mindist minDistI= distArr.index(mindist) currPosition = node[minDistI] del node[minDistI] return cost 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): """ 状态是一个元组(pacmanPosition,foodGrid) 其中foodGrid是一个Grid(参见game.py) 调用foodGrid.asList()来获取食物坐标列表。 如果你想存储信息,可以在其他调用中重复使用 启发式,你可以使用一个名为problem.heuristicInfo的字典 例如,如果您只想计算一次墙壁并存储它 尝试:problem.heuristicInfo ['wallCount'] = problem.walls.count() 对此启发式的后续调用可以访问 problem.heuristicInfo [ 'wallCount'] """ position, foodGrid = state "*** YOUR CODE HERE ***" hvalue = 0 food_available = [] total_distance = 0 #处理食物的位置,以此构造启发式函数 for i in range(0,foodGrid.width): for j in range(0,foodGrid.height): if (foodGrid[i][j] == True): food_location = (i,j) food_available.append(food_location) #没有食物就不用找了 if (len(food_available) == 0): return 0 #初始化距离(current_food,select_food,distance) max_distance=((0,0),(0,0),0) for current_food in food_available: for select_food in food_available: if(current_food==select_food): pass else: #使用曼哈顿距离构造启发式函数 distance = util.manhattanDistance(current_food,select_food) if(max_distance[2] < distance): max_distance = (current_food,select_food,distance) #把起点和第一个搜索的食物连接起来 #处理只有一个食物的情况 if(max_distance[0]==(0,0) and max_distance[1]==(0,0)): hvalue = util.manhattanDistance(position,food_available[0]) else: d1 = util.manhattanDistance(position,max_distance[0]) d2 = util.manhattanDistance(position,max_distance[1]) hvalue = max_distance[2] + min(d1,d2) return hvalue 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 ***" return search.aStarSearch(problem) 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): x,y = state if self.food[x][y]: return True else: return False """ 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 ***" foodGrid = self.food if (foodGrid[x][y] == True) or (foodGrid.count() == 0): return True util.raiseNotDefined() ################## # Mini-contest 1 # ################## class ApproximateSearchAgent(Agent): def registerInitialState(self, state): self.walls = state.getWalls() self.mark = 0 self.curPos = state.getPacmanPosition() self.path = [] self.path.append(self.curPos) self.starttime = time.time() self.path = ApproximateSearchAgent.findPath2(self,state) self.cost = 0 self.DisRecord = {} self.mark = 0 self.disTime = 0 self.pT = 0 self.m = [[0 for col in range(450)] for row in range(450)] ApproximateSearchAgent.initFloyed(self) # print ApproximateSearchAgent.getTotalDistance(self,self.path,state) # print self.path # print len(self.path) self.path = ApproximateSearchAgent.TwoOpt(self,state) # print ApproximateSearchAgent.brutalDis(self,self.path,state) # print time.time() - self.starttime def initFloyed(self): size = len(self.path) for i in range(0,size): x,y=self.path[i] if (x+1,y) in self.path: self.m[x+y*30][x+1+y*30]=1 self.m[x+1+y*30][x+y*30]=1 if (x-1,y) in self.path: self.m[x+y*30][x-1+y*30]=1 self.m[x-1+y*30][x+y*30]=1 if (x,y+1) in self.path: self.m[x+(y+1)*30][x+y*30]=1 self.m[x+y*30][x+(y+1)*30]=1 if (x,y-1) in self.path: self.m[x+(y-1)*30][x+y*30]=1 self.m[x+y*30][x+(y-1)*30]=1 for k in range(0,size): for i in range(0,size): if not(i==k): for j in range(0,size): if not(i==j) and not(j==k): tx,ty=self.path[k] pk=tx+ty*30 tx,ty=self.path[i] pi=tx+ty*30 tx,ty=self.path[j] pj=tx+ty*30 if not(self.m[pi][pk]==0) and not(self.m[pk][pj]==0): if self.m[pi][pj]==0 or self.m[pi][pk]+self.m[pk][pj] 0: minDis = 9999999 for pos in foodMap: t = util.manhattanDistance(curPos,pos) if t < minDis: minDis = t nextpos = pos originPath.append(nextpos) foodMap.remove(nextpos) curPos = nextpos return originPath # greedy path def findPath2(self, state): from game import Directions s = Directions.SOUTH w = Directions.WEST n = Directions.NORTH e = Directions.EAST originPath = [] foodMap = state.getFood() unvisited = foodMap.asList() curPos = state.getPacmanPosition() originPath.append(curPos) while len(unvisited) > 0: minDis = 999999 minMD = 999999 for pos in unvisited: # print curPos, pos t = util.manhattanDistance(curPos,pos) if t < minDis: tt = mazeDistance(curPos,pos,state) if tt < minMD: minDis = t minMD = tt nextpos = pos prob = PositionSearchProblem(state, start=curPos, goal=nextpos, warn=False, visualize=False) move = search.bfs(prob)[0] x, y = curPos if move == s: y -= 1 if move == w: x -= 1 if move == n: y += 1 if move == e: x += 1 curPos = (x,y) if curPos in unvisited: unvisited.remove(curPos) originPath.append(curPos) return originPath def TwoOpt(self, state): size = len(self.path) improve = 0 bestDis = ApproximateSearchAgent.getTotalDistance(self,self.path,state) while improve < 20: #print bestDis for i in range(1,size - 1): for k in range (i+1, min(i+size/2,size)): newPath = ApproximateSearchAgent.TwoOptSwap(self,i,k) newDis = ApproximateSearchAgent.newTotalDistance(self,i,k,self.path,state,bestDis) if newDis = len(thispath): return 0 tx,ty=thispath[start] p1=tx+ty*30 tx,ty=thispath[end] p2=tx+ty*30 return self.m[p1][p2] def getTotalDistance(self,thispath,state): # dt0 = time.time() totalDis = 0 for i in range(len(thispath) - 1): tx,ty=thispath[i] p1=tx+ty*30 tx,ty=thispath[i+1] p2=tx+ty*30 totalDis += self.m[p1][p2] """ if self.DisRecord.has_key((thispath[i],thispath[i+1])): totalDis += self.DisRecord[(thispath[i],thispath[i+1])] else: self.DisRecord[(thispath[i],thispath[i+1])] = mazeDistance(thispath[i],thispath[i+1],state) totalDis += self.DisRecord[(thispath[i],thispath[i+1])] """ #totalDis += mazeDistance(thispath[i],thispath[i+1],state) # dt = time.time() - dt0 # self.disTime += dt # print self.disTime return totalDis def brutalDis(self,thispath,state): totalDis = 0 for i in range(len(thispath) - 1): totalDis += mazeDistance(thispath[i],thispath[i+1],state) return totalDis def getAction(self, state): if self.pT == 0: # print self.disTime self.pT = 1 curPos = state.getPacmanPosition() if self.path[self.mark] == curPos: self.mark += 1 nextpos = self.path[self.mark] prob = PositionSearchProblem(state, start=curPos, goal=nextpos, warn=False, visualize=False) move = (search.bfs(prob))[0] self.cost += 1 #print self.cost #print time.time() - self.starttime return move 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: ' + 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))

 



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有