Skip to content

Instantly share code, notes, and snippets.

@dcalacci
Last active December 6, 2023 16:54
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dcalacci/6953749 to your computer and use it in GitHub Desktop.
Save dcalacci/6953749 to your computer and use it in GitHub Desktop.
the manual evaluation function I used for hw2 of berkeley's pac-man projects
def betterEvaluationFunction(currentGameState):
"""
Your extreme ghost-hunting, pellet-nabbing, food-gobbling, unstoppable
evaluation function (question 5).
I used the following features in this model:
- distance to the closest active ghost (active ghosts are non-scared ghosts)
- current score in the game
- distance to the closest scared ghost
- number of capsules left
- number of foods left
- distance to the closest food
My evaluation function computes a linear combination of
these features (or related features, since in some cases, I take
the inverse of a feature)
I kept the current score the same, because I saw no reason to modify it.
I multiply the distance to the closest food by -1.5. This means that the
larger the distance pac-man has to the closest food, the more negative the
score is.
I take the inverse of the distance to the closest active ghost, and then
multiply it by -2. This means that the larger the distance to the closest
active ghost, the les negative the score is, but the closer a ghost is,
the more negative the score becomes.
I multiply distance to the closest scared ghost by -2, to motivate pac-man to
move towards scared ghosts. This coefficient is larger than the coefficient I
used for food, even though the distance to the closest scared ghost will
almost always be greater than the distance to the nearest food. I chose to
use a larger coefficient here because:
- pac-man gets a large number of points for eating a scared ghost
- if the distance to the closest scared ghost is greater than the distance
to the nearest food, it is usually because there are not many foods left
on the board. This means that it's likely more beneficial for pac-man to go
towards the scared ghost, because eating the scared ghost will likely net
pac-man more points than eating the remaining foods.
I multiply the number of capsules left by a very high negative number - -20 -
in order to motivate pac-man to eat capsules that he passes. I didn't want
pac-man to move toward capsules over food or over running away from ghosts,
but I DID want pac-man to eat them when he passed by them. When pac-man
passes by a capsule, the successor state where pac-man eats a capsule will
gain +20 points, which is (usually) significant enough that pac-man eats
the capsule.
I also multiply the number of foods left by -4, because pac-man should
minimize the number of foods that are left on the board.
some results:
dan at staircar in ~/classes/ai/multiagent on master
$ python pacman.py -l smallClassic -p ExpectimaxAgent -a evalFn=better -n 10 -q
Pacman emerges victorious! Score: 1366
Pacman died! Score: -198
Pacman emerges victorious! Score: 1367
Pacman emerges victorious! Score: 1737
Pacman emerges victorious! Score: 1364
Pacman emerges victorious! Score: 933
Pacman emerges victorious! Score: 1743
Pacman emerges victorious! Score: 1193
Pacman emerges victorious! Score: 1373
Pacman emerges victorious! Score: 1348
Average Score: 1222.6
Scores: 1366, -198, 1367, 1737, 1364, 933, 1743, 1193, 1373, 1348
Win Rate: 9/10 (0.90)
Record: Win, Loss, Win, Win, Win, Win, Win, Win, Win, Win
dan at staircar in ~/classes/ai/multiagent on master
$ python pacman.py -l smallClassic -p ExpectimaxAgent -a evalFn=better -n 10
Pacman emerges victorious! Score: 1139
Pacman emerges victorious! Score: 1362
Pacman emerges victorious! Score: 1770
Pacman emerges victorious! Score: 1361
Pacman emerges victorious! Score: 1234
Pacman emerges victorious! Score: 1521
Pacman emerges victorious! Score: 1755
Pacman emerges victorious! Score: 1759
Pacman emerges victorious! Score: 1759
Pacman died! Score: 101
Average Score: 1376.1
Scores: 1139, 1362, 1770, 1361, 1234, 1521, 1755, 1759, 1759, 101
Win Rate: 9/10 (0.90)
Record: Win, Win, Win, Win, Win, Win, Win, Win, Win, Loss
---
I also experimented with using the actual maze-distance instead of the
manhattan distance, but that turned out to be mostly useless.
"""
pos = currentGameState.getPacmanPosition()
currentScore = scoreEvaluationFunction(currentGameState)
if currentGameState.isLose():
return -float("inf")
elif currentGameState.isWin():
return float("inf")
# food distance
foodlist = currentGameState.getFood().asList()
manhattanDistanceToClosestFood = min(map(lambda x: util.manhattanDistance(pos, x), foodlist))
distanceToClosestFood = manhattanDistanceToClosestFood
# number of big dots
# if we only count the number fo them, he'll only care about
# them if he has the opportunity to eat one.
numberOfCapsulesLeft = len(currentGameState.getCapsules())
# number of foods left
numberOfFoodsLeft = len(foodlist)
# ghost distance
# active ghosts are ghosts that aren't scared.
scaredGhosts, activeGhosts = [], []
for ghost in currentGameState.getGhostStates():
if not ghost.scaredTimer:
activeGhosts.append(ghost)
else:
scaredGhosts.append(ghost)
def getManhattanDistances(ghosts):
return map(lambda g: util.manhattanDistance(pos, g.getPosition()), ghosts)
distanceToClosestActiveGhost = distanceToClosestScaredGhost = 0
if activeGhosts:
distanceToClosestActiveGhost = min(getManhattanDistances(activeGhosts))
else:
distanceToClosestActiveGhost = float("inf")
distanceToClosestActiveGhost = max(distanceToClosestActiveGhost, 5)
if scaredGhosts:
distanceToClosestScaredGhost = min(getManhattanDistances(scaredGhosts))
else:
distanceToClosestScaredGhost = 0 # I don't want it to count if there aren't any scared ghosts
outputTable = [["dist to closest food", -1.5*distanceToClosestFood],
["dist to closest active ghost", 2*(1./distanceToClosestActiveGhost)],
["dist to closest scared ghost", 2*distanceToClosestScaredGhost],
["number of capsules left", -3.5*numberOfCapsulesLeft],
["number of total foods left", 2*(1./numberOfFoodsLeft)]]
score = 1 * currentScore + \
-1.5 * distanceToClosestFood + \
-2 * (1./distanceToClosestActiveGhost) + \
-2 * distanceToClosestScaredGhost + \
-20 * numberOfCapsulesLeft + \
-4 * numberOfFoodsLeft
return score
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment