Module pacai.core.game

The core of a pacman-style game.

Expand source code
"""
The core of a pacman-style game.
"""

import logging
import time

class Game:
    """
    The Game manages the control flow, soliciting actions from agents.
    """

    def __init__(self, agents, display, rules, startingIndex = 0, catchExceptions = False):
        self.agentCrashed = False
        self.agents = agents
        self.display = display
        self.rules = rules
        self.startingIndex = startingIndex
        self.gameOver = False
        self.moveHistory = []
        self.totalAgentTimes = [0 for agent in agents]
        self.totalAgentTimeWarnings = [0 for agent in agents]
        self.agentTimeout = False

        self.enforceTimeouts = catchExceptions
        self.catchExceptions = catchExceptions

    def run(self):
        """
        Main control loop for game play.
        """

        self.numMoves = 0

        agentIndex = self.startingIndex
        numAgents = len(self.agents)

        self.display.initialize(self.state)

        if (not self._registerInitialState()):
            return False

        # Draw the initial frame.
        self.display.update(self.state)

        while (not self.gameOver):
            # Fetch the next agent
            agent = self.agents[agentIndex]

            action = None
            startTime = time.time()

            # Get an action from the agent.
            try:
                agent.observationFunction(self.state)
                action = agent.getAction(self.state)
            except Exception as ex:
                if (not self.catchExceptions):
                    raise ex

                self._agentCrash(agentIndex, ex)
                return False

            timeTaken = time.time() - startTime
            self.totalAgentTimes[agentIndex] += timeTaken

            if (self._checkForTimeouts(agentIndex, timeTaken)):
                return False

            # Execute the action.
            self.moveHistory.append((agentIndex, action))
            try:
                self.state = self.state.generateSuccessor(agentIndex, action)
            except Exception as ex:
                if (not self.catchExceptions):
                    raise ex

                self._agentCrash(agentIndex, ex)
                return False

            # Update the display.
            self.display.update(self.state)

            # Allow for game specific conditions (winning, losing, etc.).
            self.rules.process(self.state, self)

            # Track progress.
            if (agentIndex == numAgents + 1):
                self.numMoves += 1

            # Next agent.
            agentIndex = (agentIndex + 1) % numAgents

        if (not self._registerFinalState()):
            return False

        self.display.finish()

    def _agentCrash(self, agentIndex, exception = None):
        """
        Helper method for handling agent crashes.
        """

        logging.warning('Agent %d crashedtimed out on a single move!' % agentIndex,
                exc_info = exception)

        self.gameOver = True
        self.agentCrashed = True
        self.rules.agentCrash(self, agentIndex)

    def _checkForTimeouts(self, agentIndex, timeTaken):
        """
        Check if an agent timed out.
        Return: True if an agent times out.
        """

        if (not self.enforceTimeouts):
            return False

        # Check for a single move timeout (results in an instant loss).
        moveTimeout = self.rules.getMoveTimeout(agentIndex)
        if (timeTaken > moveTimeout):
            logging.warning('Agent %d timed out on a single move!' % agentIndex)
            self.agentTimeout = True
            self._agentCrash(agentIndex)
            return True

        # Check for a timeout warning (you get a few of theses).
        moveWarningTime = self.rules.getMoveWarningTime(agentIndex)
        if (timeTaken > moveWarningTime):
            self.totalAgentTimeWarnings[agentIndex] += 1
            logging.warning('Agent %d took too long to move! This is warning %d' %
                    (agentIndex, self.totalAgentTimeWarnings[agentIndex]))

            maxTimeouts = self.rules.getMaxTimeWarnings(agentIndex)
            if (self.totalAgentTimeWarnings[agentIndex] > maxTimeouts):
                logging.warning('Agent %d exceeded the maximum number of warnings: %d' %
                        (agentIndex, self.totalAgentTimeWarnings[agentIndex]))
                self.agentTimeout = True
                self._agentCrash(agentIndex)
                return True

        # Check if the agent has used too much time overall.
        maxTotalTime = self.rules.getMaxTotalTime(agentIndex)
        if (self.totalAgentTimes[agentIndex] > maxTotalTime):
            logging.warning('Agent %d ran out of time! (time: %1.2f)' %
                    (agentIndex, self.totalAgentTimes[agentIndex]))
            self.agentTimeout = True
            self._agentCrash(agentIndex)
            return True

        return False

    def _registerInitialState(self):
        """
        Inform agents of the game start.
        """

        for agentIndex in range(len(self.agents)):
            agent = self.agents[agentIndex]

            if (not agent):
                # this is a null agent, meaning it failed to load the other team wins.
                self._agentCrash(agentIndex)
                return False

            maxStartupTime = int(self.rules.getMaxStartupTime(agentIndex))
            startTime = time.time()

            try:
                agent.registerInitialState(self.state)
            except Exception as ex:
                if (not self.catchExceptions):
                    raise ex

                self._agentCrash(agentIndex, ex)
                return False

            timeTaken = time.time() - startTime
            self.totalAgentTimes[agentIndex] += timeTaken

            if (self.enforceTimeouts and timeTaken > maxStartupTime):
                logging.warning('Agent %d ran out of time on startup!' % agentIndex)
                self.agentTimeout = True
                self._agentCrash(agentIndex)
                return False

        return True

    def _registerFinalState(self):
        # Inform a learning agent of the game's result.
        for agent in self.agents:
            try:
                agent.final(self.state)
            except Exception as ex:
                if (not self.catchExceptions):
                    raise ex

                self._agentCrash(agent.index, ex)
                return False

        return True

