def __init__( self, prevState = None ): ## This initializes the GameState object. This is important as it also specifies the self.data object which is derived from the GameStateData class. """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData()
def __init__( self, prevState = None ): ###PLEASE NOTE THIS THAT THE __init__ method is here and this is where GameState() starts """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData()
def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData()
def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: self.data = GameStateData(prevState.data) self.livingGhosts = prevState.livingGhosts[:] else: # Initial state self.data = GameStateData() self.data.ghostDistances = []
def __init__( self, prevState = None ): ###PLEASE NOTE THIS THAT THE __init__ method is here and this is where GameState() starts """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) ##This statement imports the GameStateData object from the GameStateData class in game.py. This object contains a data packet documenting the state of the game. else: self.data = GameStateData() """
def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: self.data = GameStateData(prevState.data) self.livingGhosts = prevState.livingGhosts[:] self.numMoves = prevState.numMoves; self.maxMoves = prevState.maxMoves; else: # Initial state self.data = GameStateData() self.numMoves = 0; self.maxMoves = -1;
def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) self.blueTeam = prevState.blueTeam self.redTeam = prevState.redTeam self.teams = prevState.teams self.agentDistances = prevState.agentDistances else: self.data = GameStateData() self.agentDistances = []
def initPlot(self, xmin, ymin, width, height): if graphicsUtils._canvas is not None: graphicsUtils.clear_screen() # Initialize GameStateData with blank board with axes self.width = width self.height = height self.xShift = -(xmin-1) self.yShift = -(ymin-1) self.line = None self.zoom = min(30.0/self.width, 20.0/self.height) self.gridSize = graphicsDisplay.DEFAULT_GRID_SIZE * self.zoom # fullRow = ['%']*self.width # row = ((self.width-1)/2)*[' '] + ['%'] + ((self.width-1)/2)*[' '] # boardText = ((self.height-1)/2)*[row] + [fullRow] + ((self.height-1)/2)*[row] numSpaces = self.width-1 numSpacesLeft = self.xShift numSpacesRight = numSpaces-numSpacesLeft numRows = self.height numRowsBelow = self.yShift numRowsAbove = numRows-1-numRowsBelow fullRow = ['%']*self.width if numSpacesLeft < 0: row = [' ']*self.width else: row = numSpacesLeft*[' '] + ['%'] + numSpacesRight*[' '] boardText = numRowsAbove*[row] + [fullRow] + numRowsBelow*[row] layout = Layout(boardText) self.blankGameState = GameStateData() self.blankGameState.initialize(layout, 0) self.initialize(self.blankGameState) title = 'Pacman Plot' graphicsUtils.changeText(self.infoPane.scoreText, title) graphicsUtils.refresh()
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### def updateState(self, actions): """ Returns the successor state after the actions of all active agents. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('it is terminal state now.') self.data.clear() for agentIndex in range(len(actions)): if self.data._eaten[agentIndex] > 0: BombermanRules.applyAction(self, actions[agentIndex], agentIndex) self.minusOneFrame() for counter, position, power, index in self.data.bombs: if counter == self.getFramesUntilEnd(): self.bombExplode(self.data.bombs, position, power) if index >= 0: self.getAgentState(index).recoverABomb() self.data.bombs = [ b for b in self.data.bombs if (b[0] != self.getFramesUntilEnd()) ] self.updateBombScore() self.updateMapScore() self.data.score = self.data._eaten[0] def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] return BombermanRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action, force=False): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board #state.data._eaten = [False for i in range(state.getNumAgents())] if state.data._eaten[agentIndex] > 0: BombermanRules.applyAction(state, action, agentIndex) if force or (agentIndex == state.getNumAgents() - 1): state.minusOneFrame() for counter, position, power, index in state.data.bombs: if counter == state.getFramesUntilEnd(): state.bombExplode(state.data.bombs, position, power) state.getAgentState(index).recoverABomb() state.data.bombs = [ b for b in state.data.bombs if (b[0] != state.getFramesUntilEnd()) ] state.updateBombScore() state.updateMapScore() # Time passes state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around # Resolve multi-agent effects #GhostRules.checkDeath( state, agentIndex ) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange return state def getAgentPosition(self, agentIndex): return self.data.agentStates[agentIndex].getPosition() def getAgentState(self, agentIndex): return self.data.agentStates[agentIndex] def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return self.data.score def getMapScore(self, x, y=None): if y is None: try: x, y = x except: raise 'incomprehensible coordinates' return self.data.MapScore[x][y] def getBombScore(self, x, y=None): if y is None: try: x, y = x except: raise 'incomprehensible coordinates' return self.data.BombScore[x][y] def hasWall(self, x, y): return self.data.map.isWall((x, y)) def isLose(self): return (self.getNumAgents() == 1 and self.data._eaten[0] == 0) or (self.data._eaten.count(0) == self.getNumAgents()) def isWin(self): return (self.getNumAgents() != 1 and self.data._eaten.count(0) is self.getNumAgents() - 1) def getFramesUntilEnd(self): return self.data.FramesUntilEnd def minusOneFrame(self): self.data.FramesUntilEnd = self.data.FramesUntilEnd - 1 return self.data.FramesUntilEnd def layABomb(self, agentIndex, pos): self.data._bombLaid.append(pos) self.data.map.add_bomb(pos) self.getAgentState(agentIndex).minusABomb() self.data.bombs.append( (self.data.FramesUntilEnd - BOMB_DURATION, pos, self.getAgentState(agentIndex).getBombPower(), agentIndex)) def bombExplode(self, bombs, position, power): x_int, y_int = position if not self.data.map.isBomb(position): return self.data._bombExplode.append(position) self.data.map.remove_object(position) fired = [] for i in range(len(self.data._fire)): fired += self.data._fire[i] if not position in fired: self.checkDie(position) self.data._fire[0].append(position) fired.append(position) for vec in [ v for dir, v in Actions._directionsAsList if (not dir in [Actions.LAY, Directions.STOP]) ]: isbreak = False i = 0 dx, dy = vec next_y, next_x = y_int, x_int while not isbreak and i < power: i = i + 1 next_y = int(next_y + dy) next_x = int(next_x + dx) pos = (next_x, next_y) if pos in fired: continue if self.data.map.isEmpty(pos): self.checkDie(pos) self.data._fire[i].append(pos) fired.append(pos) elif self.data.map.isBlock(pos): isbreak = True self.data._blockBroken.append(pos) res = self.data.map.remove_object(pos) self.data._fire[i].append(pos) fired.append(pos) if res != None: self.data._itemDrop.append((next_x, next_y, res)) elif self.data.map.isWall(pos): isbreak = True elif self.data.map.isItem(pos): self.data._itemEaten.append(pos) self.data.map.remove_object(pos) self.data._fire[i].append(pos) fired.append(pos) self.checkDie(pos) elif self.data.map.isBomb(pos): self.checkDie(pos) self.data._fire[i].append(pos) fired.append(pos) bombSweep = [(idx, bomb) for idx, bomb in enumerate(bombs) if (pos in bomb) and ( bomb[0] < self.data.FramesUntilEnd - int(BOMB_DURATION / 10))] if len(bombSweep) is 1: bombs[bombSweep[0][0]] = ( self.data.FramesUntilEnd - int(BOMB_DURATION / 10), ) + bombSweep[0][1][1:] def checkDie(self, position): x, y = position for index, agent in enumerate(self.data.agentStates): if self.data._eaten[index] is 0: continue sx, sy = agent.getPosition() sx, sy = round(sx), round(sy) if manhattanDistance(position, (sx, sy)) <= 0.5: self.data._eaten[index] -= 1 agent.configuration = agent.start def updateBombScore(self): # The change to the BombScore: self.data.BombScore.data = [[0 for y in range(self.data.map.height)] for x in range(self.data.map.width)] for counter, pos, power, index in self.data.bombs: score = self.calBombScore(counter) self.data.BombScore[pos[0]][pos[1]] += score isbreak = False for vec in [ v for dir, v in Actions._directionsAsList if (not dir in [Actions.LAY, Directions.STOP]) ]: isbreak = False i = 0 dx, dy = vec next_x, next_y = pos while not isbreak and i < power: i += 1 next_x = int(next_x + dx) next_y = int(next_y + dy) if self.data.map.isBlock( (next_x, next_y)) or self.data.map.isWall( (next_x, next_y)): isbreak = True else: self.data.BombScore[next_x][next_y] += score - i / 5.0 def updateMapScore(self): self.data.MapScore.data = [[0 for y in range(self.data.map.height)] for x in range(self.data.map.width)] for x in range(self.data.map.width): for y in range(self.data.map.height): if not self.data.map.isBlocked((x, y)) or self.data.map.isBomb( (x, y)): main = [ self.data.map.isBlocked((row, col)) for row, col in [(x + 1, y), (x - 1, y), (x, y + 1), (x, y - 1)] ] second = [ self.data.map.isBlocked((row, col)) for row, col in [(x + 1, y + 1), (x - 1, y + 1), (x + 1, y - 1), (x - 1, y - 1)] ] self.data.MapScore[x][y] = (main.count(True) * 1 + second.count(True) * 0.4) if main.count(True) == 4: self.data.MapScore[x][y] = 100 if self.data.map.isBomb((x, y)): self.data.MapScore[x][y] += 1 def calBombScore(self, counter): if self.getFramesUntilEnd() - 1 == counter: # next frame would explode return 100 return 3 * (BOMB_DURATION - (self.getFramesUntilEnd() - counter)) def getTotalLives(self, indexes): return sum([self.data._eaten[index] for index in indexes]) ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() return state def __eq__(self, other): """ Allows two states to be compared. """ return self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(self.data) def __str__(self): return str(self.data) def initialize(self, layout, numAgents=1000, timeout=3000, life=5): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numAgents, timeout, life, BOMB_DURATION)
class GameState: def getLegalActions(self, agentIndex=0): if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer(state.data.agentStates[agentIndex]) # Resolve multi-agent effects GhostRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange return state def getLegalPacmanActions(self): return self.getLegalActions(0) def generatePacmanSuccessor(self, action): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor(0, action) def getPacmanState(self): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getGhostStates(self): return self.data.agentStates[1:] def getGhostState(self, agentIndex): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition(self, agentIndex): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return self.data.score def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose(self): return self.data._lose def isWin(self): return self.data._win ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() return state def __eq__(self, other): """ Allows two states to be compared. """ return self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(self.data) def __str__(self): return str(self.data) def initialize(self, layout, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents)
class GameState: explored = set() def getAndResetExplored(): tmp = GameState.explored.copy() GameState.explored = set() return tmp getAndResetExplored = staticmethod(getAndResetExplored) def getLegalActions( self, agentIndex=0 ): if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions( self ) else: return GhostRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, agentIndex, action): if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') state = GameState(self) if agentIndex == 0: state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction( state, action ) else: GhostRules.applyAction( state, action, agentIndex ) if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY else: GhostRules.decrementTimer( state.data.agentStates[agentIndex] ) GhostRules.checkDeath( state, agentIndex ) state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange GameState.explored.add(self) GameState.explored.add(state) return state def getLegalPacmanActions( self ): return self.getLegalActions( 0 ) def generatePacmanSuccessor( self, action ): return self.generateSuccessor( 0, action ) def getPacmanState( self ): return self.data.agentStates[0].copy() def getPacmanPosition( self ): return self.data.agentStates[0].getPosition() def getGhostStates( self ): return self.data.agentStates[1:] def getGhostState( self, agentIndex ): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition( self, agentIndex ): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return float(self.data.score) def getCapsules(self): return self.data.capsules def getNumFood( self ): return self.data.food.count() def getFood(self): return self.data.food def getWalls(self): return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose( self ): return self.data._lose def isWin( self ): return self.data._win def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() return state def __eq__( self, other ): return hasattr(other, 'data') and self.data == other.data def __hash__( self ): return hash( self.data ) def __str__( self ): return str(self.data) def initialize( self, layout, numGhostAgents=1000 ): self.data.initialize(layout, numGhostAgents)
class GameState: """ Un GameState (Estado del juego) especifica el estado completo del juego, incluyendo la comida, capsulas, configuraciones del agente y cambios en el puntaje. Los GameStates son utilizados por el objeto Game para caputar el estado acutal del juego y puede ser utilizado por los agentes para razonar sobre el juego. Mucha de la informaciĆ³n en un GameState estĆ” almacenada en un objeto GameStateData. Recomendamos fuertemente que accedas a esa informaciĆ³n por medio de los mĆ©todos descritos debajo que en lugar de utilizar el objeto GameStateData directamente. Observa que en Pacman clĆ”sico, Pacman siempre es el agente 0. """ ############################################################## # Metodos de acceso: usa estos para acceder a GameStateData # ############################################################ # static variable keeps track of which states have had getLegalActions called explored = set() def getAndResetExplored(): tmp = GameState.explored.copy() GameState.explored = set() return tmp getAndResetExplored = staticmethod(getAndResetExplored) def getLegalActions(self, agentIndex=0): """ Retorna las acciones legales del agente especificado """ # GameState.explored.add(self) if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman estĆ” en movimiento return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Retorna el estado sucesor despuĆ©s de que el agente especificado realiza la acciĆ³n """ # Verifica que los sucesores existen if self.isWin() or self.isLose(): raise Exception( 'No se puede generar un sucesor de un estado terminal') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer(state.data.agentStates[agentIndex]) # Resolve multi-agent effects GhostRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange GameState.explored.add(self) GameState.explored.add(state) return state def getLegalPacmanActions(self): return self.getLegalActions(0) def generatePacmanSuccessor(self, action): """ Genera el estado sucesor despuĆ©s del movimiento de Pacman especificado """ return self.generateSuccessor(0, action) def getPacmanState(self): """ Regresa un objeto AgentState para Pacman (en game.py) state.pos gives da la posiciĆ³n actual state.direction da la direcciĆ³n del vector de viaje """ return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getGhostStates(self): return self.data.agentStates[1:] def getGhostState(self, agentIndex): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition(self, agentIndex): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return float(self.data.score) def getCapsules(self): """ Retorna una lista de posiciones (x,y) de las capsulas restantes. """ return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): """ Regresa un Grid de variables booleanas que indican el estado de la comida. Los Grids pueden ser accesados utilizando la notaciĆ³n de lista, asi que para verificar si hay comida en (x,y), simplemente llama currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Retorna un Grid de variables booleanas que indican la posiciĆ³n de las paredes. Los Grids pueden ser accesados utilizando la notaciĆ³n de lista, asi que para verificar si hay una pared en (x,y), simplemente llama walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose(self): return self.data._lose def isWin(self): return self.data._win ##################################################### # MĆ©todos auxiliares: # # No deberĆas llamar a estos mĆ©todos directamente # ##################################################### def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() return state def __eq__(self, other): """ Allows two states to be compared. """ return hasattr(other, 'data') and self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(self.data) def __str__(self): return str(self.data) def initialize(self, layout, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents)
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around # Resolve multi-agent effects GhostRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange # Pacman observes neighboring squares state.getObservation() return state def getLegalPacmanActions(self): return self.getLegalActions(0) def generatePacmanSuccessor(self, action): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor(0, action) def getPacmanState(self): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return self.data.score def isLose(self): return self.data._lose def isWin(self): return self.data._win ################################ # Additions for Hunters Pacman # ################################ def getObservation(self): x, y = self.getPacmanPosition() adjacent = [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] for x, y in adjacent: self.data.observedPositions[x][y] = True return {(x, y): self.squareInfo(x, y) for x, y in adjacent} def squareInfo(self, x, y): if self.hasWall(x, y): return WALL_STRING elif self.data.layout.redWalls[x][y]: return RED_WALL_STRING elif self.data.layout.blueWalls[x][y]: return BLUE_WALL_STRING else: return EMPTY_SQUARE_STRING def getObservedPositions(self): return self.data.observedPositions def getHouseWalls(self, house): return layout.buildHouseAroundCenter(*house) def getPossibleHouses(self): return layout.pickPossibleLocations(self.data.layout.width, self.data.layout.height) def getEvidence(self): evidence = {} possible = { w for h in self.getPossibleHouses() for w in self.getHouseWalls(h) } for pos in self.getObservedPositions().asList(): if pos in possible: evidence[pos] = self.squareInfo(*pos) return evidence ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: self.data = GameStateData(prevState.data) self.numMoves = prevState.numMoves self.maxMoves = prevState.maxMoves else: # Initial state self.data = GameStateData() self.numMoves = 0 self.maxMoves = -1 def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() return state def __eq__(self, other): """ Allows two states to be compared. """ return self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(str(self)) def __str__(self): return str(self.data) def initialize(self, layout, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents) def getGhostPosition(self, agentIndex): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex].getPosition() def getGhostState(self, agentIndex): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex] def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y]
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception("Can't generate a successor of a terminal state.") # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around # Resolve multi-agent effects GhostRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange # Pacman observes neighboring squares state.getObservation() return state def getLegalPacmanActions(self): return self.getLegalActions(0) def generatePacmanSuccessor(self, action): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor(0, action) def getPacmanState(self): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return self.data.score def isLose(self): return self.data._lose def isWin(self): return self.data._win ################################ # Additions for Hunters Pacman # ################################ def getObservation(self): x, y = self.getPacmanPosition() adjacent = [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)] for x, y in adjacent: self.data.observedPositions[x][y] = True return {(x, y): self.squareInfo(x, y) for x, y in adjacent} def squareInfo(self, x, y): if self.hasWall(x, y): return WALL_STRING elif self.data.layout.redWalls[x][y]: return RED_WALL_STRING elif self.data.layout.blueWalls[x][y]: return BLUE_WALL_STRING else: return EMPTY_SQUARE_STRING def getObservedPositions(self): return self.data.observedPositions def getHouseWalls(self, house): return layout.buildHouseAroundCenter(*house) def getPossibleHouses(self): return layout.pickPossibleLocations(self.data.layout.width, self.data.layout.height) def getEvidence(self): evidence = {} possible = {w for h in self.getPossibleHouses() for w in self.getHouseWalls(h)} for pos in self.getObservedPositions().asList(): if pos in possible: evidence[pos] = self.squareInfo(*pos) return evidence ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: self.data = GameStateData(prevState.data) self.numMoves = prevState.numMoves self.maxMoves = prevState.maxMoves else: # Initial state self.data = GameStateData() self.numMoves = 0 self.maxMoves = -1 def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() return state def __eq__(self, other): """ Allows two states to be compared. """ return self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(str(self)) def __str__(self): return str(self.data) def initialize(self, layout, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents) def getGhostPosition(self, agentIndex): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex].getPosition() def getGhostState(self, agentIndex): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex] def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y]
class GameState: """A GameState specifies the full game state. Full game state includes the food, capsules, agent configurations, and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. """ #################################################### # Accessor methods: use these to access state data # #################################################### def get_legal_actions(self, agent_index=0): """Return the legal actions for the agent specified.""" return AgentRules.get_legal_actions(self, agent_index) def generate_successor(self, agent_index, action): """Return the successor after the specified agent takes the action. Returns a GameState object """ # Copy current state state = GameState(self) # Find appropriate rules for the agent AgentRules.apply_action(state, action, agent_index) AgentRules.check_death(state, agent_index) AgentRules.decrement_timer(state.data.agent_states[agent_index]) # Book keeping state.data._agent_moved = agent_index state.data.score += state.data.score_change state.data.timeleft = self.data.timeleft - 1 return state def get_agent_state(self, index): """Return the state (game.AgentState) of agent with given index.""" return self.data.agent_states[index] def get_agent_position(self, index): """Attempt to get agent position. Return a location tuple if the agent with the given index is observable; if the agent is unobservable, return None. """ agent_state = self.data.agent_states[index] ret = agent_state.get_position() if ret: return tuple(int(x) for x in ret) return ret def get_num_agents(self): """Return number of agents.""" return len(self.data.agent_states) def get_score(self): """Return a number corresponding to the current score.""" return self.data.score def get_red_food(self): """Return a matrix of food on the red team's side. For the matrix m, m[x][y]=true if there is food in (x,y) that belongs to red (meaning red is protecting it, blue is trying to eat it). """ return half_grid(self.data.food, red=True) def get_blue_food(self): """Return a matrix of food on the blue team's side. For the matrix m, m[x][y]=true if there is food in (x,y) that belongs to blue (meaning blue is protecting it, red is trying to eat it). """ return half_grid(self.data.food, red=False) def get_red_capsules(self): """Return list of capsule positions (x,y) on the red team's side.""" return half_list(self.data.capsules, self.data.food, red=True) def get_blue_capsules(self): """Retun list of capsule positions (x,y) on the blue team's side.""" return half_list(self.data.capsules, self.data.food, red=False) def get_walls(self): """Return a matrix of wall positions.""" return self.data.layout.walls def has_food(self, x, y): """Return true if the location (x,y) has food. This is regardless of whether it's blue team food or red team food. """ return self.data.food[x][y] def has_wall(self, x, y): """Return true if (x,y) has a wall, false otherwise.""" return self.data.layout.walls[x][y] def is_over(self): """Return if game is over.""" return self.data._win def get_red_team_indices(self): """Return a list of agent indices for the agents on the red team.""" return self.red_team[:] def get_blue_team_indices(self): """Return a list of agent indices for the agents on the blue team.""" return self.blue_team[:] def is_on_red_team(self, agent_index): """Return true if the agent is on the red team.""" return self.teams[agent_index] def get_agent_distances(self): """Return a noisy distance to each agent.""" if 'agent_distances' in dir(self): return self.agent_distances else: return None def get_distance_prob(self, true_distance, noisy_distance): """Return the probability of noisy_distance given true_distance.""" if noisy_distance - true_distance in SONAR_NOISE_VALUES: return 1.0 / SONAR_NOISE_RANGE else: return 0 def get_initial_agent_position(self, agent_index): """Return the initial position of an agent.""" return self.data.layout.agent_positions[agent_index][1] def get_capsules(self): """Return a list of positions (x,y) of the remaining capsules.""" return self.data.capsules ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prev_state=None): """Generate a new state by copying information from its predecessor.""" if prev_state is not None: # Initial state self.data = GameStateData(prev_state.data) self.blue_team = prev_state.blue_team self.red_team = prev_state.red_team self.data.timeleft = prev_state.data.timeleft self.teams = prev_state.teams self.agent_distances = prev_state.agent_distances else: self.data = GameStateData() self.agent_distances = [] def deep_copy(self): """Return a deep copy of this state.""" state = GameState(self) state.data = self.data.deep_copy() state.data.timeleft = self.data.timeleft state.blue_team = self.blue_team[:] state.red_team = self.red_team[:] state.teams = self.teams[:] state.agent_distances = self.agent_distances[:] return state def make_observation(self, index): """Make observation for agent with given index. Return a GameState instance. """ state = self.deep_copy() # Adds the sonar signal pos = state.get_agent_position(index) n = state.get_num_agents() distances = [ noisy_distance(pos, state.get_agent_position(i)) for i in range(n) ] state.agent_distances = distances # Remove states of distant opponents if index in self.blue_team: team = self.blue_team other_team = self.red_team else: other_team = self.blue_team team = self.red_team for enemy in other_team: seen = False enemy_pos = state.get_agent_position(enemy) for teammate in team: if ((util.manhattan_distance( enemy_pos, state.get_agent_position(teammate)) <= SIGHT_RANGE)): seen = True if not seen: state.data.agent_states[enemy].configuration = None return state def __eq__(self, other): """Allow two states to be compared.""" if other is None: return False return self.data == other.data def __hash__(self): """Allow states to be keys of dictionaries.""" return int(hash(self.data)) def __str__(self): """Allow conversion to string.""" return str(self.data) def initialize(self, layout, num_agents): """Create an initial game state from a layout array (see layout.py).""" self.data.initialize(layout, num_agents) positions = [a.configuration for a in self.data.agent_states] self.blue_team = [ i for i, p in enumerate(positions) if not self.is_red(p) ] self.red_team = [i for i, p in enumerate(positions) if self.is_red(p)] self.teams = [self.is_red(p) for p in positions] # This is usually 60 (always 60 with random maps) # However, if layout map is specified otherwise, it could be less global TOTAL_FOOD TOTAL_FOOD = layout.total_food def is_red(self, config_or_pos): """Determine if position in on the red side of the board.""" width = self.data.layout.width if isinstance(config_or_pos, tuple): return config_or_pos[0] < width / 2 else: return config_or_pos.position[0] < width / 2
class GameState(object): """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### ghostDirections = {} def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions( self ) else: return GhostRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction( state, action ) else: # A ghost is moving GhostRules.applyAction( state, action, agentIndex ) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer( state.data.agentStates[agentIndex] ) # Resolve multi-agent effects GhostRules.checkDeath( state, agentIndex ) # Check food eaten GhostRules.checkFoodEaten ( state, agentIndex ) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange p = state.getPacmanPosition() state.data.ghostDistances = [getNoisyDistance(p, state.getGhostPosition(i)) for i in range(1,state.getNumAgents())] state.ghostPositions = self.ghostPositions = [self.getGhostPosition(i) for i in range(1, self.getNumAgents())] a = 0 for i in range(1, self.getNumAgents()): self.ghostDirections[a] = (state.data.agentStates[i].configuration.getDirection()) a += 1 if agentIndex == self.getNumAgents() - 1: state.numMoves += 1 return state def getLegalPacmanActions( self ): return self.getLegalActions( 0 ) def generatePacmanSuccessor( self, action ): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor( 0, action ) def getPacmanState( self ): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition( self ): return self.data.agentStates[0].getPosition() def getNumAgents( self ): try: return len( self.getGhostPositions() )+1 except: return len( self.data.agentStates ) def getScore( self ): return self.data.score def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood( self ): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] ############################## # Additions for Busters Pacman # ############################## def getLivingGhosts(self): """ Returns a list of booleans indicating which ghosts are not yet captured. The first entry (a placeholder for Pacman's index) is always False. """ return self.livingGhosts def getDistanceNearestFood(self): """ Returns the distance to the nearest food """ if(self.getNumFood() > 0): minDistance = 900000 pacmanPosition = self.getPacmanPosition() for i in range(self.data.layout.width): for j in range(self.data.layout.height): if self.hasFood(i, j): foodPosition = i, j distance = util.manhattanDistance(pacmanPosition, foodPosition) if distance < minDistance: minDistance = distance return minDistance else: return None def getDistanceNearestGhost(self, x, y): positions = self.getGhostPositions() livingGhosts = self.getLivingGhosts()[1:] # Remove Pacman from list of ghosts ghostCount = [] ghostPositions = [] for i in range(len(positions)): # Store only the ghosts marked as True and their positions in the above lists if livingGhosts[i] == True: ghostCount.append(livingGhosts[i]) ghostPositions.append(positions[i]) if len(ghostCount) > 0: # Check that there are still some ghosts alive objectPosition = (x, y) distances = [] for j in ghostPositions: ghostPosition = j[0],j[1] distance = util.manhattanDistance(objectPosition, ghostPosition) if distance >= 0: distances.append(distance) minDistance = min(distances) closestGhost = ghostPositions[distances.index(minDistance)] else: minDistance = math.inf closestGhost = (-1,-1) return minDistance, closestGhost def getGhostPositions(self): return self.ghostPositions def getGhostDirections(self): return self.ghostDirections def setGhostNotLiving(self, index): self.livingGhosts[index] = False def isLose( self ): return self.maxMoves > 0 and self.numMoves >= self.maxMoves def isWin( self ): return self.livingGhosts.count(True) == 0 def getNoisyGhostDistances(self): """ Returns a noisy distance to each ghost. """ return self.data.ghostDistances ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: self.data = prevState.data.deepCopy() self.livingGhosts = prevState.livingGhosts[:] self.ghostPositions = prevState.ghostPositions[:] self.numMoves = prevState.numMoves; self.maxMoves = prevState.maxMoves; else: # Initial state self.data = GameStateData() self.numMoves = 0; self.maxMoves = -1; self.data.ghostDistances = [] def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() state.data.ghostDistances = self.data.ghostDistances return state def __eq__( self, other ): """ Allows two states to be compared. """ if (other): return self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return hash( str( self ) ) def __str__( self ): return str(self.data) def initialize( self, layout, numGhostAgents=1000 ): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents) self.data.ghostDistances = [getNoisyDistance(self.getPacmanPosition(), self.getGhostPosition(i)) for i in range(1, self.getNumAgents())] self.ghostPositions = [self.getGhostPosition(i) for i in range(1, self.getNumAgents())] self.livingGhosts = [False] + [True for i in range(len(self.getGhostPositions()))] def getGhostPosition( self, agentIndex ): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostDirection( self, agentIndex ): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostDirection") return self.data.agentStates[agentIndex].getDirection() def getGhostState( self, agentIndex ): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex]
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ return AgentRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Copy current state state = GameState(self) # Find appropriate rules for the agent AgentRules.applyAction( state, action, agentIndex ) AgentRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange return state def getAgentState(self, index): return self.data.agentStates[index] def getAgentPosition(self, index): " Note: this could return None if the agent is unobservable " agentState = self.data.agentStates[index] return agentState.getPosition() def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return self.data.score def getRedFood(self): return halfGrid(self.data.food, red = True) def getBlueFood(self): return halfGrid(self.data.food, red = False) def getWalls(self): """ Just like getFood but for walls """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isOver( self ): return self.data._win def getRedTeamIndices(self): return self.redTeam[:] def getBlueTeamIndices(self): return self.blueTeam[:] def isOnRedTeam(self, agentIndex): return self.teams[agentIndex] def getAgentDistances(self): "Returns a noisy distance to each agent." if 'agentDistances' in dir(self) : return self.agentDistances else: return None ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) self.blueTeam = prevState.blueTeam self.redTeam = prevState.redTeam self.teams = prevState.teams self.agentDistances = prevState.agentDistances else: self.data = GameStateData() self.agentDistances = [] def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() state.blueTeam = self.blueTeam[:] state.redTeam = self.redTeam[:] state.teams = self.teams[:] state.agentDistances = self.agentDistances[:] return state def makeObservation(self, index): state = self.deepCopy() # Adds the sonar signal pos = state.getAgentPosition(index) n = state.getNumAgents() distances = [noisyDistance(pos, state.getAgentPosition(i)) for i in range(n)] state.agentDistances = distances # Remove states of distant opponents if index in self.blueTeam: team = self.blueTeam otherTeam = self.redTeam else: otherTeam = self.blueTeam team = self.redTeam for enemy in otherTeam: seen = False enemyPos = state.getAgentPosition(enemy) for teammate in team: if util.manhattanDistance(enemyPos, state.getAgentPosition(teammate)) <= SIGHT_RANGE: seen = True if not seen: state.data.agentStates[enemy].configuration = None return state def __eq__( self, other ): """ Allows two states to be compared. """ if other == None: return False return self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return int(hash( self.data )) def __str__( self ): return str(self.data) def initialize( self, layout, numAgents): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numAgents) positions = [a.configuration for a in self.data.agentStates] self.blueTeam = [i for i,p in enumerate(positions) if not self.isRed(p)] self.redTeam = [i for i,p in enumerate(positions) if self.isRed(p)] self.teams = [self.isRed(p) for p in positions] def isRed(self, configOrPos): width = self.data.layout.width if type(configOrPos) == type( (0,0) ): return configOrPos[0] < width / 2 else: return configOrPos.pos[0] < width / 2
class GameState: """A GameState specifies the full game state. Full game state includes the food, capsules, agent configurations, and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### # static variable keeps track of which states have had get_legal_actions # called explored = set() @staticmethod def get_and_reset_explored(): """Return a copy of the explored set and reset the original.""" tmp = GameState.explored.copy() GameState.explored = set() return tmp def get_legal_actions(self, agent_index=0): """Return the legal actions for the agent specified.""" if self.is_win() or self.is_lose(): return [] if agent_index == 0: # Pacman is moving return PacmanRules.get_legal_actions(self) else: return GhostRules.get_legal_actions(self, agent_index) def generate_successor(self, agent_index, action): """Generate the successor state after specified agent takes action.""" # Check that successors exist if self.is_win() or self.is_lose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agent_index == 0: # Pacman is moving state.data._eaten = [False for i in range(state.get_num_agents())] PacmanRules.apply_action(state, action) else: # A ghost is moving GhostRules.apply_action(state, action, agent_index) # Time passes if agent_index == 0: # Penalty for waiting around state.data.score_change += -TIME_PENALTY else: GhostRules.decrement_timer(state.data.agent_states[agent_index]) # Resolve multi-agent effects GhostRules.check_death(state, agent_index) # Book keeping state.data._agent_moved = agent_index state.data.score += state.data.score_change GameState.explored.add(self) GameState.explored.add(state) return state def get_legal_pacman_actions(self): """Return legal actions for pacman (convience function). (convenience function that calls get_legal_actions with pacman's index) """ return self.get_legal_actions(0) def generate_pacman_successor(self, action): """Generate successor state after the specified pacman action. (convenience function that calls generate_successor with pacman's index) """ return self.generate_successor(0, action) def get_pacman_state(self): """Return an game.AgentState object for pacman. state.position gives the current position state.direction gives the travel vector """ return self.data.agent_states[0].copy() def get_pacman_position(self): """Return pacman's position.""" return self.data.agent_states[0].get_position() def get_ghost_states(self): """Return list of game.AgentState objects for all ghosts.""" return self.data.agent_states[1:] def get_ghost_state(self, agent_index): """Return game.AgentState object for specified ghost. :raise IndexError if invalid agent_index. """ if agent_index == 0 or agent_index >= self.get_num_agents(): raise IndexError("Invalid index passed to get_ghost_state") return self.data.agent_states[agent_index] def get_ghost_position(self, agent_index): """Return position of specified ghost. :raise IndexError if invalid agent_index. """ return self.get_ghost_state(agent_index).get_position() def get_ghost_positions(self): """Return list of ghost positions for all ghosts.""" return [s.get_position() for s in self.get_ghost_states()] def get_num_agents(self): """Return total number of agents (pacman + ghosts).""" return len(self.data.agent_states) def get_score(self): """Return score of the state.""" return float(self.data.score) def get_capsules(self): """Return a list of positions (x,y) of the remaining capsules.""" return self.data.capsules def get_num_food(self): """Return number of food pellets in the game state.""" return self.data.food.count() def get_food(self): """Return a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call current_food = state.get_food() if current_food[x][y] == True: ... """ return self.data.food def get_walls(self): """Return a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is a wall at (x,y), just call walls = state.get_walls() if walls[x][y] == True: ... """ return self.data.layout.walls def has_food(self, x, y): """Return whether there is food at (x,y).""" return self.data.food[x][y] def has_wall(self, x, y): """Return whether there is a wall at (x,y).""" return self.data.layout.walls[x][y] def is_lose(self): """Return if the state is a losing one.""" return self.data._lose def is_win(self): """Return if the state is a winning one.""" return self.data._win ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prev_state=None): """Generate a new state by copying information from its predecessor.""" if prev_state is not None: # Initial state self.data = GameStateData(prev_state.data) else: self.data = GameStateData() def deep_copy(self): """Return a deep copy of the state.""" state = GameState(self) state.data = self.data.deep_copy() return state def __eq__(self, other): """Allow two states to be compared.""" return hasattr(other, 'data') and self.data == other.data def __hash__(self): """Allow states to be keys of dictionaries / set entries.""" return hash(self.data) def __str__(self): """Return string representation of state.""" return str(self.data) def initialize(self, layout, num_ghost_agents=1000): """Create an initial game state from a layout array (see layout.py).""" self.data.initialize(layout, num_ghost_agents)
def __init__(self, prev_state=None): """Generate a new state by copying information from its predecessor.""" if prev_state is not None: # Initial state self.data = GameStateData(prev_state.data) else: self.data = GameStateData()
class GameState: """ A GameState specifies the full game state, including the food, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that Green House Worker is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### # static variable keeps track of which states have had getLegalActions called explored = set() def getAndResetExplored(): tmp = GameState.explored.copy() GameState.explored = set() return tmp getAndResetExplored = staticmethod(getAndResetExplored) def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ GameState.explored.add(self) if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return GHworkerRules.getLegalActions( self ) def generateSuccessor( self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] GHworkerRules.applyAction( state, action ) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange return state def getLegalGHworkerActions( self ): return self.getLegalActions( 0 ) def generateGHworkerSuccessor( self, action ): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor( 0, action ) def getGHworkerState( self ): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getGHworkerPosition( self ): return self.data.agentStates[0].getPosition() def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return self.data.score def getNumFood( self ): print "getNumFood" print self.data.food return self.data.food.count() def getNumGHs( self ): print "getNumGHs" print self.data._foodEaten return self.data._foodEaten.count() def getFood(self): """ Returns a Grid of boolean food indicator variables (strawberries!) Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose( self ): return self.data._lose def isWin( self ): return self.data._win ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() return state def __eq__( self, other ): """ Allows two states to be compared. """ return self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return hash( self.data ) def __str__( self ): return str(self.data) def initialize( self, layout): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout)
class GameState: def getLegalActions(self, agentIndex=0): if self.isWin() or self.isLose(): return [] if agentIndex == 0: return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): if self.isWin() or self.isLose(): raise Exception("Can\'t generate a successor of a terminal state.") state = GameState(self) if agentIndex == 0: state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) else: GhostRules.applyAction(state, action, agentIndex) if agentIndex == 0: state.data.scoreChange += 0 else: GhostRules.decrementTimer(state.data.agentStates[agentIndex]) GhostRules.checkDeath(state, agentIndex) state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange return state def getLegalPacmanActions(self): return self.getLegalActions(0) def generatePacmanSuccessor(self, action): return self.generateSuccessor(0, action) def getPacmanState(self): return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getGhostStates(self): return self.data.agentStates[1:] def getGhostState(self, agentIndex): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise BaseException("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition(self, agentIndex): if agentIndex == 0: raise BaseException("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return self.data.score def getCapsules(self): return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): return self.data.food def getWalls(self): return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose(self): return self.data._lose def isWin(self): return self.data._win def __init__(self, prevState=None): if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() return state def __eq__(self, other): if other == None: return self.data == other return self.data == other.data def __hash__(self): return hash(str(self)) def __str__(self): return str(self.data) def initialize(self, layout, numGhostAgents=1000): self.data.initialize(layout, numGhostAgents)
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### # static variable keeps track of which states have had getLegalActions called explored = set() def getAndResetExplored(self): tmp = GameState.explored.copy() GameState.explored = set() return tmp getAndResetExplored = staticmethod(getAndResetExplored) def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ # GameState.explored.add(self) if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) ghostPosition = state.getGhostPosition(agentIndex) state.explorePositionSurrounding(ghostPosition, agentIndex) state.data.ghostDistances[agentIndex - 1] = self.getGhostDistance(agentIndex) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer(state.data.agentStates[agentIndex]) # Resolve multi-agent effects GhostRules.checkDeath(state, agentIndex) #print(self.getBestSectors(5)) # Book keeping state.data._agentMoved = agentIndex state.visibleData._agentMoved = agentIndex state.visibleData.fitness += self.fitnessfunction() state.data.score += state.data.scoreChange state.visibleData.score += state.data.scoreChange state.data.fitness += self.fitnessfunction() state.data.fitnessChange += self.fitnessfunction() state.visibleData.previousExploredCount = self.countExploredTiles() GameState.explored.add(self) GameState.explored.add(state) return state def getLegalPacmanActions(self): return self.getLegalActions(0) def generatePacmanSuccessor(self, action): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor(0, action) def getPacmanState(self): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getPacmanPositionIfVisible(self): pacman_position = self.getPacmanPosition() for ghost_position in self.getGhostPositions(): withinXBound = ghost_position[0] - self.ghostVisionDistance <= pacman_position[0] and\ ghost_position[0] + self.ghostVisionDistance >= pacman_position[0] withinYBound = ghost_position[1] - self.ghostVisionDistance <= pacman_position[1] and\ ghost_position[1] + self.ghostVisionDistance >= pacman_position[1] withinBound = withinXBound and withinYBound if withinBound: return self.getPacmanPosition() return None def getGhostStates(self): return self.data.agentStates[1:] def getGhostState(self, agentIndex): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition(self, agentIndex): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] def fitnessfunction(self): sightingPoint = 1000 points = 0 maxTime = self.data.maxTime currentTime = self.data.timeRemaining timeRatio = currentTime / maxTime if self.getPacmanPositionIfVisible() != None: points += sightingPoint * timeRatio #exploration points explorationPoint = 10 * timeRatio ##fix unexplored count points += explorationPoint * (self.countExploredTiles() - self.visibleData.previousExploredCount) return points def countExploredTiles(self): j = 0 for i in range(len(self.visibleData.unexplored)): if self.visibleData.unexplored[i] == False: j += 1 return j def getGhostDistance(self, ghost_index): pacman_position = self.getPacmanPosition() ghost_position = self.data.agentStates[ghost_index].getPosition() ghostDistance = manhattanDistance(pacman_position, ghost_position) return ghostDistance def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return float(self.data.score) def getFitness(self): return self.data.fitness def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is a wall at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def getBestSectors(self, topCount): maxTime = self.data.maxTime currentTime = self.data.timeRemaining timeRatio = currentTime / maxTime * 1.0 rowCount = self.data.sectorrow colCount = self.data.sectorcol PacManPoint = 2 * (1 - (timeRatio + 0.1)) print(timeRatio) print(PacManPoint) ghostPoint = -2 if topCount > rowCount * colCount: topCount = rowCount * colCount y = self.getWalls().__getheight__() x = self.getWalls().__getwidth__() sectorWidth = math.floor(x / colCount) sectorHeight = math.floor(y / rowCount) #how you compute a sector number sector = (math.floor(x / sectorWidth) + 1) * (math.floor(y / sectorHeight) + 1) #now count where each ghost, pac is #pacman pacX, pacY = self.data.agentStates[0].getPosition() pacSector, pacMinSec, pacMaxSec = self.getSectorPosition( pacX, pacY, sectorWidth, sectorHeight) ghostSector = {} sectorScore = {} sectorMax = {} sectorMin = {} sectorCount = 0 for row in range(rowCount): for col in range(colCount): #min x_min = col * sectorWidth y_min = row * sectorHeight x_max = x_min + sectorWidth y_max = y_min + sectorHeight if y_max >= y: y_max = y - 1 if x_max >= x: x_max = x - 1 sectorMin[sectorCount + 1] = (x_min, y_min) sectorMax[sectorCount + 1] = (x_max, y_max) sectorCount += 1 #populate based on sector count for i in range(rowCount * colCount): ghostSector[i + 1] = 0 sectorScore[i + 1] = 0 #get sector per ghosts for ghost in range(len(self.data.agentStates) - 1): gX, gY = self.data.agentStates[ghost + 1].getPosition() sector, sec_min, sec_max = self.getSectorPosition( gX, gY, sectorWidth, sectorHeight) ghostSector[sector] += 1 sectorScore[pacSector] += PacManPoint queue = [] for i in range(colCount * rowCount): sectorScore[i + 1] += ghostSector[i + 1] * ghostPoint if i + 1 != pacSector: sectorScore[i + 1] += 0.5 * random.random() queue.append((sectorScore[i + 1], i + 1)) topSectorsPairs = sorted(queue, key=lambda tup: tup[0], reverse=True) topSectors = [] for i in range(len(topSectorsPairs)): topSectors.append(topSectorsPairs[i][1]) topSubSectors = [] for s in range(topCount): topSubSectors.append(topSectors[s]) topSectors = topSubSectors return topSectors, [sectorMin[i] for i in topSectors ], [sectorMax[i] for i in topSectors] def getSectorPosition(self, x, y, sectorWidth, sectorHeight): xcal = math.floor(x / sectorWidth) ycal = math.floor(y / sectorHeight) if xcal == math.floor(x / sectorWidth) and xcal > 1: xcal -= 1 if ycal == math.floor(y / sectorHeight) and ycal > 1: ycal -= 1 return (xcal + 1) * (ycal + 1), (xcal, ycal), (xcal + sectorWidth, ycal + sectorHeight) def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose(self): return self.data._lose def isWin(self): return self.data._win "adding method to help figure out how much ghost has explored" def getExplored(self): #print(type(self.visibleData.layout.unexplored)) return self.visibleData.layout.unexplored def getToExplore(self): return self.visibleData.layout.unexploredAccessible def resetExplored(self): self.visibleData.layout.resUn() ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) self.visibleData = GameStateData(prevState.visibleData) self.visibleData.agentStates = self.data.agentStates self.visibleData.ghostDistances = self.data.ghostDistances self.ghostVisionDistance = prevState.ghostVisionDistance else: self.data = GameStateData() self.visibleData = GameStateData() def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() return state def __eq__(self, other): """ Allows two states to be compared. """ return hasattr(other, 'data') and self.data == other.data and \ hasattr(other, 'visibleData') and self.visibleData == other.visibleData def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(self.data) def __str__(self): return str(self.data) def initialize(self, fullLayout, ghostVisionDistance, numGhostAgents=1000, sectorrow=2, sectorcol=3): """ Creates an initial game state from a layout array (see layout.py). """ self.ghostVisionDistance = ghostVisionDistance self.data.initialize(fullLayout, numGhostAgents, sectorrow, sectorcol) self.visibleData.initialize(fullLayout, numGhostAgents, sectorrow, sectorcol) def explorePositionSurrounding(self, position, agentIndex): orig_x, orig_y = position width = self.visibleData.layout.width height = self.visibleData.layout.height min_x = int(max(0, orig_x - self.ghostVisionDistance)) max_x = int(min(width, orig_x + self.ghostVisionDistance + 1)) min_y = int(max(0, orig_y - self.ghostVisionDistance)) max_y = int(min(height, orig_y + self.ghostVisionDistance + 1)) brmin_x = (min_x > 0) brmax_x = (max_x + 1 < width) brmin_y = (min_y > 0) brmax_y = (max_y + 1 < height) self.visibleData._visited = self.visibleData._visible[agentIndex - 1] self.visibleData._visible[agentIndex - 1] = [] for y in range(min_y, max_y): borderymin = (brmin_y and y == min_y) borderymax = (brmax_y and y == max_y - 1) for x in range(min_x, max_x): self.visibleData.food[x][y] = self.data.food[x][y] if (x, y) in self.data.capsules and ( x, y) not in self.visibleData.capsules: self.visibleData.capsules.append((x, y)) elif (x, y) in self.visibleData.capsules and ( x, y) not in self.data.capsules: self.visibleData.capsules.remove((x, y)) self.visibleData.layout.walls[x][y] = self.data.layout.walls[ x][y] self.visibleData.layout.food[x][y] = self.data.layout.food[x][ y] self.visibleData.layout.unexplored[x][y] = False self.visibleData.layout.unexploredRepeat[x][y] = False self.visibleData.layout.unexploredAccessible[x][y] = False #if self.visibleData.unexplored[x][y]: self.visibleData._visible[agentIndex - 1].append((x, y)) if (x, y) in self.visibleData._visited: self.visibleData._visited.remove((x, y)) if (brmin_x and x == min_x and self.visibleData.layout.unexploredRepeat[x - 1][y] and not (self.visibleData.layout.walls[x][y])): self.visibleData.layout.unexploredAccessible[x - 1][y] = True if (brmax_x and x == max_x - 1 and self.visibleData.layout.unexploredRepeat[x + 1][y] and not (self.visibleData.layout.walls[x][y])): self.visibleData.layout.unexploredAccessible[x + 1][y] = True if (borderymin and self.visibleData.layout.unexploredRepeat[x][y - 1] and not (self.visibleData.layout.walls[x][y])): self.visibleData.layout.unexploredAccessible[x][y - 1] = True if (borderymax and self.visibleData.layout.unexploredRepeat[x][y + 1] and not (self.visibleData.layout.walls[x][y])): self.visibleData.layout.unexploredAccessible[x][y + 1] = True
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ return AgentRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Returns the successor state (a GameState object) after the specified agent takes the action. """ # Copy current state state = GameState(self) # Find appropriate rules for the agent AgentRules.applyAction(state, action, agentIndex) AgentRules.checkDeath(state, agentIndex) AgentRules.decrementTimer(state.data.agentStates[agentIndex]) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange state.data.timeleft = self.data.timeleft - 1 return state def getAgentState(self, index): return self.data.agentStates[index] def getAgentPosition(self, index): """ Returns a location tuple if the agent with the given index is observable; if the agent is unobservable, returns None. """ agentState = self.data.agentStates[index] ret = agentState.getPosition() if ret: return tuple(int(x) for x in ret) return ret def getNumAgents(self): return len(self.data.agentStates) def getScore(self): """ Returns a number corresponding to the current score. """ return self.data.score def getRedFood(self): """ Returns a matrix of food that corresponds to the food on the red team's side. For the matrix m, m[x][y]=true if there is food in (x,y) that belongs to red (meaning red is protecting it, blue is trying to eat it). """ return halfGrid(self.data.food, red=True) def getBlueFood(self): """ Returns a matrix of food that corresponds to the food on the blue team's side. For the matrix m, m[x][y]=true if there is food in (x,y) that belongs to blue (meaning blue is protecting it, red is trying to eat it). """ return halfGrid(self.data.food, red=False) def getRedCapsules(self): return halfList(self.data.capsules, self.data.food, red=True) def getBlueCapsules(self): return halfList(self.data.capsules, self.data.food, red=False) def getWalls(self): """ Just like getFood but for walls """ return self.data.layout.walls def hasFood(self, x, y): """ Returns true if the location (x,y) has food, regardless of whether it's blue team food or red team food. """ return self.data.food[x][y] def hasWall(self, x, y): """ Returns true if (x,y) has a wall, false otherwise. """ return self.data.layout.walls[x][y] def isOver(self): return self.data._win def getRedTeamIndices(self): """ Returns a list of agent index numbers for the agents on the red team. """ return self.redTeam[:] def getBlueTeamIndices(self): """ Returns a list of the agent index numbers for the agents on the blue team. """ return self.blueTeam[:] def isOnRedTeam(self, agentIndex): """ Returns true if the agent with the given agentIndex is on the red team. """ return self.teams[agentIndex] def getAgentDistances(self): """ Returns a noisy distance to each agent. """ if 'agentDistances' in dir(self) : return self.agentDistances else: return None def getDistanceProb(self, trueDistance, noisyDistance): "Returns the probability of a noisy distance given the true distance" if noisyDistance - trueDistance in SONAR_NOISE_VALUES: return 1.0 / SONAR_NOISE_RANGE else: return 0 def getInitialAgentPosition(self, agentIndex): "Returns the initial position of an agent." return self.data.layout.agentPositions[agentIndex][1] def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) self.blueTeam = prevState.blueTeam self.redTeam = prevState.redTeam self.data.timeleft = prevState.data.timeleft self.teams = prevState.teams self.agentDistances = prevState.agentDistances else: self.data = GameStateData() self.agentDistances = [] def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() state.data.timeleft = self.data.timeleft state.blueTeam = self.blueTeam[:] state.redTeam = self.redTeam[:] state.teams = self.teams[:] state.agentDistances = self.agentDistances[:] return state def makeObservation(self, index): state = self.deepCopy() # Adds the sonar signal pos = state.getAgentPosition(index) n = state.getNumAgents() distances = [noisyDistance(pos, state.getAgentPosition(i)) for i in range(n)] state.agentDistances = distances # Remove states of distant opponents if index in self.blueTeam: team = self.blueTeam otherTeam = self.redTeam else: otherTeam = self.blueTeam team = self.redTeam for enemy in otherTeam: seen = False enemyPos = state.getAgentPosition(enemy) for teammate in team: if util.manhattanDistance(enemyPos, state.getAgentPosition(teammate)) <= SIGHT_RANGE: seen = True if not seen: state.data.agentStates[enemy].configuration = None return state def __eq__(self, other): """ Allows two states to be compared. """ if other == None: return False return self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return int(hash(self.data)) def __str__(self): return str(self.data) def initialize(self, layout, numAgents): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numAgents) positions = [a.configuration for a in self.data.agentStates] self.blueTeam = [i for i, p in enumerate(positions) if not self.isRed(p)] self.redTeam = [i for i, p in enumerate(positions) if self.isRed(p)] self.teams = [self.isRed(p) for p in positions] def isRed(self, configOrPos): width = self.data.layout.width if type(configOrPos) == type((0, 0)): return configOrPos[0] < width / 2 else: return configOrPos.pos[0] < width / 2
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions( self ) else: return GhostRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction( state, action ) else: # A ghost is moving GhostRules.applyAction( state, action, agentIndex ) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer( state.data.agentStates[agentIndex] ) # Resolve multi-agent effects GhostRules.checkDeath( state, agentIndex ) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange p = state.getPacmanPosition() state.data.ghostDistances = [getNoisyDistance(p, state.getGhostPosition(i)) for i in range(1,state.getNumAgents())] if agentIndex == self.getNumAgents() - 1: state.numMoves += 1 return state def getLegalPacmanActions( self ): return self.getLegalActions( 0 ) def generatePacmanSuccessor( self, action ): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor( 0, action ) def getPacmanState( self ): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition( self ): return self.data.agentStates[0].getPosition() def setAgentPosition(self, pos, agentIndex): self.data.agentStates[agentIndex].setPosition(pos) def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return self.data.score def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood( self ): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] ############################## # Additions for Busters Pacman # ############################## def getLivingGhosts(self): """ Returns a list of booleans indicating which ghosts are not yet captured. The first entry (a placeholder for Pacman's index) is always False. """ return self.livingGhosts def setGhostNotLiving(self, index): self.livingGhosts[index] = False def isLose( self ): return self.data._lose def isWin( self ): return self.data._win """ def isLose( self ): return self.maxMoves > 0 and self.numMoves >= self.maxMoves def isWin( self ): return self.livingGhosts.count(True) == 0 """ def getNoisyGhostDistances(self): """ Returns a noisy distance to each ghost. """ return self.data.ghostDistances def generateStateObservationReward(self, agent, ghostAgents, action): gameStateCopy = self.deepCopy() nextGameState = gameStateCopy.generateSuccessor(0, action) for (i, ghostAgent) in zip(range(1, len(ghostAgents)+1), ghostAgents): if nextGameState.isWin() or nextGameState.isLose(): break nextGameState = nextGameState.generateSuccessor( i, ghostAgent.getAction(nextGameState)) reward = nextGameState.getScore() - self.getScore() if agent.obsOnStopOnly: if action == Directions.STOP: observation = nextGameState.getNoisyGhostDistances() else: observation = [None] else: observation = nextGameState.getNoisyGhostDistances() return (nextGameState, tuple(observation), reward) ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: self.data = GameStateData(prevState.data) self.livingGhosts = prevState.livingGhosts[:] self.numMoves = prevState.numMoves; self.maxMoves = prevState.maxMoves; else: # Initial state self.data = GameStateData() self.numMoves = 0; self.maxMoves = -1; self.data.ghostDistances = [] def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() state.data.ghostDistances = self.data.ghostDistances return state def __eq__( self, other ): """ Allows two states to be compared. """ return self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return hash( str( self ) ) def __str__( self ): return str(self.data) def initialize( self, layout, numGhostAgents=1000 ): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents) self.livingGhosts = [False] + [True for i in range(numGhostAgents)] self.data.ghostDistances = [getNoisyDistance(self.getPacmanPosition(), self.getGhostPosition(i)) for i in range(1, self.getNumAgents())] def getGhostPosition( self, agentIndex ): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex].getPosition() def getGhostState( self, agentIndex ): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex]
class GameState: """ A ćGameStateć specifies the full game state, including the food, capsulesč¶å, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a ćGameStateDatać object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions( self, agentIndex=0 ): """ ä¼ å „agentIndexļ¼čæåå ¶å½ååÆéactions Returns the legal actions for the agent specified. """ return AgentRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, agentIndex, action): """ čæåęäøŖagentļ¼åØå½ågameStateļ¼ę§č”å®ęäøŖactionļ¼ ä¹åēgameStateļ¼ęÆäøŖę“äøŖå°å¾ēē½ę ¼ę°ę®ļ¼å½ęę¹åØčå“5å ļ¼ä¼ę¾ē¤ŗåÆ¹ę¹ ļ¼ Returns the successor state (a GameState object) after the specified agent takes the action. """ # Copy current state state = GameState(self) # Find appropriate rules for the agentéčæęøøęč§åę“ę°gamestate AgentRules.applyAction( state, action, agentIndex ) AgentRules.checkDeath(state, agentIndex) AgentRules.decrementTimer(state.data.agentStates[agentIndex]) # Book keeping 记蓦ļ¼ę“ę°āč°ē§»åØčæāļ¼āå½ååę°āļ¼āęå©ę¶é“ā state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange state.data.timeleft = self.data.timeleft - 1 return state def getAgentState(self, index): """ ä¼ å „äøäøŖagentIndexļ¼čæåå ¶å½åē¶ęćč„äøåØčå“å ļ¼ä¼čæåčŗ«ä»½ļ¼ä½å ¶ä½å¼äøŗnoneć ę ¼å¼äøŗļ¼å½åčŗ«ä»½ļ¼ä½ē½®ļ¼čæåØę¹å Ghost: (x,y)=(9.0, 13.0), East Ghost: None Pacman: (x,y)=(19.0, 6.0), West """ return self.data.agentStates[index] def getAgentPosition(self, index): """ å¦ęå½åä¼ å „ēagentęÆåÆč§ēļ¼é£ä¹čæåå ¶åę ļ¼å ē»ļ¼ļ¼äøåÆč§ļ¼čæåNone Returns a location tuple if the agent with the given index is observable; if the agent is unobservable, returns None. """ agentState = self.data.agentStates[index] ret = agentState.getPosition() if ret: return tuple(int(x) for x in ret) return ret def getNumAgents( self ): """ čæåå½åęøøęäøagentēę°éļ¼å¼äøē“ęÆåŗå®ē4 """ return len( self.data.agentStates ) def getScore( self ): """ čæåå½åå·±ę¹ēåę°ļ¼ Returns a number corresponding to the current score. """ return self.data.score def getRedFood(self): """ čæåēŗ¢ę¹č¦äæę¤ēč±ļ¼ē©éµ,éé¢å ØęÆT/F Returns a matrix of food that corresponds to the food on the red team's side. For the matrix m, m[x][y]=true if there is food in (x,y) that belongs to red (meaning red is protecting it, blue is trying to eat it). """ return halfGrid(self.data.food, red = True) def getBlueFood(self): """ čæåčę¹č¦äæę¤ēč±ļ¼ē©éµ,éé¢å ØęÆT/F Returns a matrix of food that corresponds to the food on the blue team's side. For the matrix m, m[x][y]=true if there is food in (x,y) that belongs to blue (meaning blue is protecting it, red is trying to eat it). """ return halfGrid(self.data.food, red = False) def getRedCapsules(self): """ čæåēŗ¢ę¹č¦äæę¤ēāåčŗ«č¶åā """ return halfList(self.data.capsules, self.data.food, red = True) def getBlueCapsules(self): """ čæåčę¹č¦äæę¤ēāåčŗ«č¶åā """ return halfList(self.data.capsules, self.data.food, red = False) def getWalls(self): """ čæåäøäøŖāå¢āē©éµļ¼å ØęÆT/F Just like getFood but for walls """ return self.data.layout.walls def hasFood(self, x, y): """ å¤ęå ·ä½ęäøŖē¹ęÆå¦ęé£ē©ļ¼ętureļ¼ę false Returns true if the location (x,y) has food, regardless of whether it's blue team food or red team food. """ return self.data.food[x][y] def hasWall(self, x, y): """ å¤ęå ·ä½ęäøŖē¹ęÆå¦ęāå¢ā Returns true if (x,y) has a wall, false otherwise. """ return self.data.layout.walls[x][y] def isOver( self ): """ å¤ęęøøęęÆå¦ē»ęļ¼ęä»ä¹ēØļ¼ęøøęē»ęåļ¼čæäøŖę¹ę³ä¹ę§č”äøäŗćå¦åäøē“čæåfalse """ return self.data._win def getRedTeamIndices(self): """ čæåēŗ¢éēagentē“¢å¼å¼,ę ¼å¼äøŗļ¼[0, 2] Returns a list of agent index numbers for the agents on the red team. """ return self.redTeam[:] def getBlueTeamIndices(self): """ Returns a list of the agent index numbers for the agents on the blue team. """ return self.blueTeam[:] def isOnRedTeam(self, agentIndex): """ å¤ęęäøŖindiceęÆå¦å±äŗēŗ¢é Returns true if the agent with the given agentIndex is on the red team. """ return self.teams[agentIndex] def getAgentDistances(self): """ čæåęÆäøŖagentå°å½åagentēē²ē³č·ē¦»listļ¼ ę ¼å¼äøŗļ¼[4, 32, -3, 29]ļ¼åƹåŗēå°0-3 agentIndicesēč·ē¦»ć Returns a noisy distance to each agent. """ if 'agentDistances' in dir(self) : return self.agentDistances else: return None def getDistanceProb(self, trueDistance, noisyDistance): """ ä¼ å „å®é č·ē¦»åē²ē³č·ē¦»ļ¼č®”ē®ē²ē³č·ē¦»ēāåÆäæ”åŗ¦āć ęä¹ēØļ¼å¦ęęē„éēå®č·ē¦»ļ¼ęč¦ē²ē³č·ē¦»å¹²ä»ä¹ēØļ¼ Returns the probability of a noisy distance given the true distance """ if noisyDistance - trueDistance in SONAR_NOISE_VALUES: return 1.0/SONAR_NOISE_RANGE else: return 0 def getInitialAgentPosition(self, agentIndex): """ ę ¹ę®indexč·åčÆ„agentēåŗēä½ē½®ļ¼åƹäŗåäøäøŖå°å¾ļ¼čÆ„å¼ęÆåŗå®ēć Returns the initial position of an agent. """ return self.data.layout.agentPositions[agentIndex][1] def getCapsules(self): """ čæåå©ä½ēāč¶ ēŗ§č¶åāēåę list Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) self.blueTeam = prevState.blueTeam self.redTeam = prevState.redTeam self.data.timeleft = prevState.data.timeleft self.teams = prevState.teams self.agentDistances = prevState.agentDistances else: self.data = GameStateData() self.agentDistances = [] def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() state.data.timeleft = self.data.timeleft state.blueTeam = self.blueTeam[:] state.redTeam = self.redTeam[:] state.teams = self.teams[:] state.agentDistances = self.agentDistances[:] return state def makeObservation(self, index): state = self.deepCopy() # Adds the sonar signal pos = state.getAgentPosition(index) n = state.getNumAgents() distances = [noisyDistance(pos, state.getAgentPosition(i)) for i in range(n)] state.agentDistances = distances # Remove states of distant opponents if index in self.blueTeam: team = self.blueTeam otherTeam = self.redTeam else: otherTeam = self.blueTeam team = self.redTeam for enemy in otherTeam: seen = False enemyPos = state.getAgentPosition(enemy) for teammate in team: if util.manhattanDistance(enemyPos, state.getAgentPosition(teammate)) <= SIGHT_RANGE: seen = True if not seen: state.data.agentStates[enemy].configuration = None return state def __eq__( self, other ): """ Allows two states to be compared. """ if other == None: return False return self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return int(hash( self.data )) def __str__( self ): return str(self.data) def initialize( self, layout, numAgents): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numAgents) positions = [a.configuration for a in self.data.agentStates] self.blueTeam = [i for i,p in enumerate(positions) if not self.isRed(p)] self.redTeam = [i for i,p in enumerate(positions) if self.isRed(p)] self.teams = [self.isRed(p) for p in positions] #This is usually 60 (always 60 with random maps) #However, if layout map is specified otherwise, it could be less global TOTAL_FOOD TOTAL_FOOD = layout.totalFood def isRed(self, configOrPos): width = self.data.layout.width if type(configOrPos) == type( (0,0) ): return configOrPos[0] < width / 2 else: return configOrPos.pos[0] < width / 2
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### # static variable keeps track of which states have had getLegalActions called explored = set() def getAndResetExplored(): tmp = GameState.explored.copy() GameState.explored = set() return tmp getAndResetExplored = staticmethod(getAndResetExplored) def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ # GameState.explored.add(self) if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions( self ) else: return GhostRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, action ): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose() or self.eventQueue.isEmpty(): raise Exception('Can\'t generate a successor of a terminal state.') time, event = self.eventQueue.peek() assert event.isAgentMove(), 'Can only generate successors of a state where an agent is about to move' state = self.makeAgentMove(action) state.resolveEventsUntilAgentEvent() # Book keeping GameState.explored.add(self.data) GameState.explored.add(state.data) return state def makeAgentMove( self, action ): # Copy current state state = GameState(self) time, event = state.eventQueue.pop() agentIndex = event.getAgentIndex() agentState = state.data.agentStates[agentIndex] state.data.time = time delay = agentState.powers.timestepsBetweenMoves state.registerEventWithDelay(event, delay) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction( state, action ) state.data.scoreChange -= TIME_PENALTY # Penalty for waiting around else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) GhostRules.decrementTimer(agentState) # Resolve multi-agent effects GhostRules.checkDeath( state, agentIndex ) if action == Directions.LASER: GhostRules.checkLaserShot(state,agentIndex) if action == Directions.BLAST: GhostRules.checkBlast(state,agentIndex) # Book keeping state.data._agentMoved = agentIndex # Note: It is important that the following value accurately # reflects when Pacman will make the next move, even if the # speed changes (such as a speed-up power pellet). Otherwise # the graphics will do weird things. state.data._timeTillAgentMovesAgain = delay state.data._action = action state.data.score += state.data.scoreChange return state def runEvent( self ): # Check that successors exist if self.eventQueue.isEmpty(): raise Exception('Can\'t run an event of a terminal state.') time, event = self.eventQueue.pop() assert not event.isAgentMove(), 'Can\'t run an AgentMoveEvent' self.data.time = time event.trigger(self) return event def getNextEvent( self ): _, event = self.eventQueue.peek() return event def getLegalPacmanActions( self ): return self.getLegalActions( 0 ) def getPacmanState( self ): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition( self ): return self.data.agentStates[0].getPosition() def getPacmanDirection(self): return self.data.agentStates[0].getDirection() def getGhostStates( self ): return self.data.agentStates[1:] def getGhostState( self, agentIndex ): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition( self, agentIndex ): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] def getNextAgentIndex(self): for time, event in self.eventQueue.getSortedTimesAndEvents(): if event.isAgentMove(): return event.getAgentIndex() assert False, "No more moves can be made" def getAgentMoveTime(self, agentIndex): for time, event in self.eventQueue.getSortedTimesAndEvents(): if event.isAgentMove(): if event.getAgentIndex() == agentIndex: return time assert False, "No more moves can be made by agent " + str(agentIndex) def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return float(self.data.score) def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood( self ): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is a wall at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.walls[x][y] def isLose( self ): return self.data._lose def isWin( self ): return self.data._win ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) self.eventQueue = prevState.eventQueue.deepCopy() else: self.data = GameStateData() self.eventQueue = EventQueue() def resolveEventsUntilAgentEvent(self): # Resolve any events until the next agent event while not self.eventQueue.isEmpty(): time, event = self.eventQueue.peek() if event.isAgentMove(): return else: self.runEvent() def registerEventWithDelay(self, event, delay): self.eventQueue.registerEventAtTime(event, self.data.time + delay) def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() # Event queue has already been copied in the constructor return state def __eq__( self, other ): """ Allows two states to be compared. """ return hasattr(other, 'data') and self.data == other.data \ and hasattr(other, 'eventQueue') and self.eventQueue == other.eventQueue \ def __hash__( self ): """ Allows states to be keys of dictionaries. """ return hash( (self.data, self.eventQueue) ) def __str__( self ): return str(self.data) def initialize( self, layout, pacmanPowers, ghostPowers, numGhostAgents=1000 ): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, pacmanPowers, ghostPowers, numGhostAgents) numAgents = self.getNumAgents() for i in range(numAgents): self.registerEventWithDelay(AgentMoveEvent(i), i) self.registerEventWithDelay(WallTimerEvent(), 1)
class GameState: explored = set() def getAndResetExplored(): tmp = GameState.explored.copy() GameState.explored = set() return tmp getAndResetExplored = staticmethod(getAndResetExplored) def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ # GameState.explored.add(self) if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer(state.data.agentStates[agentIndex]) # Resolve multi-agent effects GhostRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange GameState.explored.add(self) GameState.explored.add(state) return state def getLegalPacmanActions(self): return self.getLegalActions(0) def generatePacmanSuccessor(self, action): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor(0, action) def getPacmanState(self): return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getGhostStates(self): return self.data.agentStates[1:] def getGhostState(self, agentIndex): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition(self, agentIndex): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return float(self.data.score) def getCapsules(self): return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): return self.data.food def getWalls(self): return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose(self): return self.data._lose def isWin(self): return self.data._win def __init__(self, prevState=None): if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() return state def __eq__(self, other): """ Allows two states to be compared. """ return hasattr(other, 'data') and self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(self.data) def __str__(self): return str(self.data) def initialize(self, layout, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents)
class CornerMaz: # static variable keeps track of which states have had getLegalActions called explored = set() def generateSuccessor(self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = CornerMaz(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange GameState.explored.add(self) GameState.explored.add(state) return state def getLegalPacmanActions(self): return self.getLegalActions(0) def generatePacmanSuccessor(self, action): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor(0, action) def getPacmanState(self): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getNumFood(self): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is a wall at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def isLose(self): return self.data._lose def isWin(self): return self.data._win ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() return state def __eq__(self, other): """ Allows two states to be compared. """ return hasattr(other, 'data') and self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(self.data) def __str__(self): return str(self.data) def initialize(self, layout, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents)
class PacmanPlot(PacmanGraphics): def __init__(self, x=None, y=None, zoom=1.0, frameTime=0.0): """ Create and dispaly a pacman plot figure. If both x and y are provided, plot the points (x[i],y[i]) for all i in len(x). This will draw on the existing pacman window (clearing it first) or create a new one if no window exists. x: array or list of N scalar values. Default=None, in which case no points will be plotted y: array or list of N scalar values. Default=None, in which case no points will be plotted """ super(PacmanPlot, self).__init__(zoom, frameTime) if x is None or y is None: width = 23 height = 23 xmin = -(width-1)/2+1 ymin = -(height-1)/2+1 self.initPlot(xmin, ymin, width, height) else: self.plot(x,y) def initPlot(self, xmin, ymin, width, height): if graphicsUtils._canvas is not None: graphicsUtils.clear_screen() # Initialize GameStateData with blank board with axes self.width = width self.height = height self.xShift = -(xmin-1) self.yShift = -(ymin-1) self.line = None self.zoom = min(30.0/self.width, 20.0/self.height) self.gridSize = graphicsDisplay.DEFAULT_GRID_SIZE * self.zoom # fullRow = ['%']*self.width # row = ((self.width-1)/2)*[' '] + ['%'] + ((self.width-1)/2)*[' '] # boardText = ((self.height-1)/2)*[row] + [fullRow] + ((self.height-1)/2)*[row] numSpaces = self.width-1 numSpacesLeft = self.xShift numSpacesRight = numSpaces-numSpacesLeft numRows = self.height numRowsBelow = self.yShift numRowsAbove = numRows-1-numRowsBelow fullRow = ['%']*self.width if numSpacesLeft < 0: row = [' ']*self.width else: row = numSpacesLeft*[' '] + ['%'] + numSpacesRight*[' '] boardText = numRowsAbove*[row] + [fullRow] + numRowsBelow*[row] layout = Layout(boardText) self.blankGameState = GameStateData() self.blankGameState.initialize(layout, 0) self.initialize(self.blankGameState) title = 'Pacman Plot' graphicsUtils.changeText(self.infoPane.scoreText, title) graphicsUtils.refresh() def plot(self, x, y, weights=None, title='Pacman Plot'): """ Plot the input values x with their corresponding output values y (either true or predicted). Also, plot the linear regression line if weights are given; assuming h_w(x) = weights[0]*x + weights[1]. This will draw on the existing pacman window (clearing it first) or create a new one if no window exists. x: array or list of N scalar values. y: array or list of N scalar values. weights: array or list of 2 values (or if just one value, the bias weight is assumed to be zero). If None, no line is drawn. Default: None """ if np.array(x).size == 0: return if isinstance(x[0], np.ndarray): # Scrape the first element of each data point x = [data[0] for data in x] xmin = int(math.floor(min(x))) ymin = int(math.floor(min(y))) xmax = int(math.ceil(max(x))) ymax = int(math.ceil(max(y))) width = xmax-xmin+3 height = ymax-ymin+3 self.initPlot(xmin, ymin, width, height) gameState = self.blankGameState.deepCopy() gameState.agentStates = [] # Add ghost at each point for (px,py) in zip(x,y): point = (px+self.xShift, py+self.yShift) gameState.agentStates.append( AgentState( Configuration( point, Directions.STOP), False) ) # self.initialize(gameState) graphicsUtils.clear_screen() self.infoPane = InfoPane(gameState.layout, self.gridSize) self.drawStaticObjects(gameState) self.drawAgentObjects(gameState) graphicsUtils.changeText(self.infoPane.scoreText, title) graphicsUtils.refresh() def setWeights(self, weights): pass def takeControl(self): """ Give full control to the window. Blocks current thread. Program will exit when window is closed. """ mainloop()
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### # static variable keeps track of which states have had getLegalActions called explored = set() def getAndResetExplored(): tmp = GameState.explored.copy() GameState.explored = set() return tmp getAndResetExplored = staticmethod(getAndResetExplored) def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ # GameState.explored.add(self) if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer(state.data.agentStates[agentIndex]) # Resolve multi-agent effects GhostRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange GameState.explored.add(self) GameState.explored.add(state) return state def getLegalPacmanActions(self): return self.getLegalActions(0) def generatePacmanSuccessor(self, action): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor(0, action) def getPacmanState(self): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getGhostStates(self): return self.data.agentStates[1:] def getGhostState(self, agentIndex): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition(self, agentIndex): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return float(self.data.score) def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is a wall at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose(self): return self.data._lose def isWin(self): return self.data._win ############################################# # Elena methods : # # Metodos anhadidos para funcionalidad q # ############################################# """ FOOD """ def getDistanceNearestFood(self): """ Returns the distance to the nearest food """ if (self.getNumFood() > 0): minDistance = 900000 pacmanPosition = self.getPacmanPosition() for i in range(self.data.layout.width): for j in range(self.data.layout.height): if self.hasFood(i, j): foodPosition = i, j distance = util.manhattanDistance( pacmanPosition, foodPosition) if distance < minDistance: minDistance = distance return minDistance else: return None def getPositionNearestFood(self): if not self.getFoodPositions(): return None else: return min(self.getFoodPositions()) def getFoodPositions(self): """ Elena: returns an array of food positions """ foodPositionArray = [] for i in range(self.data.layout.width): for j in range(self.data.layout.height): if self.hasFood(i, j): foodPositionArray.append((i, j)) return foodPositionArray """ GHOSTS """ def getLivingGhosts(self): """ Returns a list of booleans indicating which ghosts are not yet captured. The first entry (a placeholder for Pacman's index) is always False. """ return self.livingGhosts def getPositionNearestGhost(self): if all(v is None for v in self.data.ghostDistances): return None else: livingGhosts = self.getLivingGhosts() return self.getGhostPositions()[self.data.ghostDistances.index( min(value for value in self.data.ghostDistances if value is not None))] def getGhostDirections(self): return self.ghostDirections def setGhostNotLiving(self, index): self.livingGhosts[index] = False """ WALLS: POR DEFINIR """ ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() return state def __eq__(self, other): """ Allows two states to be compared. """ return hasattr(other, 'data') and self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(self.data) def __str__(self): return str(self.data) def initialize(self, layout, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents)
def __init__(self, prevState=None): if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData()
class PacmanPlotLP(PacmanGraphics): def __init__(self, constraints=[], infeasiblePoints=[], feasiblePoints=[], optimalPoint=None, costVector=None, zoom=1.0, frameTime=0.0): """ Create and dispaly a pacman plot figure. This will draw on the existing pacman window (clearing it first) or create a new one if no window exists. constraints: list of inequality constraints, where each constraint w1*x + w2*y <= b is represented as a tuple ((w1, w2), b) infeasiblePoints (food): list of points where each point is a tuple (x, y) feasiblePoints (power): list of points where each point is a tuple (x, y) optimalPoint (pacman): optimal point as a tuple (x, y) costVector (shading): cost vector represented as a tuple (c1, c2), where cost is c1*x + c2*x """ super(PacmanPlotLP, self).__init__(zoom, frameTime) xmin = 100000 ymin = 100000 xmax = -100000 ymax = -100000 for point in feasiblePoints: if point[0] < xmin: xmin = point[0] if point[0] > xmax: xmax = point[0] if point[1] < ymin: ymin = point[1] if point[1] > ymax: ymax = point[1] if len(feasiblePoints) == 0: for point in infeasiblePoints: if point[0] < xmin: xmin = point[0] if point[0] > xmax: xmax = point[0] if point[1] < ymin: ymin = point[1] if point[1] > ymax: ymax = point[1] xmin = int(math.floor(xmin)) - 3 ymin = int(math.floor(ymin)) - 3 xmax = int(math.ceil(xmax)) + 3 ymax = int(math.ceil(ymax)) + 3 width = xmax - xmin + 1 height = ymax - ymin + 1 # p = feasiblePoints[2] # print("p={}".format(p)) # print("feasible={}".format(self.pointFeasible(p, constraints))) # g = self.cartesianToLayout(xmin, ymin, xmax, ymax, p) # print("g={}".format(g)) # gr = (int(round(g[0])), int(round(g[1]))) # p2 = self.layoutToCartesian(xmin, ymin, xmax, ymax, gr) # print("p2={}".format(p2)) # print("p2 feasible={}".format(self.pointFeasible(p2, constraints))) layoutLists = self.blankLayoutLists(width, height) self.addInfeasibleGhosts(layoutLists, constraints, xmin, ymin, xmax, ymax) layoutLists = self.changeBorderGhostsToWall(layoutLists) for point in infeasiblePoints: self.addCartesianPointToLayout(layoutLists, point, '.', xmin, ymin, xmax, ymax) for point in feasiblePoints: self.addCartesianPointToLayout(layoutLists, point, 'o', xmin, ymin, xmax, ymax) if optimalPoint is not None: self.addCartesianPointToLayout(layoutLists, optimalPoint, 'P', xmin, ymin, xmax, ymax) if graphicsUtils._canvas is not None: graphicsUtils.clear_screen() # Initialize GameStateData with blank board with axes self.width = width self.height = height self.zoom = min(30.0 / self.width, 20.0 / self.height) self.gridSize = graphicsDisplay.DEFAULT_GRID_SIZE * self.zoom maxNumGhosts = 10000 layout = Layout(layoutLists) self.blankGameState = GameStateData() self.blankGameState.initialize(layout, maxNumGhosts) self.initialize(self.blankGameState) title = 'Pacman Plot LP' graphicsUtils.changeText(self.infoPane.scoreText, title) graphicsUtils.refresh() if costVector is not None: self.shadeCost(layoutLists, constraints, costVector, feasiblePoints, xmin, ymin, xmax, ymax) def takeControl(self): """ Give full control to the window. Blocks current thread. Program will exit when window is closed. """ mainloop() def pointCost(self, costVector, point): return costVector[0] * point[0] + costVector[1] * point[1] def shadeCost(self, layout, constraints, costVector, feasiblePoints, xmin, ymin, xmax, ymax): baseColor = [1.0, 0.0, 0.0] costs = [self.pointCost(costVector, point) for point in feasiblePoints] minCost = min(costs) maxCost = max(costs) costSpan = maxCost - minCost allFeasiblePoints = self.getFeasibleLayoutPoints( layout, constraints, xmin, ymin, xmax, ymax) # The feasible points themselves may have been gridded to infeasible grid points, # but we want to make sure they are shaded too. #cornerPoints = [self.cartesianToLayout(xmin, ymin, xmax, ymax, point) for point in feasiblePoints] cornerPoints = self.getLayoutPointsWithSymbol(layout, ('o', 'P')) gridPointsToShade = cornerPoints + allFeasiblePoints for gridPoint in gridPointsToShade: point = self.layoutToCartesian(xmin, ymin, xmax, ymax, gridPoint) relativeCost = (self.pointCost(costVector, point) - minCost) * 1.0 / costSpan # Whoops our grid points are flipped top-bottom from what to_screen expects screenPos = self.to_screen( (gridPoint[0], len(layout) - gridPoint[1] - 1)) cellColor = [ 0.25 + 0.5 * relativeCost * channel for channel in baseColor ] graphicsUtils.square(screenPos, 0.5 * self.gridSize, color=graphicsUtils.formatColor(*cellColor), filled=1, behind=2) graphicsUtils.refresh() def layoutToCartesian(self, xmin, ymin, xmax, ymax, point): xnew = point[0] + xmin ynew = (ymax - ymin) - point[1] + ymin return (xnew, ynew) def cartesianToLayout(self, xmin, ymin, xmax, ymax, point): xnew = point[0] - xmin ynew = (ymax - ymin) - (point[1] - ymin) return (xnew, ynew) def printLayout(self, layout): print('-' * (len(layout[0]) + 2)) for row in layout: print('|' + ''.join(row) + '|') print('-' * (len(layout[0]) + 2)) def blankLayoutLists(self, width, height): layout = [] for _ in range(height): row = [' '] * width layout.append(row) return layout def roundPoint(self, p): return (int(round(p[0])), int(round(p[1]))) def setLayoutWall(self, layout, point): self.setLayoutPoint(layout, point, '%') def getLayoutPointsWithSymbol(self, layout, symbolSet): points = [] for gy in range(len(layout)): for gx in range(len(layout[0])): if layout[gy][gx] in symbolSet: points.append((gx, gy)) return points def getLayoutSymbol(self, layout, point): point = self.roundPoint(point) if point[0] >= 0 and point[0] < len( layout[0]) and point[1] >= 0 and point[1] < len(layout): return layout[point[1]][point[0]] return None def setLayoutPoint(self, layout, point, symbol): point = self.roundPoint(point) if point[0] >= 0 and point[0] < len( layout[0]) and point[1] >= 0 and point[1] < len(layout): layout[point[1]][point[0]] = symbol return True return False def distance(self, p1, p2): vec = (p2[0] - p1[0], p2[1] - p1[1]) vecLen = math.sqrt(vec[0]**2 + vec[1]**2) return vecLen def addLineToLayout(self, layout, p1, p2): radius = 1 STEPS_PER_UNIT = 10 fullVec = (p2[0] - p1[0], p2[1] - p1[1]) fullVecLen = math.sqrt(fullVec[0]**2 + fullVec[1]**2) stepVec = (fullVec[0] / fullVecLen / STEPS_PER_UNIT, fullVec[1] / fullVecLen / STEPS_PER_UNIT) numSteps = int(math.ceil(fullVecLen) * STEPS_PER_UNIT) self.setLayoutWall(layout, p1) point = p1 while point != p2: # Generate four connected points deltas = [(-1, 0), (0, 1), (1, 0), (0, -1)] nextPoints = [(point[0] + delta[0], point[1] + delta[1]) for delta in deltas] distances = [ self.distance(nextPoint, p2) for nextPoint in nextPoints ] minDist = distances[0] minIndex = 0 for i, dist in enumerate(distances): if dist < minDist: minDist = dist minIndex = i #print("distances={}, minIndex={}".format(distances, minIndex)) point = nextPoints[minIndex] self.setLayoutWall(layout, point) #print("p1={}, point={}, p2={}".format(p1, point, p2)) #for n in range(1, numSteps+1): # x = p1[0] + n*stepVec[0] # y = p1[1] + n*stepVec[1] # self.setLayoutWall(layout, (x,y)) def getCartesianSymbol(self, layout, point, xmin, ymin, xmax, ymax): point = self.cartesianToLayout(xmin, ymin, xmax, ymax, point) return self.getLayoutSymbol(layout, point) def addCartesianPointToLayout(self, layout, point, symbol, xmin, ymin, xmax, ymax): point = self.cartesianToLayout(xmin, ymin, xmax, ymax, point) return self.setLayoutPoint(layout, point, symbol) def addCartesianLineToLayout(self, layout, w1, w2, b, xmin, ymin, xmax, ymax): (p1, p2) = lineBoxIntersection(w1, w2, b, xmin, ymin, xmax, ymax) p1 = self.cartesianToLayout(xmin, ymin, xmax, ymax, p1) p2 = self.cartesianToLayout(xmin, ymin, xmax, ymax, p2) self.addLineToLayout(layout, p1, p2) def pointFeasible(self, point, constraints): EPSILON = 1e-6 for constraint in constraints: if constraint[0][0] * point[0] + constraint[0][1] * point[ 1] > constraint[1] + EPSILON: #print("Infeasible: point={}, constraint={}".format(point, constraint)) #print("\t{}*{} + {}*{} = {}".format(constraint[0][0], point[0], constraint[0][1], point[1], constraint[0][0]*point[0] + constraint[0][1]*point[1])) return False return True def getFeasibleLayoutPoints(self, layout, constraints, xmin, ymin, xmax, ymax): height = len(layout) width = len(layout[0]) layoutPoints = [] for gy in range(height): for gx in range(width): point = self.layoutToCartesian(xmin, ymin, xmax, ymax, (gx, gy)) if self.pointFeasible(point, constraints): layoutPoints.append((gx, gy)) return layoutPoints def addInfeasibleGhosts(self, layout, constraints, xmin, ymin, xmax, ymax): numGhosts = 0 height = len(layout) width = len(layout[0]) for gy in range(height): for gx in range(width): point = self.layoutToCartesian(xmin, ymin, xmax, ymax, (gx, gy)) if not self.pointFeasible(point, constraints): self.setLayoutPoint(layout, (gx, gy), 'G') numGhosts += 1 return numGhosts def isSymbolNeighbor(self, layout, point, symbols): deltas = [(-1, -1), (-1, 0), (-1, 1), (0, 1), (1, 1), (1, 0), (1, -1), (0, -1)] neighborSymbols = [ self.getLayoutSymbol(layout, (point[0] + delta[0], point[1] + delta[1])) for delta in deltas ] for symbol in symbols: if symbol in neighborSymbols: return True return False def changeBorderGhostsToWall(self, layout): width = len(layout[0]) height = len(layout) newLayout = self.blankLayoutLists(width, height) for gy in range(height): for gx in range(width): symbol = self.getLayoutSymbol(layout, (gx, gy)) newLayout[gy][gx] = symbol if symbol == 'G': if self.isSymbolNeighbor(layout, (gx, gy), (' ', 'o', 'P')): newLayout[gy][gx] = '%' return newLayout
class PacmanPlot(PacmanGraphics): def __init__(self, x=None, y=None, zoom=1.0, frameTime=0.0): """ Create and dispaly a pacman plot figure. If both x and y are provided, plot the points (x[i],y[i]) for all i in len(x). This will draw on the existing pacman window (clearing it first) or create a new one if no window exists. x: array or list of N scalar values. Default=None, in which case no points will be plotted y: array or list of N scalar values. Default=None, in which case no points will be plotted """ super(PacmanPlot, self).__init__(zoom, frameTime) if x is None or y is None: width = 23 height = 23 xmin = -(width - 1) / 2 + 1 ymin = -(height - 1) / 2 + 1 self.initPlot(xmin, ymin, width, height) else: self.plot(x, y) def initPlot(self, xmin, ymin, width, height): if graphicsUtils._canvas is not None: graphicsUtils.clear_screen() # Initialize GameStateData with blank board with axes self.width = width self.height = height self.xShift = -(xmin - 1) self.yShift = -(ymin - 1) self.line = None self.zoom = min(30.0 / self.width, 20.0 / self.height) self.gridSize = graphicsDisplay.DEFAULT_GRID_SIZE * self.zoom # fullRow = ['%']*self.width # row = ((self.width-1)/2)*[' '] + ['%'] + ((self.width-1)/2)*[' '] # boardText = ((self.height-1)/2)*[row] + [fullRow] + ((self.height-1)/2)*[row] numSpaces = self.width - 1 numSpacesLeft = self.xShift numSpacesRight = numSpaces - numSpacesLeft numRows = self.height numRowsBelow = self.yShift numRowsAbove = numRows - 1 - numRowsBelow fullRow = ['%'] * self.width if numSpacesLeft < 0: row = [' '] * self.width else: row = numSpacesLeft * [' '] + ['%'] + numSpacesRight * [' '] boardText = numRowsAbove * [row] + [fullRow] + numRowsBelow * [row] layout = Layout(boardText) self.blankGameState = GameStateData() self.blankGameState.initialize(layout, 0) self.initialize(self.blankGameState) title = 'Pacman Plot' graphicsUtils.changeText(self.infoPane.scoreText, title) graphicsUtils.refresh() def plot(self, x, y, weights=None, title='Pacman Plot'): """ Plot the input values x with their corresponding output values y (either true or predicted). Also, plot the linear regression line if weights are given; assuming h_w(x) = weights[0]*x + weights[1]. This will draw on the existing pacman window (clearing it first) or create a new one if no window exists. x: array or list of N scalar values. y: array or list of N scalar values. weights: array or list of 2 values (or if just one value, the bias weight is assumed to be zero). If None, no line is drawn. Default: None """ if np.array(x).size == 0: return if isinstance(x[0], np.ndarray): # Scrape the first element of each data point x = [data[0] for data in x] xmin = int(math.floor(min(x))) ymin = int(math.floor(min(y))) xmax = int(math.ceil(max(x))) ymax = int(math.ceil(max(y))) width = xmax - xmin + 3 height = ymax - ymin + 3 self.initPlot(xmin, ymin, width, height) gameState = self.blankGameState.deepCopy() gameState.agentStates = [] # Add ghost at each point for (px, py) in zip(x, y): point = (px + self.xShift, py + self.yShift) gameState.agentStates.append( AgentState(Configuration(point, Directions.STOP), False)) # self.initialize(gameState) graphicsUtils.clear_screen() self.infoPane = InfoPane(gameState.layout, self.gridSize) self.drawStaticObjects(gameState) self.drawAgentObjects(gameState) graphicsUtils.changeText(self.infoPane.scoreText, title) graphicsUtils.refresh() def setWeights(self, weights): pass def takeControl(self): """ Give full control to the window. Blocks current thread. Program will exit when window is closed. """ mainloop()
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions( self ) else: return GhostRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction( state, action ) else: # A ghost is moving GhostRules.applyAction( state, action, agentIndex ) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer( state.data.agentStates[agentIndex] ) # Resolve multi-agent effects GhostRules.checkDeath( state, agentIndex ) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange p = state.getPacmanPosition() if agentIndex == self.getNumAgents() - 1: state.numMoves += 1 return state def getLegalPacmanActions( self ): return self.getLegalActions( 0 ) def generatePacmanSuccessor( self, action ): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor( 0, action ) def getPacmanState( self ): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition( self ): return self.data.agentStates[0].getPosition() def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return self.data.score def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood( self ): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] ############################## # Additions for Busters Pacman # ############################## def getLivingGhosts(self): """ Returns a list of booleans indicating which ghosts are not yet captured. The first entry (a placeholder for Pacman's index) is always False. """ return self.livingGhosts def setGhostNotLiving(self, index): self.livingGhosts[index] = False def isLose( self ): return self.maxMoves > 0 and self.numMoves >= self.maxMoves def isWin( self ): return self.livingGhosts.count(True) == 0 def getTrueWallPerception(self,location): p = [] x,y = location for action in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]: dx, dy = Actions.directionToVector(action) nextx, nexty = int(x + dx), int(y + dy) p.append( ( action,self.hasWall( nextx, nexty ) ) ) return tuple(p) def getNoisyWalls(self): position = self.getPacmanPosition() perception = [] for action in [Directions.NORTH, Directions.SOUTH, Directions.EAST, Directions.WEST]: x,y = position dx, dy = Actions.directionToVector(action) nextx, nexty = int(x + dx), int(y + dy) isWall = self.hasWall(nextx,nexty) if util.flipCoin(EPSILON): isWall = not isWall perception.append( ( action, isWall ) ) return tuple(perception) def getBoardWidth(self): return self.getWalls().width def getBoardHeight(self): return self.getWalls().height ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: self.data = GameStateData(prevState.data) self.livingGhosts = prevState.livingGhosts[:] self.numMoves = prevState.numMoves; self.maxMoves = prevState.maxMoves; else: # Initial state self.data = GameStateData() self.numMoves = 0; self.maxMoves = -1; def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() return state def __eq__( self, other ): """ Allows two states to be compared. """ return self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return hash( str( self ) ) def __str__( self ): return str(self.data) def initialize( self, layout, numGhostAgents=1000 ): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents) self.livingGhosts = [False] + [True for i in range(numGhostAgents)] def getGhostPosition( self, agentIndex ): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex].getPosition() def getGhostState( self, agentIndex ): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex]
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ return AgentRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Copy current state state = GameState(self) # Find appropriate rules for the agent AgentRules.applyAction(state, action, agentIndex) AgentRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange return state def getAgentState(self, index): return self.data.agentStates[index] def getAgentPosition(self, index): " Note: this could return None if the agent is unobservable " agentState = self.data.agentStates[index] return agentState.getPosition() def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return self.data.score def getRedFood(self): return halfGrid(self.data.food, red=True) def getBlueFood(self): return halfGrid(self.data.food, red=False) def getWalls(self): """ Just like getFood but for walls """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isOver(self): return self.data._win def getRedTeamIndices(self): return self.redTeam[:] def getBlueTeamIndices(self): return self.blueTeam[:] def isOnRedTeam(self, agentIndex): return self.teams[agentIndex] def getAgentDistances(self): "Returns a noisy distance to each agent." if 'agentDistances' in dir(self): return self.agentDistances else: return None ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) self.blueTeam = prevState.blueTeam self.redTeam = prevState.redTeam self.teams = prevState.teams self.agentDistances = prevState.agentDistances else: self.data = GameStateData() self.agentDistances = [] def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() state.blueTeam = self.blueTeam[:] state.redTeam = self.redTeam[:] state.teams = self.teams[:] state.agentDistances = self.agentDistances[:] return state def makeObservation(self, index): state = self.deepCopy() # Adds the sonar signal pos = state.getAgentPosition(index) n = state.getNumAgents() distances = [ noisyDistance(pos, state.getAgentPosition(i)) for i in range(n) ] state.agentDistances = distances # Remove states of distant opponents if index in self.blueTeam: team = self.blueTeam otherTeam = self.redTeam else: otherTeam = self.blueTeam team = self.redTeam for enemy in otherTeam: seen = False enemyPos = state.getAgentPosition(enemy) for teammate in team: if util.manhattanDistance( enemyPos, state.getAgentPosition(teammate)) <= SIGHT_RANGE: seen = True if not seen: state.data.agentStates[enemy].configuration = None return state def __eq__(self, other): """ Allows two states to be compared. """ if other == None: return False return self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return int(hash(self.data)) def __str__(self): return str(self.data) def initialize(self, layout, numAgents): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numAgents) positions = [a.configuration for a in self.data.agentStates] self.blueTeam = [ i for i, p in enumerate(positions) if not self.isRed(p) ] self.redTeam = [i for i, p in enumerate(positions) if self.isRed(p)] self.teams = [self.isRed(p) for p in positions] def isRed(self, configOrPos): width = self.data.layout.width if type(configOrPos) == type((0, 0)): return configOrPos[0] < width / 2 else: return configOrPos.pos[0] < width / 2
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def getResult(self, agentIndex, action): """ Returns the state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a result of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer(state.data.agentStates[agentIndex]) # Resolve multi-agent effects GhostRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange p = state.getPacmanPosition() state.data.ghostDistances = [ getNoisyDistance(p, state.getGhostPosition(i)) for i in range(1, state.getNumAgents()) ] if agentIndex == self.getNumAgents() - 1: state.numMoves += 1 return state def getLegalPacmanActions(self): return self.getLegalActions(0) def getPacmanResult(self, action): """ Generates the result state after the specified pacman action """ return self.getResult(0, action) def getPacmanState(self): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return self.data.score def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] ############################## # Additions for Busters Pacman # ############################## def getLivingGhosts(self): """ Returns a list of booleans indicating which ghosts are not yet captured. The first entry (a placeholder for Pacman's index) is always False. """ return self.livingGhosts def setGhostNotLiving(self, index): self.livingGhosts[index] = False def isLose(self): return self.maxMoves > 0 and self.numMoves >= self.maxMoves def isWin(self): return self.livingGhosts.count(True) == 0 def getNoisyGhostDistances(self): """ Returns a noisy distance to each ghost. """ return self.data.ghostDistances ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: self.data = GameStateData(prevState.data) self.livingGhosts = prevState.livingGhosts[:] self.numMoves = prevState.numMoves self.maxMoves = prevState.maxMoves else: # Initial state self.data = GameStateData() self.numMoves = 0 self.maxMoves = -1 self.data.ghostDistances = [] def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() state.data.ghostDistances = self.data.ghostDistances return state def __eq__(self, other): """ Allows two states to be compared. """ if other is None: return False return self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(str(self)) def __str__(self): return str(self.data) def initialize(self, layout, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents) self.livingGhosts = [False] + [True for i in range(numGhostAgents)] self.data.ghostDistances = [ getNoisyDistance(self.getPacmanPosition(), self.getGhostPosition(i)) for i in range(1, self.getNumAgents()) ] def getGhostPosition(self, agentIndex): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex].getPosition() def getGhostState(self, agentIndex): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex]
def __init__(self, constraints=[], infeasiblePoints=[], feasiblePoints=[], optimalPoint=None, costVector=None, zoom=1.0, frameTime=0.0): """ Create and dispaly a pacman plot figure. This will draw on the existing pacman window (clearing it first) or create a new one if no window exists. constraints: list of inequality constraints, where each constraint w1*x + w2*y <= b is represented as a tuple ((w1, w2), b) infeasiblePoints (food): list of points where each point is a tuple (x, y) feasiblePoints (power): list of points where each point is a tuple (x, y) optimalPoint (pacman): optimal point as a tuple (x, y) costVector (shading): cost vector represented as a tuple (c1, c2), where cost is c1*x + c2*x """ super(PacmanPlotLP, self).__init__(zoom, frameTime) xmin = 100000 ymin = 100000 xmax = -100000 ymax = -100000 for point in feasiblePoints: if point[0] < xmin: xmin = point[0] if point[0] > xmax: xmax = point[0] if point[1] < ymin: ymin = point[1] if point[1] > ymax: ymax = point[1] if len(feasiblePoints) == 0: for point in infeasiblePoints: if point[0] < xmin: xmin = point[0] if point[0] > xmax: xmax = point[0] if point[1] < ymin: ymin = point[1] if point[1] > ymax: ymax = point[1] xmin = int(math.floor(xmin)) - 3 ymin = int(math.floor(ymin)) - 3 xmax = int(math.ceil(xmax)) + 3 ymax = int(math.ceil(ymax)) + 3 width = xmax - xmin + 1 height = ymax - ymin + 1 # p = feasiblePoints[2] # print("p={}".format(p)) # print("feasible={}".format(self.pointFeasible(p, constraints))) # g = self.cartesianToLayout(xmin, ymin, xmax, ymax, p) # print("g={}".format(g)) # gr = (int(round(g[0])), int(round(g[1]))) # p2 = self.layoutToCartesian(xmin, ymin, xmax, ymax, gr) # print("p2={}".format(p2)) # print("p2 feasible={}".format(self.pointFeasible(p2, constraints))) layoutLists = self.blankLayoutLists(width, height) self.addInfeasibleGhosts(layoutLists, constraints, xmin, ymin, xmax, ymax) layoutLists = self.changeBorderGhostsToWall(layoutLists) for point in infeasiblePoints: self.addCartesianPointToLayout(layoutLists, point, '.', xmin, ymin, xmax, ymax) for point in feasiblePoints: self.addCartesianPointToLayout(layoutLists, point, 'o', xmin, ymin, xmax, ymax) if optimalPoint is not None: self.addCartesianPointToLayout(layoutLists, optimalPoint, 'P', xmin, ymin, xmax, ymax) if graphicsUtils._canvas is not None: graphicsUtils.clear_screen() # Initialize GameStateData with blank board with axes self.width = width self.height = height self.zoom = min(30.0 / self.width, 20.0 / self.height) self.gridSize = graphicsDisplay.DEFAULT_GRID_SIZE * self.zoom maxNumGhosts = 10000 layout = Layout(layoutLists) self.blankGameState = GameStateData() self.blankGameState.initialize(layout, maxNumGhosts) self.initialize(self.blankGameState) title = 'Pacman Plot LP' graphicsUtils.changeText(self.infoPane.scoreText, title) graphicsUtils.refresh() if costVector is not None: self.shadeCost(layoutLists, constraints, costVector, feasiblePoints, xmin, ymin, xmax, ymax)
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### def updateState(self, actions): """ Returns the successor state after the actions of all active agents. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('it is terminal state now.') self.data.clear() for agentIndex in range(len(actions)): if self.data._eaten[agentIndex] > 0: BombermanRules.applyAction( self, actions[agentIndex], agentIndex ) self.minusOneFrame() for counter,position,power,index in self.data.bombs: if counter == self.getFramesUntilEnd(): self.bombExplode(self.data.bombs,position,power) if index >= 0: self.getAgentState(index).recoverABomb() self.data.bombs = [b for b in self.data.bombs if (b[0] != self.getFramesUntilEnd())] self.updateBombScore() self.updateMapScore() self.data.score = self.data._eaten[0] def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] return BombermanRules.getLegalActions( self , agentIndex) def generateSuccessor( self, agentIndex, action , force = False): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board #state.data._eaten = [False for i in range(state.getNumAgents())] if state.data._eaten[agentIndex] > 0: BombermanRules.applyAction( state, action, agentIndex ) if force or ( agentIndex == state.getNumAgents() - 1): state.minusOneFrame() for counter,position,power,index in state.data.bombs: if counter == state.getFramesUntilEnd(): state.bombExplode(state.data.bombs,position,power) state.getAgentState(index).recoverABomb() state.data.bombs = [b for b in state.data.bombs if (b[0] != state.getFramesUntilEnd())] state.updateBombScore() state.updateMapScore() # Time passes state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around # Resolve multi-agent effects #GhostRules.checkDeath( state, agentIndex ) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange return state def getAgentPosition( self, agentIndex ): return self.data.agentStates[agentIndex].getPosition() def getAgentState(self, agentIndex): return self.data.agentStates[agentIndex] def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return self.data.score def getMapScore(self,x,y=None): if y is None: try : x,y = x except: raise 'incomprehensible coordinates' return self.data.MapScore[x][y] def getBombScore(self,x,y=None): if y is None: try : x,y = x except: raise 'incomprehensible coordinates' return self.data.BombScore[x][y] def hasWall(self, x, y): return self.data.map.isWall((x,y)) def isLose( self ): return (self.getNumAgents() == 1 and self.data._eaten[0] == 0) or (self.data._eaten.count(0) == self.getNumAgents()) def isWin( self ): return ( self.getNumAgents()!=1 and self.data._eaten.count(0) is self.getNumAgents()-1 ) def getFramesUntilEnd(self ): return self.data.FramesUntilEnd def minusOneFrame( self ): self.data.FramesUntilEnd = self.data.FramesUntilEnd - 1 return self.data.FramesUntilEnd def layABomb(self,agentIndex,pos): self.data._bombLaid.append(pos) self.data.map.add_bomb(pos) self.getAgentState(agentIndex).minusABomb() self.data.bombs.append( (self.data.FramesUntilEnd - BOMB_DURATION , pos, self.getAgentState(agentIndex).getBombPower() , agentIndex ) ) def bombExplode(self,bombs, position, power): x_int, y_int = position if not self.data.map.isBomb(position): return self.data._bombExplode.append(position) self.data.map.remove_object(position) fired = [] for i in range(len(self.data._fire)): fired += self.data._fire[i] if not position in fired: self.checkDie(position) self.data._fire[0].append(position) fired.append(position) for vec in [ v for dir, v in Actions._directionsAsList if ( not dir in [ Actions.LAY ,Directions.STOP])]: isbreak = False i = 0 dx, dy = vec next_y, next_x = y_int,x_int while not isbreak and i < power: i=i+1 next_y = int(next_y + dy) next_x = int(next_x + dx) pos = (next_x,next_y) if pos in fired: continue if self.data.map.isEmpty(pos): self.checkDie(pos) self.data._fire[i].append(pos) fired.append(pos) elif self.data.map.isBlock(pos): isbreak = True self.data._blockBroken.append(pos) res = self.data.map.remove_object(pos) self.data._fire[i].append(pos) fired.append(pos) if res != None: self.data._itemDrop.append((next_x,next_y,res)) elif self.data.map.isWall(pos): isbreak = True elif self.data.map.isItem(pos): self.data._itemEaten.append(pos) self.data.map.remove_object(pos) self.data._fire[i].append(pos) fired.append(pos) self.checkDie(pos) elif self.data.map.isBomb(pos): self.checkDie(pos) self.data._fire[i].append(pos) fired.append(pos) bombSweep = [(idx,bomb) for idx,bomb in enumerate(bombs) if (pos in bomb ) and (bomb[0] < self.data.FramesUntilEnd-int(BOMB_DURATION/10)) ] if len(bombSweep) is 1: bombs[bombSweep[0][0]] = (self.data.FramesUntilEnd-int(BOMB_DURATION/10),)+bombSweep[0][1][1:] def checkDie(self,position): x,y = position for index,agent in enumerate(self.data.agentStates): if self.data._eaten[index] is 0 : continue sx,sy = agent.getPosition() sx,sy = round(sx),round(sy) if manhattanDistance(position,(sx,sy)) <= 0.5: self.data._eaten[index] -= 1 agent.configuration = agent.start def updateBombScore(self): # The change to the BombScore: self.data.BombScore.data = [[0 for y in range(self.data.map.height)] for x in range(self.data.map.width)] for counter, pos, power, index in self.data.bombs: score = self.calBombScore(counter) self.data.BombScore[pos[0]][pos[1]] += score isbreak = False for vec in [v for dir, v in Actions._directionsAsList if ( not dir in [ Actions.LAY ,Directions.STOP])]: isbreak = False i = 0 dx,dy = vec next_x,next_y = pos while not isbreak and i < power: i += 1 next_x = int(next_x+dx) next_y = int(next_y+dy) if self.data.map.isBlock((next_x,next_y)) or self.data.map.isWall((next_x,next_y)): isbreak = True else : self.data.BombScore[next_x][next_y] += score-i/5.0 def updateMapScore(self): self.data.MapScore.data = [[0 for y in range(self.data.map.height)] for x in range(self.data.map.width)] for x in range(self.data.map.width): for y in range(self.data.map.height): if not self.data.map.isBlocked((x,y)) or self.data.map.isBomb((x,y)): main = [self.data.map.isBlocked((row,col)) for row,col in [(x+1,y),(x-1,y),(x,y+1),(x,y-1)]] second = [self.data.map.isBlocked((row,col)) for row,col in [(x+1,y+1),(x-1,y+1),(x+1,y-1),(x-1,y-1)]] self.data.MapScore[x][y] = ( main.count(True)*1 + second.count(True)*0.4 ) if main.count(True) == 4: self.data.MapScore[x][y] = 100 if self.data.map.isBomb((x,y)): self.data.MapScore[x][y] += 1 def calBombScore(self, counter): if self.getFramesUntilEnd() - 1 == counter: # next frame would explode return 100 return 3*(BOMB_DURATION - (self.getFramesUntilEnd() - counter)) def getTotalLives(self, indexes): return sum([self.data._eaten[index] for index in indexes]) ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() return state def __eq__( self, other ): """ Allows two states to be compared. """ return self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return hash( self.data ) def __str__( self ): return str(self.data) def initialize( self, layout, numAgents=1000 , timeout = 3000, life = 5 ): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numAgents, timeout, life , BOMB_DURATION)
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ return AgentRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Returns the successor state (a GameState object) after the specified agent takes the action. """ # Copy current state state = GameState(self) # Find appropriate rules for the agent AgentRules.applyAction(state, action, agentIndex) AgentRules.checkDeath(state, agentIndex) AgentRules.decrementTimer(state.data.agentStates[agentIndex]) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange state.data.timeleft = self.data.timeleft - 1 return state def getAgentState(self, index): return self.data.agentStates[index] def getAgentPosition(self, index): """ Returns a location tuple if the agent with the given index is observable; if the agent is unobservable, returns None. """ agentState = self.data.agentStates[index] ret = agentState.getPosition() if ret: return tuple(int(x) for x in ret) return ret def getNumAgents(self): return len(self.data.agentStates) def getScore(self): """ Returns a number corresponding to the current score. """ return self.data.score def getRedFood(self): """ Returns a matrix of food that corresponds to the food on the red team's side. For the matrix m, m[x][y]=true if there is food in (x,y) that belongs to red (meaning red is protecting it, blue is trying to eat it). """ return halfGrid(self.data.food, red=True) def getBlueFood(self): """ Returns a matrix of food that corresponds to the food on the blue team's side. For the matrix m, m[x][y]=true if there is food in (x,y) that belongs to blue (meaning blue is protecting it, red is trying to eat it). """ return halfGrid(self.data.food, red=False) def getRedCapsules(self): return halfList(self.data.capsules, self.data.food, red=True) def getBlueCapsules(self): return halfList(self.data.capsules, self.data.food, red=False) def getWalls(self): """ Just like getFood but for walls """ return self.data.layout.walls def hasFood(self, x, y): """ Returns true if the location (x,y) has food, regardless of whether it's blue team food or red team food. """ return self.data.food[x][y] def hasWall(self, x, y): """ Returns true if (x,y) has a wall, false otherwise. """ return self.data.layout.walls[x][y] def isOver(self): return self.data._win def getRedTeamIndices(self): """ Returns a list of agent index numbers for the agents on the red team. """ return self.redTeam[:] def getBlueTeamIndices(self): """ Returns a list of the agent index numbers for the agents on the blue team. """ return self.blueTeam[:] def isOnRedTeam(self, agentIndex): """ Returns true if the agent with the given agentIndex is on the red team. """ return self.teams[agentIndex] def getAgentDistances(self): """ Returns a noisy distance to each agent. """ if 'agentDistances' in dir(self): return self.agentDistances else: return None def getDistanceProb(self, trueDistance, noisyDistance): "Returns the probability of a noisy distance given the true distance" if noisyDistance - trueDistance in SONAR_NOISE_VALUES: return 1.0 / SONAR_NOISE_RANGE else: return 0 def getInitialAgentPosition(self, agentIndex): "Returns the initial position of an agent." return self.data.layout.agentPositions[agentIndex][1] def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) self.blueTeam = prevState.blueTeam self.redTeam = prevState.redTeam self.data.timeleft = prevState.data.timeleft self.teams = prevState.teams self.agentDistances = prevState.agentDistances else: self.data = GameStateData() self.agentDistances = [] def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() state.data.timeleft = self.data.timeleft state.blueTeam = self.blueTeam[:] state.redTeam = self.redTeam[:] state.teams = self.teams[:] state.agentDistances = self.agentDistances[:] return state def makeObservation(self, index): state = self.deepCopy() # Adds the sonar signal pos = state.getAgentPosition(index) n = state.getNumAgents() distances = [ noisyDistance(pos, state.getAgentPosition(i)) for i in range(n) ] state.agentDistances = distances # Remove states of distant opponents if index in self.blueTeam: team = self.blueTeam otherTeam = self.redTeam else: otherTeam = self.blueTeam team = self.redTeam for enemy in otherTeam: seen = False enemyPos = state.getAgentPosition(enemy) for teammate in team: if util.manhattanDistance( enemyPos, state.getAgentPosition(teammate)) <= SIGHT_RANGE: seen = True if not seen: state.data.agentStates[enemy].configuration = None return state def __eq__(self, other): """ Allows two states to be compared. """ if other == None: return False return self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return int(hash(self.data)) def __str__(self): return str(self.data) def initialize(self, layout, numAgents): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numAgents) positions = [a.configuration for a in self.data.agentStates] self.blueTeam = [ i for i, p in enumerate(positions) if not self.isRed(p) ] self.redTeam = [i for i, p in enumerate(positions) if self.isRed(p)] self.teams = [self.isRed(p) for p in positions] # This is usually 60 (always 60 with random maps) # However, if layout map is specified otherwise, it could be less global TOTAL_FOOD TOTAL_FOOD = layout.totalFood def isRed(self, configOrPos): width = self.data.layout.width if type(configOrPos) == type((0, 0)): return configOrPos[0] < width / 2 else: return configOrPos.pos[0] < width / 2
def __init__(self, layout, agents, display_class, turn=AgentRole.Mr_X): self.gameState = GameState(GameStateData(layout, agents)) self.turn = turn # create a new <type>+Display object self.display = display_class(self.gameState.data) self.MOD = len(agents) # number of players
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### # static variable keeps track of which states have had getLegalActions called explored = set() def getAndResetExplored(): tmp = GameState.explored.copy() GameState.explored = set() return tmp getAndResetExplored = staticmethod(getAndResetExplored) def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ # GameState.explored.add(self) if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions( self ) else: return GhostRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving PacmanRules.applyAction( state, action ) else: # A ghost is moving GhostRules.applyAction( state, action, agentIndex ) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer( state.data.agentStates[agentIndex] ) # Resolve multi-agent effects GhostRules.checkDeath( state, agentIndex ) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange GameState.explored.add(self) GameState.explored.add(state) return state def getLegalPacmanActions( self ): return self.getLegalActions( 0 ) def generatePacmanSuccessor( self, action ): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor( 0, action ) def getPacmanState( self ): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition( self ): return self.data.agentStates[0].getPosition() def getGhostStates( self ): return self.data.agentStates[1:] def getGhostState( self, agentIndex ): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition( self, agentIndex ): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return float(self.data.score) def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood( self ): count = 0 for x in self.data.food: for e in x: if e: count += 1 return count def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is a wall at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose( self ): return self.data._lose def isWin( self ): return self.data._win ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() return state def __eq__( self, other ): """ Allows two states to be compared. """ return hasattr(other, 'data') and self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return hash( self.data ) def __str__( self ): return str(self.data) def initialize( self, layout, numGhostAgents=1000 ): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents)
class GameState:##this is called by initState = GameState() in ClassicGameRules.newGame """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### # static variable keeps track of which states have had getLegalActions called explored = set() #REFA01 def getAndResetExplored(): ##this function passes a copy of the explored GameState object to the tmp variable, resets the same object with an empty set. It then returns the tmp tmp = GameState.explored.copy() #[REFA01] This is a copy reference to the explored variable which contains an empty set. GameState.explored = set() #This re-equipps the explored variable with an empty set. return tmp getAndResetExplored = staticmethod(getAndResetExplored) """ So, as we can see from usage of staticmethod, we don't have any access to what the class is- it's basically just a function, called syntactically like a method, but without access to the object and it's internals (fields and another methods) """ def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ GameState.explored.add(self) if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions( self ) else: return GhostRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction( state, action ) else: # A ghost is moving GhostRules.applyAction( state, action, agentIndex ) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer( state.data.agentStates[agentIndex] ) # Resolve multi-agent effects GhostRules.checkDeath( state, agentIndex ) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange return state def getLegalPacmanActions( self ): return self.getLegalActions( 0 ) def generatePacmanSuccessor( self, action ): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor( 0, action ) def getPacmanState( self ): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition( self ): return self.data.agentStates[0].getPosition() def getGhostStates( self ): return self.data.agentStates[1:] def getGhostState( self, agentIndex ): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition( self, agentIndex ): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return self.data.score def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood( self ): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose( self ): return self.data._lose def isWin( self ): return self.data._win ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): ###PLEASE NOTE THIS THAT THE __init__ method is here and this is where GameState() starts """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) ##This statement imports the GameStateData object from the GameStateData class in game.py. This object contains a data packet documenting the state of the game. else: self.data = GameStateData() """ self._foodEaten = None self._capsuleEaten = None self._agentMoved = None self._lose = False self._win = False self.scoreChange = 0 """ def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() return state def __eq__( self, other ): """ Allows two states to be compared. """ return self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return hash( self.data ) def __str__( self ): return str(self.data) def initialize( self, layout, numGhostAgents=1000 ): """ Creates an initial game state from a layout array (see layout.py). This is based on: self.width = len(layoutText[0])## measures the width of the first element in the layoutText list, which was passed in by the 'tryToLoad' function by initiating the Layout object in the function call below. Open one of the layout files in the 'layouts' folder to understand how the layout works. self.height= len(layoutText) ## measures the hight of the layout by counting the length of the array [line1,line2,line3,line4] self.walls = Grid(self.width, self.height, False) ##self.walls contains an object that contains the Grid's width, height and a 2-dimenstional array called self.data that looks something like this:[[False, False, False,False],[False, False, False,False],...] self.food = Grid(self.width, self.height, False) ## same as the line before self.capsules = [] self.agentPositions = [] self.numGhosts = 0 self.processLayoutText(layoutText) ## This function takes the symbols contained in the layout files and turns them into coordinates which are then appended or assigned to the several variables that have been initialised in the code above. This happens according to the (x,y) convention used in the 2-dimensonal array that was defined in the Games class. self.layoutText = layoutText --> The initialize function then calls the self.data object's initialize function. "self.data" contains the GameStateData objec. GameStateData contains an initialize function itself which creates an initial game state from a layout array (see layout.py) (see above). self.food = layout.food.copy() self.capsules = layout.capsules[:] self.layout = layout self.score = 0 self.scoreChange = 0 self.agentStates = [] numGhosts = 0 for isPacman, pos in layout.agentPositions: if not isPacman: if numGhosts == numGhostAgents: continue # Max ghosts reached already else: numGhosts += 1 self.agentStates.append( AgentState( Configuration( pos, Directions.STOP), isPacman) ) self._eaten = [False for a in self.agentStates] """ self.data.initialize(layout, numGhostAgents) ##self.data is defined in the Grid() class of game.py REF112.It creates an initial game state from a layout array (see layout.py).
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### # static variable keeps track of which states have had getLegalActions called explored = set() def getAndResetExplored(): tmp = GameState.explored.copy() GameState.explored = set() return tmp getAndResetExplored = staticmethod(getAndResetExplored) def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ # GameState.explored.add(self) if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def generateSuccessor(self, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose() or self.eventQueue.isEmpty(): raise Exception('Can\'t generate a successor of a terminal state.') time, event = self.eventQueue.peek() assert event.isAgentMove( ), 'Can only generate successors of a state where an agent is about to move' state = self.makeAgentMove(action) state.resolveEventsUntilAgentEvent() # Book keeping GameState.explored.add(self.data) GameState.explored.add(state.data) return state def makeAgentMove(self, action): # Copy current state state = GameState(self) time, event = state.eventQueue.pop() agentIndex = event.getAgentIndex() agentState = state.data.agentStates[agentIndex] state.data.time = time delay = agentState.powers.timestepsBetweenMoves state.registerEventWithDelay(event, delay) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) state.data.scoreChange -= TIME_PENALTY # Penalty for waiting around else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) GhostRules.decrementTimer(agentState) # Resolve multi-agent effects GhostRules.checkDeath(state, agentIndex) if action == Directions.LASER: GhostRules.checkLaserShot(state, agentIndex) if action == Directions.BLAST: GhostRules.checkBlast(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex # Note: It is important that the following value accurately # reflects when Pacman will make the next move, even if the # speed changes (such as a speed-up power pellet). Otherwise # the graphics will do weird things. state.data._timeTillAgentMovesAgain = delay state.data._action = action state.data.score += state.data.scoreChange return state def runEvent(self): # Check that successors exist if self.eventQueue.isEmpty(): raise Exception('Can\'t run an event of a terminal state.') time, event = self.eventQueue.pop() assert not event.isAgentMove(), 'Can\'t run an AgentMoveEvent' self.data.time = time event.trigger(self) return event def getNextEvent(self): _, event = self.eventQueue.peek() return event def getLegalPacmanActions(self): return self.getLegalActions(0) def getPacmanState(self): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getPacmanDirection(self): return self.data.agentStates[0].getDirection() def getGhostStates(self): return self.data.agentStates[1:] def getGhostState(self, agentIndex): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise Exception("Invalid index passed to getGhostState") return self.data.agentStates[agentIndex] def getGhostPosition(self, agentIndex): if agentIndex == 0: raise Exception("Pacman's index passed to getGhostPosition") return self.data.agentStates[agentIndex].getPosition() def getGhostPositions(self): return [s.getPosition() for s in self.getGhostStates()] def getNextAgentIndex(self): for time, event in self.eventQueue.getSortedTimesAndEvents(): if event.isAgentMove(): return event.getAgentIndex() assert False, "No more moves can be made" def getAgentMoveTime(self, agentIndex): for time, event in self.eventQueue.getSortedTimesAndEvents(): if event.isAgentMove(): if event.getAgentIndex() == agentIndex: return time assert False, "No more moves can be made by agent " + str(agentIndex) def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return float(self.data.score) def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is a wall at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.walls[x][y] def isLose(self): return self.data._lose def isWin(self): return self.data._win ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) self.eventQueue = prevState.eventQueue.deepCopy() else: self.data = GameStateData() self.eventQueue = EventQueue() def resolveEventsUntilAgentEvent(self): # Resolve any events until the next agent event while not self.eventQueue.isEmpty(): time, event = self.eventQueue.peek() if event.isAgentMove(): return else: self.runEvent() def registerEventWithDelay(self, event, delay): self.eventQueue.registerEventAtTime(event, self.data.time + delay) def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() # Event queue has already been copied in the constructor return state def __eq__(self, other): """ Allows two states to be compared. """ return hasattr(other, 'data') and self.data == other.data \ and hasattr(other, 'eventQueue') and self.eventQueue == other.eventQueue \ def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash((self.data, self.eventQueue)) def __str__(self): return str(self.data) def initialize(self, layout, pacmanPowers, ghostPowers, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, pacmanPowers, ghostPowers, numGhostAgents) numAgents = self.getNumAgents() for i in range(numAgents): self.registerEventWithDelay(AgentMoveEvent(i), i) self.registerEventWithDelay(WallTimerEvent(), 1)
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. Note that in classic Pacman, Pacman is always agent 0. In SLAM inference, you will not have access to any GameState objects. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions( self ) else: return GhostRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction( state, action ) else: # A ghost is moving GhostRules.applyAction( state, action, agentIndex ) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer( state.data.agentStates[agentIndex] ) # Resolve multi-agent effects GhostRules.checkDeath( state, agentIndex ) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange p = state.getPacmanPosition() state.data.ghostDistances = [getNoisyDistance(p, state.getGhostPosition(i)) for i in range(1,state.getNumAgents())] if agentIndex == self.getNumAgents() - 1: state.numMoves += 1 return state def getLegalPacmanActions( self ): return self.getLegalActions( 0 ) def generatePacmanSuccessor( self, action ): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor( 0, action ) def getPacmanState( self ): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition( self ): return self.data.agentStates[0].getPosition() def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return self.data.score def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood( self ): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def getLegalPositions(self): """ Returns all positions that need to be considered for mapping (i.e., both walls and walkable positions) """ l = [p for p in self.getWalls().asList() + self.getWalls().asList(False)] return l def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose( self ): """ Not used by default for SLAM. """ return self.maxMoves > 0 and self.numMoves >= self.maxMoves def isWin( self ): """ Not used for SLAM. """ return False ############################## # Additions for Slam Pacman # ############################## def getNoisyRangeMeasurements(self): """ Return a noisy measurement in each of the four directions as a tuple (N, E, S, W). """ x, y = self.getPacmanPosition() currentX = x currentY = y while not self.hasWall(currentX, currentY): currentY += 1 N = getNoisyDistance((x,y), (currentX, currentY)) currentX = x currentY = y while not self.hasWall(currentX, currentY): currentX += 1 E = getNoisyDistance((x,y), (currentX, currentY)) currentX = x currentY = y while not self.hasWall(currentX, currentY): currentY -= 1 S = getNoisyDistance((x,y), (currentX, currentY)) currentX = x currentY = y while not self.hasWall(currentX, currentY): currentX -= 1 W = getNoisyDistance((x,y), (currentX, currentY)) return (N, E, S, W) ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: self.data = GameStateData(prevState.data) self.livingGhosts = prevState.livingGhosts[:] self.numMoves = prevState.numMoves; self.maxMoves = prevState.maxMoves; else: # Initial state self.data = GameStateData() self.numMoves = 0; self.maxMoves = -1; self.data.ghostDistances = [] def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() state.data.ghostDistances = self.data.ghostDistances return state def __eq__( self, other ): """ Allows two states to be compared. """ return self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return hash( str( self ) ) def __str__( self ): return str(self.data) def initialize( self, layout, numGhostAgents=1000 ): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents) self.livingGhosts = [False] + [True for i in range(numGhostAgents)] self.data.ghostDistances = [getNoisyDistance(self.getPacmanPosition(), self.getGhostPosition(i)) for i in range(1, self.getNumAgents())] def getGhostPosition( self, agentIndex ): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex].getPosition() def getGhostState( self, agentIndex ): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex]
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. We strongly suggest that you access that data via the accessor methods below rather than referring to the GameStateData object directly. Note that in classic Pacman, Pacman is always agent 0. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions( self, agentIndex=0 ): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions( self ) else: return GhostRules.getLegalActions( self, agentIndex ) def generateSuccessor( self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction( state, action ) else: # A ghost is moving GhostRules.applyAction( state, action, agentIndex ) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer( state.data.agentStates[agentIndex] ) # Resolve multi-agent effects GhostRules.checkDeath( state, agentIndex ) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange return state def getLegalPacmanActions( self ): return self.getLegalActions( 0 ) def generatePacmanSuccessor( self, action ): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor( 0, action ) def getPacmanState( self ): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition( self ): return self.data.agentStates[0].getPosition() def getGhostStates( self ): return self.data.agentStates[1:] def getGhostState( self, agentIndex ): if agentIndex == 0 or agentIndex >= self.getNumAgents(): raise "Invalid index passed to getGhostState" return self.data.agentStates[agentIndex] def getGhostPosition( self, agentIndex ): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex].getPosition() def getNumAgents( self ): return len( self.data.agentStates ) def getScore( self ): return self.data.score def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood( self ): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose( self ): return self.data._lose def isWin( self ): return self.data._win ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__( self, prevState = None ): """ Generates a new state by copying information from its predecessor. """ if prevState != None: # Initial state self.data = GameStateData(prevState.data) else: self.data = GameStateData() def deepCopy( self ): state = GameState( self ) state.data = self.data.deepCopy() return state def __eq__( self, other ): """ Allows two states to be compared. """ return self.data == other.data def __hash__( self ): """ Allows states to be keys of dictionaries. """ return hash( str( self ) ) def __str__( self ): return str(self.data) def initialize( self, layout, numGhostAgents=1000 ): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents)
class GameState: """ A GameState specifies the full game state, including the food, capsules, agent configurations and score changes. GameStates are used by the Game object to capture the actual state of the game and can be used by agents to reason about the game. Much of the information in a GameState is stored in a GameStateData object. Note that in classic Pacman, Pacman is always agent 0. In SLAM inference, you will not have access to any GameState objects. """ #################################################### # Accessor methods: use these to access state data # #################################################### def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ if self.isWin() or self.isLose(): return [] if agentIndex == 0: # Pacman is moving return PacmanRules.getLegalActions(self) else: return GhostRules.getLegalActions(self, agentIndex) def generateSuccessor(self, agentIndex, action): """ Returns the successor state after the specified agent takes the action. """ # Check that successors exist if self.isWin() or self.isLose(): raise Exception('Can\'t generate a successor of a terminal state.') # Copy current state state = GameState(self) # Let agent's logic deal with its action's effects on the board if agentIndex == 0: # Pacman is moving state.data._eaten = [False for i in range(state.getNumAgents())] PacmanRules.applyAction(state, action) else: # A ghost is moving GhostRules.applyAction(state, action, agentIndex) # Time passes if agentIndex == 0: state.data.scoreChange += -TIME_PENALTY # Penalty for waiting around else: GhostRules.decrementTimer(state.data.agentStates[agentIndex]) # Resolve multi-agent effects GhostRules.checkDeath(state, agentIndex) # Book keeping state.data._agentMoved = agentIndex state.data.score += state.data.scoreChange p = state.getPacmanPosition() state.data.ghostDistances = [ getNoisyDistance(p, state.getGhostPosition(i)) for i in range(1, state.getNumAgents()) ] if agentIndex == self.getNumAgents() - 1: state.numMoves += 1 return state def getLegalPacmanActions(self): return self.getLegalActions(0) def generatePacmanSuccessor(self, action): """ Generates the successor state after the specified pacman move """ return self.generateSuccessor(0, action) def getPacmanState(self): """ Returns an AgentState object for pacman (in game.py) state.pos gives the current position state.direction gives the travel vector """ return self.data.agentStates[0].copy() def getPacmanPosition(self): return self.data.agentStates[0].getPosition() def getNumAgents(self): return len(self.data.agentStates) def getScore(self): return self.data.score def getCapsules(self): """ Returns a list of positions (x,y) of the remaining capsules. """ return self.data.capsules def getNumFood(self): return self.data.food.count() def getFood(self): """ Returns a Grid of boolean food indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call currentFood = state.getFood() if currentFood[x][y] == True: ... """ return self.data.food def getWalls(self): """ Returns a Grid of boolean wall indicator variables. Grids can be accessed via list notation, so to check if there is food at (x,y), just call walls = state.getWalls() if walls[x][y] == True: ... """ return self.data.layout.walls def getLegalPositions(self): """ Returns all positions that need to be considered for mapping (i.e., both walls and walkable positions) """ l = [ p for p in self.getWalls().asList() + self.getWalls().asList(False) ] return l def hasFood(self, x, y): return self.data.food[x][y] def hasWall(self, x, y): return self.data.layout.walls[x][y] def isLose(self): """ Not used by default for SLAM. """ return self.maxMoves > 0 and self.numMoves >= self.maxMoves def isWin(self): """ Not used for SLAM. """ return False ############################## # Additions for Slam Pacman # ############################## def getNoisyRangeMeasurements(self): """ Return a noisy measurement in each of the four directions as a tuple (N, E, S, W). """ x, y = self.getPacmanPosition() currentX = x currentY = y while not self.hasWall(currentX, currentY): currentY += 1 N = getNoisyDistance((x, y), (currentX, currentY)) currentX = x currentY = y while not self.hasWall(currentX, currentY): currentX += 1 E = getNoisyDistance((x, y), (currentX, currentY)) currentX = x currentY = y while not self.hasWall(currentX, currentY): currentY -= 1 S = getNoisyDistance((x, y), (currentX, currentY)) currentX = x currentY = y while not self.hasWall(currentX, currentY): currentX -= 1 W = getNoisyDistance((x, y), (currentX, currentY)) return (N, E, S, W) ############################################# # Helper methods: # # You shouldn't need to call these directly # ############################################# def __init__(self, prevState=None): """ Generates a new state by copying information from its predecessor. """ if prevState != None: self.data = GameStateData(prevState.data) self.livingGhosts = prevState.livingGhosts[:] self.numMoves = prevState.numMoves self.maxMoves = prevState.maxMoves else: # Initial state self.data = GameStateData() self.numMoves = 0 self.maxMoves = -1 self.data.ghostDistances = [] def deepCopy(self): state = GameState(self) state.data = self.data.deepCopy() state.data.ghostDistances = self.data.ghostDistances return state def __eq__(self, other): """ Allows two states to be compared. """ return self.data == other.data def __hash__(self): """ Allows states to be keys of dictionaries. """ return hash(str(self)) def __str__(self): return str(self.data) def initialize(self, layout, numGhostAgents=1000): """ Creates an initial game state from a layout array (see layout.py). """ self.data.initialize(layout, numGhostAgents) self.livingGhosts = [False] + [True for i in range(numGhostAgents)] self.data.ghostDistances = [ getNoisyDistance(self.getPacmanPosition(), self.getGhostPosition(i)) for i in range(1, self.getNumAgents()) ] def getGhostPosition(self, agentIndex): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex].getPosition() def getGhostState(self, agentIndex): if agentIndex == 0: raise "Pacman's index passed to getGhostPosition" return self.data.agentStates[agentIndex]