Introduction In this assignment, you will design agents for an almost classic version of Pac-Man, which includes a ghost. Along the way, you will implement both minimax and alpha-beta search and try your hand at evaluation function design.
The code base has not changed much from the previous assignment, but please start with a fresh installation, rather than intermingling files from assignment 1. You can, however, use your search.py and searchAgents.py in any way you want.
The code for this assignment contains the following files (including this description) and is available as a zip archive.
Key files to read multiAgents.py Where all of your multi-agent search agents will reside. pacman.py The main file that runs Pac-Man games. This file also describes a Pac-Man GameState type, which you will use extensively in this assignment game.py The logic behind how the Pac-Man world works. This file describes several supporting types like AgentState, Agent, Direction, and Grid. util.py Useful data structures for implementing search algorithms. Files you can ignore graphicsDisplay.py Graphics for Pac-Man graphicsUtils.py Support for Pac-Man graphics textDisplay.py ASCII graphics for Pac-Man ghostAgents.py Agents to control ghosts keyboardAgents.py Keyboard interfaces to control Pac-Man layout.py Code for reading layout files and storing their contents
Evaluation: Your code will be autograded for technical correctness. Please do not change the names of any provided functions or classes within the code, or you will wreak havoc on the autograder. However, the correctness of your implementation -- not the autograder's judgements -- will be the final judge of your score. If necessary, we will review and grade assignments individually to ensure that you receive due credit for your work.
Multi-Agent Pac-Man Run the provided ReflexAgent in multiAgents.py:
python pacman.py -p ReflexAgent -k 1 Note that it often loses and when it wins it doesn't always get a good score (greater than 0) even on simple layouts:
python pacman.py -p ReflexAgent -l testClassic -k 1 Inspect its code (in multiAgents.py) and make sure you understand what it's doing.
Question 1 (20%) Improve the ReflexAgent in multiAgents.py to play respectably. The provided reflex agent code provides some helpful examples of methods that query the GameState for information. A capable reflex agent will have to consider both food locations and ghost locations to perform well. Your agent should easily and reliably clear the testClassic layout:
python pacman.py -p ReflexAgent -l testClassic -k 1 Try out your reflex agent on the default mediumClassic layout with one ghost (and animation off to speed up the display):
python pacman.py --frameTime 0 -p ReflexAgent -k 1 How does your agent fare?
Note: As features, try the reciprocal of important values (such as distance to food) rather than just the values themselves.
Note: The evaluation function you're writing is evaluating state-action pairs; in later parts of the assignment, you'll be evaluating states.
Options: Default ghosts are random; you can also play for fun with a slightly smarter directional ghost using -g DirectionalGhost. If the randomness is preventing you from telling whether your agent is improving, you can use -f to run with a fixed random seed (same random choices every game). You can also play multiple games in a row with -n. Turn off graphics with -q to run lots of games quickly.
The autograder will check that your agent can rapidly clear the openClassic layout ten times without dying more than twice or thrashing around infinitely (i.e. repeatedly moving back and forth between two positions, making no progress).
python pacman.py -p ReflexAgent -l openClassic -k 1 -n 10 -q Don't spend too much time on this question, though, as the meat of the assignment lies ahead.
Question 2 (40%) Now you will write an adversarial search agent in the provided MinimaxAgent class stub in multiAgents.py. Your minimax agent should work with one ghost.
Your code should also expand the game tree to an arbitrary depth. Score the leaves of your minimax tree with the supplied self.evaluationFunction, which defaults to scoreEvaluationFunction. MinimaxAgent extends MultiAgentAgent, which gives access to self.depth and self.evaluationFunction. Make sure your minimax code makes reference to these two variables where appropriate as these variables are populated in response to command line options.
Important: A single search ply is considered to be one Pac-Man move and the ghost's response, so depth 2 search will involve Pac-Man and the ghost moving two times.
Hints and Observations
· The evaluation function in this part is already written (self.evaluationFunction). You shouldn't change this function, but recognize that now we're evaluating *states* rather than actions, as we were for the reflex agent. Look-ahead agents evaluate future states whereas reflex agents evaluate actions from the current state.
python pacman.py -p MinimaxAgent -l smallClassic -k 1 -a depth=4 · To increase the search depth achievable by your agent, remove the Directions.STOP action from Pac-Man's list of possible actions. Depth 2, 3, and 4 should be pretty quick, but depth 5 and higher will be slow. Don't worry, the next question will speed up the search somewhat.
· Pac-Man is always agent 0, and the agents move in order of increasing agent index.
· All states in minimax should be GameStates, either passed in to getAction or generated via GameState.generateSuccessor.
Question 3 (40%) Make a new agent that uses alpha-beta pruning to more efficiently explore the minimax tree, in AlphaBetaAgent.
You should see a speed-up (perhaps depth 5 alpha-beta will run as fast as depth 4 minimax). Ideally, depth 5 on smallClassic should run in just a few seconds per move or faster.
python pacman.py -p AlphaBetaAgent -k 1 -a depth=6 -l smallClassic The AlphaBetaAgent minimax values should be identical to the MinimaxAgent minimax values, although the actions it selects can vary because of different tie-breaking behavior.
Hints and Observations
· As for your reflex agent evaluation function, you may want to use the reciprocal of important values (such as distance to food) rather than the values themselves.
· One way you might want to write your evaluation function is to use a linear combination of features. That is, compute values for features about the state that you think are important, and then combine those features by multiplying them by different values and adding the results together. You might decide what to multiply each feature by based on how important you think it is.