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 # #################################################### 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. 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. """ #################################################### # 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
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 # 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 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. 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 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 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, 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: """ 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. 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: """ 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 # #################################################### # 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 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): 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 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 = GameStateData(prevState.data) 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.livingGhosts = [False] + [True for i in range(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()) ] 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: def getLegalActions(self, agentIndex=0): """ Returns the legal actions for the agent specified. """ 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 += -TIME_PENALTY 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 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): 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: 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 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: """ 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 ############################################# # 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 # #################################################### 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. 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. 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:##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).