From 98e39449ba5545f429e417586a99b36b193b5573 Mon Sep 17 00:00:00 2001 From: hopkinsm Date: Thu, 11 Oct 2018 13:31:41 -0700 Subject: [PATCH] Fresh search. --- code/pacman/search/search.py | 168 ++++--- code/pacman/search/searchAgents.py | 751 ++++++++++++++--------------- 2 files changed, 460 insertions(+), 459 deletions(-) diff --git a/code/pacman/search/search.py b/code/pacman/search/search.py index 23a8fe5..95575cd 100644 --- a/code/pacman/search/search.py +++ b/code/pacman/search/search.py @@ -1,4 +1,21 @@ -# search.py + + + + + + + + + + search.py + + +

search.py (original)

+
+
+# 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
@@ -12,37 +29,37 @@
 # 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
+import util
 
-class SearchProblem:
-    """
+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):
-        """
+    def getStartState(self):
+        """
         Returns the start state for the search problem.
         """
-        util.raiseNotDefined()
+        util.raiseNotDefined()
 
-    def isGoalState(self, state):
-        """
+    def isGoalState(self, state):
+        """
           state: Search state
 
         Returns True if and only if the state is a valid goal state.
         """
-        util.raiseNotDefined()
+        util.raiseNotDefined()
 
-    def getSuccessors(self, state):
-        """
+    def getSuccessors(self, state):
+        """
           state: Search state
 
         For a given state, this should return a list of triples, (successor,
@@ -50,52 +67,30 @@ def getSuccessors(self, state):
         state, 'action' is the action required to get there, and 'stepCost' is
         the incremental cost of expanding to that successor.
         """
-        util.raiseNotDefined()
+        util.raiseNotDefined()
 
-    def getCostOfActions(self, actions):
-        """
+    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()
+        util.raiseNotDefined()
 
 
-def tinyMazeSearch(problem):
-    """
+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]
-
+    from game import Directions
+    s = Directions.SOUTH
+    w = Directions.WEST
+    return  [s, s, w, s, w, w, s, w]
 
-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 generalPurposeSearch(problem, stack, heuristic=nullHeuristic):       
-    marked = set()
-    stack.push(([], problem.getStartState(), 0, 0))
-    while not stack.isEmpty():
-        (directions, nextState, costSoFar, stateValue) = stack.pop()
-        if problem.isGoalState(nextState):
-            return directions
-        if nextState not in marked:
-            successors = problem.getSuccessors(nextState)
-            for (successor, direction, cost) in successors:
-                hCost = heuristic(successor, problem)
-                stack.push((directions + [direction], successor, costSoFar + cost, costSoFar + cost + hCost))
-                marked.add(nextState)
-
-def depthFirstSearch(problem):
-    """
+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
@@ -108,32 +103,59 @@ def depthFirstSearch(problem):
     print "Is the start a goal?", problem.isGoalState(problem.getStartState())
     print "Start's successors:", problem.getSuccessors(problem.getStartState())
     """
-    # Problem with this code: does not use linear space
-    return generalPurposeSearch(problem, util.Stack())
-
-
-def breadthFirstSearch(problem):
-    """Search the shallowest nodes in the search tree first."""
-    return generalPurposeSearch(problem, util.Queue())
+    "*** YOUR CODE HERE ***"
+    util.raiseNotDefined()
 
+def breadthFirstSearch(problem):
+    """Search the shallowest nodes in the search tree first."""
+    "*** YOUR CODE HERE ***"
+    util.raiseNotDefined()
 
-def uniformCostSearch(problem):
-    """Search the node of least total cost first."""
-    return generalPurposeSearch(
-            problem, 
-            util.PriorityQueueWithFunction(lambda x: x[2]))
-            
+def uniformCostSearch(problem):
+    """Search the node of least total cost first."""
+    "*** YOUR CODE HERE ***"
+    util.raiseNotDefined()
 
