Module pacai.bin.pacman

This file holds the logic for a classic pacman game along with the main code to run a game.

To play your first game, type 'python -m pacai.bin.pacman' from the command line. Use WASD (or the arrow keys) to move.

Have fun!

Functions

def main(argv)

Entry point for a pacman game. The args are a blind pass of sys.argv with the executable stripped.

def parseAgentArgs(str)
def readCommand(argv)

Processes the command used to run pacman from the command line.

def replayGame(layout, actions, display)
def runGames(layout, pacman, ghosts, display, numGames, record=None, numTraining=0, catchExceptions=False, timeout=30, **kwargs)

Classes

class ClassicGameRules (timeout=30)

These game rules manage the control flow of a game, deciding when and how the game starts and ends.

Expand source code
class ClassicGameRules(object):
    """
    These game rules manage the control flow of a game, deciding when
    and how the game starts and ends.
    """

    def __init__(self, timeout = 30):
        self.timeout = timeout

    def newGame(self, layout, pacmanAgent, ghostAgents, display, catchExceptions = False):
        agents = [pacmanAgent] + ghostAgents[:layout.getNumGhosts()]
        initState = PacmanGameState(layout)
        game = Game(agents, display, self, catchExceptions = catchExceptions)
        game.state = initState

        self._initialFoodCount = initState.getNumFood()

        return game

    def process(self, state, game):
        """
        Checks to see whether it is time to end the game.
        """

        if (state.isWin()):
            self.win(state, game)
        elif (state.isLose()):
            self.lose(state, game)

    def win(self, state, game):
        logging.info('Pacman emerges victorious! Score: %d' % state.getScore())
        game.gameOver = True

    def lose(self, state, game):
        logging.info('Pacman died! Score: %d' % state.getScore())
        game.gameOver = True

    def agentCrash(self, game, agentIndex):
        if (agentIndex == PACMAN_AGENT_INDEX):
            logging.error('Pacman crashed')
        else:
            logging.error('A ghost crashed')

    def getMaxTotalTime(self, agentIndex):
        return self.timeout

    def getMaxStartupTime(self, agentIndex):
        return self.timeout

    def getMoveWarningTime(self, agentIndex):
        return self.timeout

    def getMoveTimeout(self, agentIndex):
        return self.timeout

    def getMaxTimeWarnings(self, agentIndex):
        return 0

Methods

def agentCrash(self, game, agentIndex)
def getMaxStartupTime(self, agentIndex)
def getMaxTimeWarnings(self, agentIndex)
def getMaxTotalTime(self, agentIndex)
def getMoveTimeout(self, agentIndex)
def getMoveWarningTime(self, agentIndex)
def lose(self, state, game)
def newGame(self, layout, pacmanAgent, ghostAgents, display, catchExceptions=False)
def process(self, state, game)

Checks to see whether it is time to end the game.

def win(self, state, game)
class GhostRules

These functions dictate how ghosts interact with their environment.

Expand source code
class GhostRules:
    """
    These functions dictate how ghosts interact with their environment.
    """

    GHOST_SPEED = 1.0

    @staticmethod
    def getLegalActions(state, ghostIndex):
        """
        Ghosts cannot stop, and cannot turn around unless they
        reach a dead end, but can turn 90 degrees at intersections.
        """

        agentState = state.getGhostState(ghostIndex)
        possibleActions = Actions.getPossibleActions(agentState.getPosition(),
                agentState.getDirection(), state.getWalls())
        reverse = Actions.reverseDirection(agentState.getDirection())

        if (Directions.STOP in possibleActions):
            possibleActions.remove(Directions.STOP)

        if (reverse in possibleActions and len(possibleActions) > 1):
            possibleActions.remove(reverse)

        return possibleActions

    @staticmethod
    def applyAction(state, action, ghostIndex):
        legal = GhostRules.getLegalActions(state, ghostIndex)
        if (action not in legal):
            raise ValueError('Illegal ghost action: ' + str(action))

        ghostState = state.getGhostState(ghostIndex)
        speed = GhostRules.GHOST_SPEED
        if (ghostState.isScared()):
            speed /= 2.0

        vector = Actions.directionToVector(action, speed)
        ghostState.updatePosition(vector)

    @staticmethod
    def decrementTimer(agentState):
        if (not agentState.isScared()):
            return

        agentState.decrementScaredTimer()
        if (not agentState.isScared()):
            # If the ghost is done being scared, snap it to the closest point.
            agentState.snapToNearestPoint()

    @staticmethod
    def checkDeath(state, agentIndex):
        pacmanPosition = state.getPacmanPosition()

        # Did pacman just move?
        if (agentIndex == PACMAN_AGENT_INDEX):
            # See if a ghost can kill pacman.
            for index in state.getGhostIndexes():
                ghostState = state.getGhostState(index)
                ghostPosition = ghostState.getPosition()

                if (GhostRules.canKill(pacmanPosition, ghostPosition)):
                    GhostRules.collide(state, ghostState, index)

            return
        else:
            # A ghost just moved.
            ghostState = state.getGhostState(agentIndex)
            ghostPosition = ghostState.getPosition()
            if (GhostRules.canKill(pacmanPosition, ghostPosition)):
                GhostRules.collide(state, ghostState, agentIndex)

    @staticmethod
    def collide(state, ghostState, agentIndex):
        if (ghostState.isScared()):
            # Pacman ate a ghost.
            state.addScore(GHOST_POINTS)
            ghostState.respawn()
        elif (not state.isOver()):
            # A ghost ate pacman.
            state.addScore(LOSE_POINTS)
            state.endGame(False)

    @staticmethod
    def canKill(pacmanPosition, ghostPosition):
        return manhattan(ghostPosition, pacmanPosition) <= COLLISION_TOLERANCE