Classes

class Game (agents, display, rules, startingIndex=0, catchExceptions=False)

The Game manages the control flow, soliciting actions from agents.

Expand source code
class Game:
    """
    The Game manages the control flow, soliciting actions from agents.
    """

    def __init__(self, agents, display, rules, startingIndex = 0, catchExceptions = False):
        self.agentCrashed = False
        self.agents = agents
        self.display = display
        self.rules = rules
        self.startingIndex = startingIndex
        self.gameOver = False
        self.moveHistory = []
        self.totalAgentTimes = [0 for agent in agents]
        self.totalAgentTimeWarnings = [0 for agent in agents]
        self.agentTimeout = False

        self.enforceTimeouts = catchExceptions
        self.catchExceptions = catchExceptions

    def run(self):
        """
        Main control loop for game play.
        """

        self.numMoves = 0

        agentIndex = self.startingIndex
        numAgents = len(self.agents)

        self.display.initialize(self.state)

        if (not self._registerInitialState()):
            return False

        # Draw the initial frame.
        self.display.update(self.state)

        while (not self.gameOver):
            # Fetch the next agent
            agent = self.agents[agentIndex]

            action = None
            startTime = time.time()

            # Get an action from the agent.
            try:
                agent.observationFunction(self.state)
                action = agent.getAction(self.state)
            except Exception as ex:
                if (not self.catchExceptions):
                    raise ex

                self._agentCrash(agentIndex, ex)
                return False

            timeTaken = time.time() - startTime
            self.totalAgentTimes[agentIndex] += timeTaken

            if (self._checkForTimeouts(agentIndex, timeTaken)):
                return False

            # Execute the action.
            self.moveHistory.append((agentIndex, action))
            try:
                self.state = self.state.generateSuccessor(agentIndex, action)
            except Exception as ex:
                if (not self.catchExceptions):
                    raise ex

                self._agentCrash(agentIndex, ex)
                return False

            # Update the display.
            self.display.update(self.state)

            # Allow for game specific conditions (winning, losing, etc.).
            self.rules.process(self.state, self)

            # Track progress.
            if (agentIndex == numAgents + 1):
                self.numMoves += 1

            # Next agent.
            agentIndex = (agentIndex + 1) % numAgents

        if (not self._registerFinalState()):
            return False

        self.display.finish()

    def _agentCrash(self, agentIndex, exception = None):
        """
        Helper method for handling agent crashes.
        """

        logging.warning('Agent %d crashedtimed out on a single move!' % agentIndex,
                exc_info = exception)

        self.gameOver = True
        self.agentCrashed = True
        self.rules.agentCrash(self, agentIndex)

    def _checkForTimeouts(self, agentIndex, timeTaken):
        """
        Check if an agent timed out.
        Return: True if an agent times out.
        """

        if (not self.enforceTimeouts):
            return False

        # Check for a single move timeout (results in an instant loss).
        moveTimeout = self.rules.getMoveTimeout(agentIndex)
        if (timeTaken > moveTimeout):
            logging.warning('Agent %d timed out on a single move!' % agentIndex)
            self.agentTimeout = True
            self._agentCrash(agentIndex)
            return True

        # Check for a timeout warning (you get a few of theses).
        moveWarningTime = self.rules.getMoveWarningTime(agentIndex)
        if (timeTaken > moveWarningTime):
            self.totalAgentTimeWarnings[agentIndex] += 1
            logging.warning('Agent %d took too long to move! This is warning %d' %
                    (agentIndex, self.totalAgentTimeWarnings[agentIndex]))

            maxTimeouts = self.rules.getMaxTimeWarnings(agentIndex)
            if (self.totalAgentTimeWarnings[agentIndex] > maxTimeouts):
                logging.warning('Agent %d exceeded the maximum number of warnings: %d' %
                        (agentIndex, self.totalAgentTimeWarnings[agentIndex]))
                self.agentTimeout = True
                self._agentCrash(agentIndex)
                return True

        # Check if the agent has used too much time overall.
        maxTotalTime = self.rules.getMaxTotalTime(agentIndex)
        if (self.totalAgentTimes[agentIndex] > maxTotalTime):
            logging.warning('Agent %d ran out of time! (time: %1.2f)' %
                    (agentIndex, self.totalAgentTimes[agentIndex]))
            self.agentTimeout = True
            self._agentCrash(agentIndex)
            return True

        return False

    def _registerInitialState(self):
        """
        Inform agents of the game start.
        """

        for agentIndex in range(len(self.agents)):
            agent = self.agents[agentIndex]

            if (not agent):
                # this is a null agent, meaning it failed to load the other team wins.
                self._agentCrash(agentIndex)
                return False

            maxStartupTime = int(self.rules.getMaxStartupTime(agentIndex))
            startTime = time.time()

            try:
                agent.registerInitialState(self.state)
            except Exception as ex:
                if (not self.catchExceptions):
                    raise ex

                self._agentCrash(agentIndex, ex)
                return False

            timeTaken = time.time() - startTime
            self.totalAgentTimes[agentIndex] += timeTaken

            if (self.enforceTimeouts and timeTaken > maxStartupTime):
                logging.warning('Agent %d ran out of time on startup!' % agentIndex)
                self.agentTimeout = True
                self._agentCrash(agentIndex)
                return False

        return True

    def _registerFinalState(self):
        # Inform a learning agent of the game's result.
        for agent in self.agents:
            try:
                agent.final(self.state)
            except Exception as ex:
                if (not self.catchExceptions):
                    raise ex

                self._agentCrash(agent.index, ex)
                return False

        return True

