summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--searchAgents.py139
1 files changed, 85 insertions, 54 deletions
diff --git a/searchAgents.py b/searchAgents.py
index e990dce..a203795 100644
--- a/searchAgents.py
+++ b/searchAgents.py
@@ -4,8 +4,9 @@
# Project 1
# Due: Sept. 14th, 2021
#
-# TODO NAME
-# Partner: TODO NAME
+# TODO Add name
+# Name:
+# Partner:
#
@@ -504,15 +505,12 @@ def foodHeuristic(state, problem):
Subsequent calls to this heuristic can access
problem.heuristicInfo['wallCount']
"""
-
- # manhattanDist = lambda pos1, pos2: abs(pos1[0] - pos2[0]) + abs(pos1[1] - pos2[1])
-
+
+ # returns an estimation of the traversal cost between two points
def getDistance(pos1, pos2):
- # Manhattan Distance
- distance = abs(pos1[0] - pos2[0]) + abs(pos1[1] - pos2[1])
- # Returns the penalty for a full bisection of walls along the a given axis, or if none are found, 0
- # -952 nodes expanded (6700/7652)
+ # Returns the penalty for a full bisection of walls along the a given
+ # axis, or if none are found, returns 0. -952 nodes expanded (6700/7652)
def wallPenalty(arrayLambda, axis):
# Get the other axis index
other = int(not axis)
@@ -524,59 +522,82 @@ def foodHeuristic(state, problem):
upperBound = max((pos2[other], pos1[other]))
# Only run if the secondary axis's width is > 1
- if lowerBound != upperBound:
-
- # Loop though each line in primary axis between the two positions
- for item in range(axisLowerBound, axisUpperBound):
-
- # The lambda is used to generically return an array of isWall's for each line
- wallArray = arrayLambda(item)
-
- # Slice the array of walls using the bounds
- wallsBetween = wallArray[lowerBound:upperBound]
-
- # Check if all the spaces between the bounds are walls
- if all(wallsBetween):
-
- # Initialize the penalty to 2 (minimum to get around the line of walls)
- penalty = 2
- lowerWall = lowerBound + 1
- upperWall = upperBound + 1
-
- # For each distance the wall exends out on both sides, increase the penalty by 1
- while lowerWall >= 0 and upperWall < len(wallArray) and wallArray[lowerWall] and wallArray[upperWall]:
- penalty += 1
- lowerWall += 1
- upperWall += 1
- return penalty
+ if lowerBound == upperBound:
+ return 0
+
+ # Loop though each line in primary axis between two positions
+ for item in range(axisLowerBound, axisUpperBound):
+
+ # The lambda is used to generically return an array of
+ # isWall's for each line
+ wallArray = arrayLambda(item)
+
+ # Slice the array of walls using the bounds
+ wallsBetween = wallArray[lowerBound:upperBound]
+
+ # Check if all the spaces between the bounds are walls
+ if not all(wallsBetween):
+ continue
+
+ # Initialize the penalty to 2 (minimum to get around
+ # the line of walls)
+ penalty = 2
+ lowerWall = lowerBound + 1
+ upperWall = upperBound + 1
+
+ # For each distance the wall exends out on both sides and
+ # increase the penalty by 1
+ while (
+ lowerWall >= 0
+ and upperWall < len(wallArray)
+ and wallArray[lowerWall]
+ and wallArray[upperWall]
+ ):
+ penalty += 1
+ lowerWall += 1
+ upperWall += 1
+ return penalty
+
return 0
- # Check for a full bisection of walls along the x axis,
+ # Manhattan Distance
+ distance = abs(pos1[0] - pos2[0]) + abs(pos1[1] - pos2[1])
+
+ # Check for a full bisection of walls along the x axis,
# if found, return the penalty + Manhattan Distance
penalty = wallPenalty(lambda x: wallGrid[x], 0)
if penalty > 0:
return distance + penalty
- # Check for a full bisection of walls along the y axis,
+ # Check for a full bisection of walls along the y axis,
# if found, return the penalty + Manhattan Distance
penalty = wallPenalty(lambda y: [axis[y] for axis in wallGrid], 1)
if penalty > 0:
return distance + penalty
- # If no wall bisections were found, but the "box" is width/length of 1, return the path
+ # If no wall bisections were found and the "box" is 1xK or Kx1,
+ # return the path
if pos2[0] == pos1[0] or pos2[1] == pos1[1]:
return distance
- # Lastly, check if either node is immediately "boxed off" and, if so, add a penalty
+ # Lastly, check if either node is immediately "boxed off" and, if so,
+ # add a penalty
+
# normalizes the x and y offsets to either 1 or -1
xOffset = (pos1[0] - pos2[0]) / abs(pos1[0] - pos2[0])
yOffset = (pos1[1] - pos2[1]) / abs(pos1[1] - pos2[1])
# adds weight for walls around the positions being looked at
- if wallGrid[pos2[0] + xOffset][pos2[1]] and wallGrid[pos2[0]][pos2[1] + yOffset]:
+ if (
+ wallGrid[pos2[0] + xOffset][pos2[1]]
+ and wallGrid[pos2[0]][pos2[1] + yOffset]
+ ):
distance += 2
- if wallGrid[pos1[0] + (xOffset * -1) ][pos1[1]] and wallGrid[pos1[0]][pos1[1] + (yOffset * -1)]:
+ if (
+ wallGrid[pos1[0] + (xOffset * -1)][pos1[1]]
+ and wallGrid[pos1[0]][pos1[1] + (yOffset * -1)]
+ ):
distance += 2
return distance
@@ -591,30 +612,40 @@ def foodHeuristic(state, problem):
if foodLeft == 0:
return 0
- # get the distances between the current position and remaining food
+ # get the position and distance of the closest food to pacman
minFood = min(foodList, key=lambda food: getDistance(food, position))
minFoodDist = getDistance(minFood, position)
-
- # get distance to minFood and then distance between foods that are farthest from eachother
- # -925 nodes expanded (7652/8577)
- if problem.heuristicInfo.has_key('foodList') and problem.heuristicInfo['foodList'] == foodList:
- mostDispersed = problem.heuristicInfo['mostDispersed']
+ # get distance to minFood and then distance between foods that are farthest
+ # from each other. -925 nodes expanded (7652/8577)
+
+ # Check if the foodList has changed
+ if (
+ problem.heuristicInfo.has_key("foodList")
+ and problem.heuristicInfo["foodList"] == foodList
+ ):
+ # If foodList has not changed, there is no need to calculate a new
+ # mosDispersed, just return the last one calculated
+ mostDispersed = problem.heuristicInfo["mostDispersed"]
else:
+ # If foodList has changed, initialize mostDispersed and recalculate it.
mostDispersed = (minFood, minFood, 0)
+ # Loop though each food, find the furthest food from it foodList. O(n^2)?
for food in foodList:
- temp = max(map(lambda other: (food, other, getDistance(other, food)), foodList), key=lambda node: node[2])
+ temp = max(
+ map(lambda other: (food, other, getDistance(other, food)), foodList),
+ key=lambda node: node[2],
+ )
+
+ # Store the max distances pair of foods in a tuple.
if temp[2] > mostDispersed[2]:
mostDispersed = temp
-
- problem.heuristicInfo['foodList'] = foodList
- problem.heuristicInfo['mostDispersed'] = mostDispersed
-
- # if minFoodPos != mostDispersed[0] and minFoodPos != mostDispersed[1]:
- # distance from the closest food to the closest of the two points from the mostDispersed
- # minToMostDispersed = mostDispersed[2] + min(getDistance(mostDispersed[0], minFoodPos), getDistance(mostDispersed[1], minFoodPos))
+ # Store the state of the foodList and calculated mostDispersed, for
+ # possible reuse if the foodList doesn't change.
+ problem.heuristicInfo["foodList"] = foodList
+ problem.heuristicInfo["mostDispersed"] = mostDispersed
# sets the bounds of our heuristic to keep it consistent
bounds = (mostDispersed[2], foodLeft - 1)