Class variables

var GHOST_SPEED

Static methods

def applyAction(state, action, ghostIndex)
def canKill(pacmanPosition, ghostPosition)
def checkDeath(state, agentIndex)
def collide(state, ghostState, agentIndex)
def decrementTimer(agentState)
def getLegalActions(state, ghostIndex)

Ghosts cannot stop, and cannot turn around unless they reach a dead end, but can turn 90 degrees at intersections.

class PacmanGameState (layout)

A game state specific to pacman. Note that in classic Pacman, Pacman is always agent PACMAN_AGENT_INDEX.

Expand source code
class PacmanGameState(AbstractGameState):
    """
    A game state specific to pacman.
    Note that in classic Pacman, Pacman is always agent PACMAN_AGENT_INDEX.
    """

    def __init__(self, layout):
        super().__init__(layout)

    # Override
    def generateSuccessor(self, agentIndex, action):
        """
        Returns the successor state after the specified agent takes the action.
        """

        # Check that successors exist.
        if (self.isOver()):
            raise RuntimeError("Can't generate successors of a terminal state.")

        successor = self._initSuccessor()
        successor._applySuccessorAction(agentIndex, action)

        return successor

    # Override
    def getLegalActions(self, agentIndex = PACMAN_AGENT_INDEX):
        if (self.isOver()):
            return []

        # Pacman's turn.
        if (agentIndex == PACMAN_AGENT_INDEX):
            return PacmanRules.getLegalActions(self)

        return GhostRules.getLegalActions(self, agentIndex)

    def generatePacmanSuccessor(self, action):
        return self.generateSuccessor(PACMAN_AGENT_INDEX, action)

    def getGhostIndexes(self):
        return range(1, self.getNumAgents())

    def getGhostPosition(self, agentIndex):
        if (agentIndex <= PACMAN_AGENT_INDEX or agentIndex >= self.getNumAgents()):
            raise ValueError("Invalid index passed to getGhostPosition(): %d." % (agentIndex))

        return self._agentStates[agentIndex].getPosition()

    def getGhostPositions(self):
        return [ghost.getPosition() for ghost in self.getGhostStates()]

    def getGhostState(self, agentIndex):
        if (agentIndex <= PACMAN_AGENT_INDEX or agentIndex >= self.getNumAgents()):
            raise ValueError("Invalid index passed to getGhostState(): %d." % (agentIndex))

        return self._agentStates[agentIndex]

    def getGhostStates(self):
        return self._agentStates[1:]

    def getLegalPacmanActions(self):
        return self.getLegalActions(PACMAN_AGENT_INDEX)

    def getNumGhosts(self):
        return self.getNumAgents() - 1

    def getPacmanPosition(self):
        return self._agentStates[PACMAN_AGENT_INDEX].getPosition()

    def getPacmanState(self):
        """
        Returns an AgentState object for pacman.

        state.getPosition() gives the current position.
        state.getDirection() gives the travel vector.
        """

        return self._agentStates[PACMAN_AGENT_INDEX]

    def _applySuccessorAction(self, agentIndex, action):
        """
        Apply the action to the context state (self).
        """

        # Let the agent's logic deal with its action's effects on the board.
        if (agentIndex == PACMAN_AGENT_INDEX):
            PacmanRules.applyAction(self, action)
        else:
            GhostRules.applyAction(self, action, agentIndex)

        # Time passes.
        if (agentIndex == PACMAN_AGENT_INDEX):
            # Penalty for waiting around.
            self.addScore(-TIME_PENALTY)
        else:
            GhostRules.decrementTimer(self.getAgentState(agentIndex))

        # Resolve multi-agent effects.
        GhostRules.checkDeath(self, agentIndex)

        # Book keeping.
        self._lastAgentMoved = agentIndex

        self._hash = None