-def aStarSearch(problem, heuristic=nullHeuristic):
-    """Search the node that has the lowest combined cost and heuristic first."""
-    return generalPurposeSearch(
-            problem, 
-            util.PriorityQueueWithFunction(lambda x: x[3]),
-            heuristic)
-
-
-# Abbreviations
-bfs = breadthFirstSearch
-dfs = depthFirstSearch
-astar = aStarSearch
-ucs = uniformCostSearch
+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 ***"
+    util.raiseNotDefined()
+
+
+# Abbreviations
+bfs = breadthFirstSearch
+dfs = depthFirstSearch
+astar = aStarSearch
+ucs = uniformCostSearch
+
+  
+ + + + diff --git a/code/pacman/search/searchAgents.py b/code/pacman/search/searchAgents.py index 8d78f7c..eddacc3 100644 --- a/code/pacman/search/searchAgents.py +++ b/code/pacman/search/searchAgents.py @@ -1,4 +1,21 @@ -# searchAgents.py + + + + + + + + + + searchAgents.py + + +

searchAgents.py (original)

+
+
+# 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
@@ -12,13 +29,13 @@
 # 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
+> python pacman.py -p SearchAgent -a fn=depthFirstSearch
 
 Commands to invoke other search strategies can be found in the project
 description.
@@ -34,30 +51,30 @@
 Good luck and happy searching!
 """
 
-from game import Directions
-from game import Agent
-from game import Actions
-import util
-import time
-import search
+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."
+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
+    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):
-    """
+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.
@@ -73,35 +90,35 @@ class SearchAgent(Agent):
     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
+    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):
-        """
+        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.
@@ -109,32 +126,32 @@ def registerInitialState(self, state):
 
         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):
-        """
+        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):
-    """
+        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.
@@ -144,44 +161,44 @@ class PositionSearchProblem(search.SearchProblem):
     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):
-        """
+    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):
-        """
+        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:
@@ -192,119 +209,120 @@ def getSuccessors(self, state):
          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):
-        """
+        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):
-    """
+        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)
+    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):
-    """
+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
-
-#####################################################
+    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):
-    """
+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):
-        """
+    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
+        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 ***"
+        "*** YOUR CODE HERE ***"
 
-    def getStartState(self):
-        """
+    def getStartState(self):
+        """
         Returns the start state (in your state space, not the full Pacman state
         space)
         """
-        visitedCorners = tuple([x == self.startingPosition for x in self.corners])
-        return (self.startingPosition, visitedCorners)
+        "*** YOUR CODE HERE ***"
+        util.raiseNotDefined()
 
-    def isGoalState(self, state):
-        """
+    def isGoalState(self, state):
+        """
         Returns whether this search state is a goal state of the problem.
         """
-        return state[1] == (True, True, True, True)
+        "*** YOUR CODE HERE ***"
+        util.raiseNotDefined()
 
-    def getSuccessors(self, state):
-        """
+    def getSuccessors(self, state):
+        """
         Returns successor states, the actions they require, and a cost of 1.
 
          As noted in search.py:
@@ -314,39 +332,36 @@ def getSuccessors(self, state):
             is the incremental cost of expanding to that successor
         """
 
-        successors = []
-        (currentPosition, goals) = state
-        for action in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]:
-            # Add a successor state to the successor list if the action is legal
+        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
             # 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]
-            if not hitsWall:
-                revisedGoals = tuple([goals[i] or (nextx, nexty) == corner 
-                                      for (i, corner) in enumerate(self.corners)])
-                successors.append((((nextx, nexty), revisedGoals), action, 1))
-
-        self._expanded += 1 # DO NOT CHANGE
-        return successors
-
-    def getCostOfActions(self, actions):
-        """
+            #   x,y = currentPosition
+            #   dx, dy = Actions.directionToVector(action)
+            #   nextx, nexty = int(x + dx), int(y + dy)
+            #   hitsWall = self.walls[nextx][nexty]
+
+            "*** YOUR CODE HERE ***"
+
+        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)
+        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):
-    """
+def cornersHeuristic(state, problem):
+    """
     A heuristic for the CornersProblem that you defined.
 
       state:   The current search state
