Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- """
- 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 searchFunction=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 searchAgents
- 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 dir(searchAgents):
- heur = getattr(searchAgents, 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 dir(searchAgents) or not prob.endswith('Problem'):
- raise AttributeError, prob + ' is not a search problem type in SearchAgents.py.'
- self.searchType = getattr(searchAgents, 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)):
- """
- 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()
- self.goal = goal
- self.costFn = costFn
- if 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
- def getStartState(self):
- return self.startState
- def isGoalState(self, state):
- isGoal = state == self.goal
- # For display purposes only
- if isGoal:
- 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
- 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):
- def __init__(self):
- self.searchFunction = search.uniformCostSearch
- costFn = lambda pos: .5 ** pos[0]
- self.searchType = lambda state: PositionSearchProblem(state, costFn)
- class StayWestSearchAgent(SearchAgent):
- 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])
- #####################################################
- # 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 and corners. Hint: you'll also want to store a starting state"
- self.walls = startingGameState.getWalls()
- self.startingGameState = startingGameState
- 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
- "*** YOUR CODE HERE ***"
- # state has structure state(current_location, visited_corners_list)
- corners_to_visit = self.corners
- self.start = (startingGameState.getPacmanPosition(), corners_to_visit)
- def getStartState(self):
- "Returns the start state (in your state space, not the full Pacman state space)"
- "*** YOUR CODE HERE ***"
- return self.start
- util.raiseNotDefined()
- def isGoalState(self, state):
- "Returns whether this search state is a goal state of the problem"
- "*** YOUR CODE HERE ***"
- return len(state[1]) == 0
- 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 direction in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]:
- # Add a successor state to the successor list if the action is legal
- # Here's a code snippet for figuring out whether a new position hits a wall:
- # x,y = currentPosition
- # dx, dy = Actions.directionToVector(action)
- # nextx, nexty = int(x + dx), int(y + dy)
- # hitsWall = self.walls[nextx][nexty]
- "*** YOUR CODE HERE ***"
- x,y = state[0]
- corners_to_visit = state[1]
- new_list = []
- # copy all corners except if the current point is one of the corners
- if (x,y) in corners_to_visit:
- for corners in corners_to_visit:
- if (x,y) != corners:
- new_list.append(corners)
- else:
- for corners in corners_to_visit:
- new_list.append(corners)
- listing = tuple(new_list)
- dx, dy = Actions.directionToVector(direction)
- nextx, nexty = int(x + dx), int(y + dy)
- if not self.walls[nextx][nexty]:
- successors.append( ( ((nextx, nexty), listing), direction, 1) )
- 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.startingGameState.getPacmanPosition()
- 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.
- """
- 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 ***"
- # state[0] is the location of the current node
- # state[1] is a tuple location of the corners that have not been visited
- distance = 0
- corners_list = list(state[1])
- xy1 = state[0]
- temp = 0
- closest =0
- distance_list = []
- min_index = 0
- farthest = 0
- distance_to_closest_corner = 0
- closest = 0
- # if no corners left - we are done
- if len(corners_list) == 0:
- None
- elif len(corners_list) > 0:
- # Step 1: If there is at least one corner left, find distance to that corner
- for i in range(len(corners_list)):
- xy2 = corners_list[i]
- # put all distances into a list
- distance_list.append(abs(xy1[0] - xy2[0]) + abs(xy1[1] - xy2[1]))
- distance_to_closest_corner = min(distance_list)
- min_index = distance_list.index(distance_to_closest_corner)
- closest_corner = corners_list[min_index]
- # If using only distance to the closest corner as the heuristics,
- # Search nodes expanded on mediumCorners is 1555.
- total = 0
- # Step 2: if there are more than 1 corner left
- # find the shortest distance from the closest corner
- # to the other corner that is closest to the closest corner
- corners_list.remove(closest_corner)
- while len(corners_list) > 0:
- distance_list = []
- xy1 = closest_corner
- for i in range(len(corners_list)):
- xy2 = corners_list[i]
- # put all distances into a list
- distance_list.append(abs(xy1[0] - xy2[0]) + abs(xy1[1] - xy2[1]))
- closest = min(distance_list)
- min_index = distance_list.index(closest)
- closest_corner = corners_list[min_index]
- corners_list.remove(closest_corner)
- total = total + closest
- # distance = distance to closest + distance to the closest of the closest
- distance = distance_to_closest_corner + total
- return distance
- return 0 # Default to trivial solution
- 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
- 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
- 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):
- """
- Your heuristic for the FoodSearchProblem goes here.
- This heuristic must be admissible. If using A* ever finds a solution that is
- longer than running uniform cost search, your heuristic is *not* admissible!
- The state is a tuple ( pacmanPosition, foodGrid ) where foodGrid is a
- Grid (see game.py) of either True or False.
- If you want access to info like walls, capsules, etc., you can query the problem.
- For example, problem.walls gives you a Grid of where the walls are.
- If you want to *store* information to be reused in other calls to the heuristic,
- there is a dictionary called problem.heuristicInfo that you can use. For example,
- if you only want to count the walls once and store that value, try:
- problem.heuristicInfo['wallCount'] = problem.walls.count()
- Subsequent calls to this heuristic can access problem.heuristicInfo['wallCount']
- """
- position, foodGrid = state
- "*** YOUR CODE HERE ***"
- """
- # Number of food left (gives ~13000 nodes)
- return foodGrid.count()
- """
- # Calculate MAX manhattan distance from Pacman to food left to (gives ~9800 nodes)
- h = foodGrid.height
- w = foodGrid.width
- ct = 0
- for x in range(w):
- for y in range(h):
- if foodGrid[x][y]:
- ct = max(ct, abs(x-position[0]) + abs(y-position[1]))
- return ct
- #------------------------------------------------------------------------------
- class ClosestDotSearchAgent(SearchAgent):
- "Search for all food using a sequence of searches"
- "using A* and nullHeuristics"
- def __init__(self):
- self.searchFunction = lambda prob: search.aStarSearch(prob, nullHeuristic)
- self.searchType = ClosestDotSearchProblem
- 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, startState):
- "Returns a path (a list of actions) to the closest dot, starting in startState"
- # Here are some useful elements of the startState
- startPosition = startState.getPacmanPosition()
- food = startState.getFood()
- walls = startState.getWalls()
- "*** YOUR CODE HERE ***"
- actions = self.getSuccessors(startState)
- return actions
- util.raiseNotDefined()
- #------------------------------------------------------------------------------
- class ClosestDotSearchProblem:
- """
- 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
- 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
- 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 ApproximateSearchAgent(Agent):
- "Implement your contest entry here. Change anything but the name."
- def registerInitialState(self, state):
- "This method is called before any moves are made."
- "*** YOUR CODE HERE ***"
- def getAction(self, state):
- """
- From game.py:
- The Agent will receive a GameState (from either {pacman, capture, sonar}.py) and
- must return an action from Directions.{North, South, East, West, Stop}
- """
- "*** YOUR CODE HERE ***"
- util.raiseNotDefined()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement