Contest: Pacman Capture the Flag

Tournament on Wednesday, 12/5 @ 6pm
Final version posted on 11/20
Qualifying instructions and final contest layout posted on 11/27
-->

Enough of defense,
Onto enemy terrain.
Capture all their food!

[5/5] Final tournament rules, brackets and maps announced

[4/13] New information about submitting to the nightly tournament has been added to the contest details section at the bottom. The nightly tournament is how you qualify for the finals.

Final Tournament

The final tournament will be held live in Soda 273 at 5pm on Wednesday May 6th. Bring your agents with you!

Each match-up will be decided in three games. The first game will be played on defaultCapture.lay. The other two games will be played on one of the 20 randomly generated maps now included in this distribution as layouts/contest*Capture.lay. One of these mazes can be chosen at random using mazeGenerator.py.

To watch games from the last nightly tournament, download the server logs and use the unpack.py tool. python unpack.py [server-log] [team-name] will generate replay files, which can be replayed with python capture.py --replay [replay-file]. The server log for May 5 is corrupted, unfortunately.

The winner's bracket:

Introduction

The course contest involves a multi-player capture-the-flag variant of Pacman, where agents control both Pacman and ghosts in coordinated team-based strategies. Your team will try to eat the food on the far side of the map, while defending the food on your home side. The contest code is available as a zip archive.

Key files to read:
capture.py The main file that runs games locally. This file also describes the new capture the flag GameState type and rules.
pacclient.py The main file that runs games over the network.
captureAgents.py Some example agents for this variant of Pacman.
Supporting files:
game.py The logic behind how the Pacman world works. This file describes several supporting types like AgentState, Agent, Direction, and Grid.
util.py Useful data structures for implementing search algorithms.
distanceCalculator.py Computes shortest paths between all maze positions.
graphicsDisplay.py Graphics for Pacman
graphicsUtils.py Support for Pacman graphics
textDisplay.py ASCII graphics for Pacman
keyboardAgents.py Keyboard interfaces to control Pacman
layout.py Code for reading layout files and storing their contents

Academic Dishonesty: While we won't grade contests, we still expect you not to falsely represent your work. Please don't let us down.

Rules of Pacman Capture the Flag

Layout: The Pacman map is now divided into two halves: blue (right) and red (left). Red agents (which all have even indices) must defend the red food while trying to eat the blue food. When on the red side, a red agent is a ghost. When crossing into enemy territory, the agent becomes a Pacman.

Scoring: When a Pacman eats a food dot, the food is permanently removed and one point is scored for that Pacman's team. Red team scores are positive, while Blue team scores are negative.

Eating Pacman: When a Pacman is eaten by an opposing ghost, the Pacman returns to its starting position (as a ghost). No points are awarded for eating an opponent. Ghosts can never be eaten.

Winning: A game ends when either one team eats all but two of the opponents' dots. Games are also limited to 3000 agent moves. If this move limit is reached, whichever team has eaten the most food wins.

Computation Time: In online play, each agent will have only 0.5 seconds to choose an action. If an action is not returned in this amount of time, the server will move the agent randomly.

Observations: Agents can only observe an opponent's configuration (position and direction) if they or their teammate is within 5 squares (Manhattan distance). In addition, an agent always gets a noisy distance reading for each agent on the board, which can be used to approximately locate unobserved opponents.

Getting Started

By default, you can run a four-player game where the keyboard controls the red ghost and all other agents play offense:
python capture.py
The arrow keys control your character, which will change from ghost to Pacman when crossing the center line.

A wealth of options are available to you:

python capture.py --help
For example, use the following command to make the Blue team play a mix of offense and defense.
python capture.py -b OffenseDefenseAgents 
There are six slots for agents, where agents 0, 2 and 4 are always on the red team and 1, 3 and 5 on the blue team. Agents are created by agent factories (one for Red, one for Blue). See the section on designing agents for a description of the agents invoked above. When judging the contest this semester, we will use only four agents (two from each side). When you're playing the local version (using capture.py), by default you can see where all the agents are. The agents, however, typically do not know where opponents are (unless they are close by, according to the rules above). When you play the online version (described below) you will not be able to see your opponents' agents.

Online Games

In order to facilitate testing of your agents against others' in the class, we have set up game servers that moderate games played over the network. We will use this network setup to administer the final tournament. Your agent factory is specified with -a.
python pacclient.py -a OffenseDefenseAgents
Look at the options with -h. If you want to identify yourself to the server for stats tracking, you should supply a name and password. If the name you supply is new, an account will be created for you. If it is a name that is already used, you must supply the correct password or the server will not accept your connection.
python pacclient.py -U blitz -P noprisoners -a AllOffenseAgents

Any agent that works in a local game should work equivalently in an online game. However, there is a real-time element to the game: you have only 0.5 seconds (plus a little leeway for network lag) to choose a move. The server will enforce this time limit, and will choose a move for you if you don't supply one in time.

Designing Agents

Unlike project 2, an agent now has the more complex job of trading off offense versus defense and effectively functioning as a ghost and a Pacman in a team setting. Furthermore, the limited information provided to your agent will likely necessitate some probabilistic tracking (like project 4). Finally, the added time limit of computation introduces new challenges.

Interface: The GameState in capture.py should look familiar, but contains new methods like getRedFood, which gets a grid of food on the red side (note that the grid is the size of the board, but is only true for cells on the red side with food). Also, note that you can list a team's indices with getRedTeamIndices, or test membership with isOnRedTeam.