@@ -358,38 +373,20 @@ def cornersHeuristic(state, problem):
     shortest path from the state to a goal of the problem; i.e.  it should be
     admissible (as well as consistent).
     """
-    def manhattanDist(xy1, xy2):
-        return abs(xy1[0] - xy2[0]) + abs(xy1[1] - xy2[1])
-    
-    def manhattanHeuristicRecursive(position, extraPositions):
-        "The Manhattan distance heuristic for a CornerSearchProblem"
-        if len(extraPositions) == 0:
-            return 0
-        distances = [(manhattanDist(position, extraPosition), extraPosition) for extraPosition in extraPositions]
-        sortedDistances = sorted(distances)
-        if len(distances) > 1:
-            extra = manhattanHeuristicRecursive(sortedDistances[0][1], [pos for (i, pos) in sortedDistances[1:]])
-        else:
-            extra = 0
-        return sortedDistances[0][0] + extra
-
-    corners = problem.corners # These are the corner coordinates
-    walls = problem.walls # These are the walls of the maze, as a Grid (game.py)
-    if problem.isGoalState(state):
-        return 0
-    (currentPosition, visitedCorners) = state
-    activeCorners = [corner for (i, corner) in enumerate(corners) if not visitedCorners[i]]
-    heuristic = manhattanHeuristicRecursive(currentPosition, activeCorners)
-    return heuristic
-
-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:
-    """
+    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 ***"
+    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.
 
@@ -397,55 +394,55 @@ class FoodSearchProblem:
       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
+    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):
-    """
+        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 consistent to ensure correctness.  First, try to come
@@ -472,88 +469,43 @@ def foodHeuristic(state, problem):
     Subsequent calls to this heuristic can access
     problem.heuristicInfo['wallCount']
     """
-    position, foodGrid = state
-    heuristics = FoodHeuristics()
-    heuristic = heuristics.mstHeuristic([position] + foodGrid.asList())
-    return heuristic
-
-
-""" 
-The following are three food heuristics that obtain scores of 2/4,
-3/4, and 4/4.
-"""
-class FoodHeuristics:
-
-    def euclideanDist(self, xy1, xy2):
-        return ( (xy1[0] - xy2[0]) ** 2 + (xy1[1] - xy2[1]) ** 2 ) ** 0.5
-
-    def simpleFoodHeuristic(self, state, problem):
-        """
-        Just checks how much food is left.
-        
-        Gets 2/4.
-        """
-        position, foodGrid = state
-        return len(foodGrid.asList())
-
-    def minimalDistHeuristic(self, position, extraPositions):
-        """
-        Gets 3/4
-        """
-        def findMinimalDist(position, extraPositions):
-            dists = [self.euclideanDist(position, pos2) for pos2 in extraPositions]
-            return min(dists)
-        minimalDists = [findMinimalDist(pos, list(set(extraPositions) - set([pos])) + [position]) for pos in extraPositions]
-        return sum(sorted(minimalDists))
-
-    def mstHeuristic(self, dots):
-        """
-        Gets 4/4
-        """
-        from scipy.sparse import csr_matrix
-        from scipy.sparse.csgraph import minimum_spanning_tree
-        pairs = [(i, j) for i in range(len(dots)) for j in range(len(dots)) if i < j]
-        row = [dot1 for (dot1, dot2) in pairs]
-        col = [dot2 for (dot1, dot2) in pairs]
-        data = [self.euclideanDist(dots[dot1], dots[dot2]) for (dot1, dot2) in pairs]
-        matrix = csr_matrix((data, (row, col)), shape=(len(dots), len(dots)))
-        Tcsr = minimum_spanning_tree(matrix)
-        return Tcsr.sum()
-    
-    
-
-
-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):
-        """
+    position, foodGrid = state
+    "*** YOUR CODE HERE ***"
+    return 0
+
+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)
-        return search.bfs(problem)
-
-class AnyFoodSearchProblem(PositionSearchProblem):
-    """
+        # 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
@@ -567,27 +519,29 @@ class AnyFoodSearchProblem(PositionSearchProblem):
     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()
+    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
+        # 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):
-        """
+    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
-        return state in self.food.asList()
+        x,y = state
 
-def mazeDistance(point1, point2, gameState):
-    """
+        "*** 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.
@@ -596,10 +550,35 @@ def mazeDistance(point1, point2, 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))
+    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))
+
+  
+ + + +