Methods

def run(self)

Main control loop for game play.

Expand source code
def run(self):
    """
    Main control loop for game play.
    """

    self.numMoves = 0

    agentIndex = self.startingIndex
    numAgents = len(self.agents)

    self.display.initialize(self.state)

    if (not self._registerInitialState()):
        return False

    # Draw the initial frame.
    self.display.update(self.state)

    while (not self.gameOver):
        # Fetch the next agent
        agent = self.agents[agentIndex]

        action = None
        startTime = time.time()

        # Get an action from the agent.
        try:
            agent.observationFunction(self.state)
            action = agent.getAction(self.state)
        except Exception as ex:
            if (not self.catchExceptions):
                raise ex

            self._agentCrash(agentIndex, ex)
            return False

        timeTaken = time.time() - startTime
        self.totalAgentTimes[agentIndex] += timeTaken

        if (self._checkForTimeouts(agentIndex, timeTaken)):
            return False

        # Execute the action.
        self.moveHistory.append((agentIndex, action))
        try:
            self.state = self.state.generateSuccessor(agentIndex, action)
        except Exception as ex:
            if (not self.catchExceptions):
                raise ex

            self._agentCrash(agentIndex, ex)
            return False

        # Update the display.
        self.display.update(self.state)

        # Allow for game specific conditions (winning, losing, etc.).
        self.rules.process(self.state, self)

        # Track progress.
        if (agentIndex == numAgents + 1):
            self.numMoves += 1

        # Next agent.
        agentIndex = (agentIndex + 1) % numAgents

    if (not self._registerFinalState()):
        return False

    self.display.finish()