Ancestors

Methods

def eatCapsule(self, x, y)

Inherited from: AbstractGameState.eatCapsule

Mark the capsule at the given location as eaten.

def eatFood(self, x, y)

Inherited from: AbstractGameState.eatFood

Mark the food at the given location as eaten.

def generatePacmanSuccessor(self, action)
def generateSuccessor(self, agentIndex, action)

Returns the successor state after the specified agent takes the action.

def getAgentPosition(self, index)

Inherited from: AbstractGameState.getAgentPosition

Returns a location tuple of the agent with the given index. It is possible for this method to return None if the agent's position is unknown (like if …

def getCapsules(self)

Inherited from: AbstractGameState.getCapsules

Returns a list of positions (x, y) of the remaining capsules.

def getFood(self)

Inherited from: AbstractGameState.getFood

Returns a Grid of boolean food indicator variables …

def getGhostIndexes(self)
def getGhostPosition(self, agentIndex)
def getGhostPositions(self)
def getGhostState(self, agentIndex)
def getGhostStates(self)
def getInitialLayout(self)

Inherited from: AbstractGameState.getInitialLayout

Get the initial layout this state starte with. User's should typically call one of the more detailed methods directly, e.g. getWalls().

def getLegalActions(self, agentIndex=0)

Inherited from: AbstractGameState.getLegalActions

Gets the legal actions for the agent specified.

def getLegalPacmanActions(self)
def getNumCapsules(self)

Inherited from: AbstractGameState.getNumCapsules

Get the amount of capsules left on the board.

def getNumFood(self)

Inherited from: AbstractGameState.getNumFood

Get the amount of food left on the board.

def getNumGhosts(self)
def getPacmanPosition(self)
def getPacmanState(self)

Returns an AgentState object for pacman.

state.getPosition() gives the current position. state.getDirection() gives the travel vector.

def getWalls(self)

Inherited from: AbstractGameState.getWalls

Returns a Grid of boolean wall indicator variables …

def hasCapsule(self, x, y)

Inherited from: AbstractGameState.hasCapsule

Returns true if the location (x, y) has a capsule.

def hasFood(self, x, y)

Inherited from: AbstractGameState.hasFood

Returns true if the location (x, y) has food.

def hasWall(self, x, y)

Inherited from: AbstractGameState.hasWall

Returns true if (x, y) has a wall, false otherwise.

class PacmanRules

These functions govern how pacman interacts with his environment under the classic game rules.

Expand source code
class PacmanRules:
    """
    These functions govern how pacman interacts with his environment under
    the classic game rules.
    """

    PACMAN_SPEED = 1

    @staticmethod
    def getLegalActions(state):
        """
        Returns a list of possible actions.
        """

        agentState = state.getPacmanState()
        return Actions.getPossibleActions(agentState.getPosition(), agentState.getDirection(),
                state.getWalls())

    @staticmethod
    def applyAction(state, action):
        """
        Edits the state to reflect the results of the action.
        """

        legal = PacmanRules.getLegalActions(state)
        if (action not in legal):
            raise ValueError('Illegal pacman action: ' + str(action))

        pacmanState = state.getPacmanState()

        # Update position.
        vector = Actions.directionToVector(action, PacmanRules.PACMAN_SPEED)
        pacmanState.updatePosition(vector)

        # Eat.
        nextPosition = pacmanState.getPosition()
        nearest = nearestPoint(nextPosition)
        if (manhattan(nearest, nextPosition) <= 0.5):
            # Remove food
            PacmanRules.consume(nearest, state)

    @staticmethod
    def consume(position, state):
        x, y = position

        if (state.hasFood(x, y)):
            # Eat food.
            state.eatFood(x, y)
            state.addScore(FOOD_POINTS)

            if (state.getNumFood() == 0 and not state.isLose()):
                state.addScore(BOARD_CLEAR_POINTS)
                state.endGame(True)
        elif (state.hasCapsule(x, y)):
            # Eat a capsule.
            state.eatCapsule(x, y)

            # Reset all ghosts' scared timers.
            for ghostState in state.getGhostStates():
                ghostState.setScaredTimer(SCARED_TIME)

Class variables

var PACMAN_SPEED

Static methods

def applyAction(state, action)

Edits the state to reflect the results of the action.

def consume(position, state)
def getLegalActions(state)

Returns a list of possible actions.