Finally, you can access the list of noisy distance observations via getAgentDistances. These distances are within 6 of the truth, and the noise is chosen uniformly at random from the range [-6, 6] (e.g., if the true distance is 6, then each of {0, 1, ..., 12} is chosen with probability 1/13). You can get the likelihood of a noisy reading using getDistanceProb.

To get started designing your own agent, we recommend subclassing the CaptureAgent class. This provides access to several convenience methods. Some useful methods are:

  def getFood(self, gameState):
    """
    Returns the food you're meant to eat. This is in the form
    of a matrix where m[x][y]=true if there is food you can
    eat (based on your team) in that square.
    """

  def getFoodYouAreDefending(self, gameState):
    """
    Returns the food you're meant to protect (i.e., that your
    opponent is supposed to eat). This is in the form of a
    matrix where m[x][y]=true if there is food at (x,y) that
    your opponent can eat.
    """
    
  def getOpponents(self, gameState):
    """
    Returns agent indices of your opponents. This is the list
    of the numbers of the agents (e.g., red might be "1,3,5")
    """
    
  def getTeam(self, gameState):
    """
    Returns agent indices of your team. This is the list of
    the numbers of the agents (e.g., red might be "1,3,5")
    """
    
  def getScore(self, gameState):
    """
    Returns how much you are beating the other team by in the
    form of a number that is the difference between your score
    and the opponents score. This number is negative if you're
    losing.
    """
    
  def getMazeDistance(self, pos1, pos2):
    """
    Returns the distance between two points; this is either
    the Manhattan distance early in the game, or actual
    shortest path maze distances once the computation is
    complete.
    
    The distancer computes the shortest path between pairs of
    points in the background, and starts using them as soon as
    they are ready. These are not just pre-computed ahead of
    time because of the time limit - we don't want to lose our
    turn because we're computing distances we don't need yet!
    """

  def getPreviousObservation(self):
    """
    Returns the GameState object corresponding to the last
    state this agent saw (the observed state of the game last
    time this agent moved - this may not include all of your
    opponent's agent locations exactly).
    """

  def getCurrentObservation(self):
    """
    Returns the GameState object corresponding this agent's
    current observation (the observed state of the game - this
    may not include all of your opponent's agent locations
    exactly).
    """
  

Baseline Agents: To kickstart your agent design, we have provided you with two baseline agents. They are both quite bad. The OffensiveReflexAgent moves toward the closest food on the opposing side. The DefensiveReflexAgent wanders around on its own side and tries to chase down invaders it happens to see.

To facilitate agent development, we provide code in distanceCalculator.py to supply shortest path maze distances as soon as they can be computed, but to supply Manhattan distances until then. This approach demonstrates some of the techniques you might want to use when designing agents under time constraints (e.g., sharing information and computing in parallel). However, this is neither the only nor the best way to solve the maze distance problem.

Restrictions: You are free to design any agent you want, and you need not use any of the code we have provided. Because the tournament will be run using the online architecture, you can run your agent from your machine using any resources or code you want; you can even write code in different programming languages if you so desire. Change pacclient.py at your own risk, though, because you don't want to break the network functionality.

Loading agents: Agents are chosen by agent factories, also specified in captureAgents.py. You may also pass options to your agent factories (see --help), which can then be passed on to your agents.

Contest Details

The contest has three parts: a qualifying round, an exhibition match between UC Berkeley and U of Utah, and a final tournament.

Important dates (subject to change):

Tuesday 3/10Contest announced and posted
Tuesday 4/14Qualification opens
Tuesday 4/28Exhibition match: Berkeley vs. Utah
Thursday 4/30Tournament layout revealed
Sunday 5/3Qualification closes
Wednesday 5/6Berkeley tournament
Thursday 5/7Awards ceremony in class

Teams: You may work in teams of up to 5 people.

Prizes: The top three teams will receive awards in class on Thursday 5/7, including shiny medals and extra credit points.

Bonus prizes: If at least 30% of the class qualifies for the tournament, then all prizes will be doubled. Additionally, all qualifiers will get a 1% bonus on their final exam. Note that 2% overall (the top prize) is a lot: it is equivalent to 6.7% on the final.

Named Games

By default, when you connect to the server for a network game, you will be paired with the first unmatched opponent that connects. If you would like to play with a buddy, you can organize a game with a specific name on the server:
python pacclient.py -a KeyboardAgents -g MyCoolGame
Which will pair you only with the next player who requests "MyCoolGame"

This being an inherently social feature, the CSUA has set up an IRC channel for chatting about the project. It can be reached at:

Server: irc.csua.berkeley.edu
Channel: #cs188
Or can be accessed by web interface here-->

PyGame Graphics

We have included an improved graphics package with this release, based on the Python library Pygame. To use this extension, you must first install PyGame on your computer. Follow these installation instructions. It may take a bit of finagling to get it to run on a Mac; if you have troubles and would like to use Pygame, please talk to us during office hours.

Once you have installed PyGame, you can run either the networked or local game using the improved (speedier) graphics.

python capture.py -1 RandomAgent -G
The KeyboardAgent will not work with the PyGame graphics because it is tied to the Tk libraries used for the old graphics. <-->

Acknowledgements

We owe special thanks to Barak Michener and Ed Karuna for providing online networking infrastructure, improved graphics and debugging help.

Have fun! Please bring our attention to any problems you discover.