import random, math import core.model from core.model import DIRECTION_UP, DIRECTION_DOWN, DIRECTION_LEFT, DIRECTION_RIGHT from core.event import TickEvent, AgentMovedEvent, QuitEvent from core.event import SimulationStartedEvent from core.utils import GreedyPath, AStar, Dijkstra from utils import PacmanLevel class Pacman(core.model.Agent): def __init__(self, disp, env): core.model.Agent.__init__(self, disp) self.ghosts = [] self.next_update = 0 self.path = [] self.env = env # Benchmark # self.fic = open("pacstats", "w") # self.ite = 0 def __repr__(self): return "Pacman@(Sector = %s)" % self.sector def move(self): def try_move(to): if to.occupant != None: if isinstance(to.occupant, Ghost): print "Suicide : DEAD" self.disp.post(QuitEvent()) return # Let's move self.sector.occupant = None self.sector = to self.sector.occupant = self self.disp.post(AgentMovedEvent(self)) d = Dijkstra(Wall) # Generate ghost map ghostmap = {} for g in self.ghosts: ghostmap = d.eval(g.sector, ghostmap) # Generate pacman map pacmap = d.eval(self.sector, {}) diffmap = ghostmap.copy() for k in diffmap: diffmap[k] = ghostmap[k] - pacmap[k] # Benchmark #self.ite += 1 #self.fic.write("%d %d %d %d %d\n"%(self.ite, diffmap[self.sector], pacmap[self.ghosts[0].sector], pacmap[self.ghosts[1].sector], pacmap[self.ghosts[2].sector])) def heur(a, b): if a == None or b == None: return 0 else: return math.fabs(a.pos[0]-b.pos[0]) + math.fabs(a.pos[1]-b.pos[1]) a = AStar(heur) def dump_map(map): for i in range(30): for j in range(28): if self.env.sectors[i][j] in map: print "%3d"%map[self.env.sectors[i][j]], else: print "###", print def maxlocal(): # meilleure position locale dans la grille x = 0 y = 0 best = None for k in ghostmap.keys(): if diffmap[k] > 0 and best == None: best = k if best == None: continue if ghostmap[k] > ghostmap[best] and diffmap[k] > 0: best = k if best == None: return None else: print "Found max local", diffmap[best] return best best = maxlocal() # A star self.path = a.find_path(self.sector, best) if self.path == None: print "No path found !!" self.disp.post(AgentMovedEvent(self)) return if len(self.path) == 0: print "Already at best position..." self.disp.post(AgentMovedEvent(self)) return # print "Shortest distance to :", ghostmap[self.sector] # print "Ghost 0 is at : ", pacmap[self.ghosts[0].sector] # print "Ghost 1 is at : ", pacmap[self.ghosts[1].sector] # print "Safety of destination : ", ghostmap[self.path[-1]] # print "Path length : ", len(self.path) print "Pacmap :" dump_map(pacmap) print "Ghostmap :" dump_map(ghostmap) print "Diffmap :" dump_map(diffmap) # Let's move to = self.path[0] self.path.remove(self.path[0]) try_move(to) def notify(self, e): if isinstance(e, TickEvent): self.move() elif isinstance(e, SimulationStartedEvent): self.ghosts = e.sim.ghosts class Ghost(core.model.Agent): (ATTACK, REST) = range(2) def __init__(self, disp): core.model.Agent.__init__(self, disp) self.last_pacman_sector = None self.last_dir = None self.last_path = None self.mode = Ghost.ATTACK self.mode_count = 20 self.count = 0 def move(self): # Prevent crash if self.last_pacman_sector == None or self.sector == None: return # Switch mode if self.mode_count == 0: if self.mode == Ghost.ATTACK: self.mode = Ghost.REST self.mode_count = 5 else: self.mode = Ghost.ATTACK self.mode_count = 10 self.mode_count -= 1 if self.mode == Ghost.ATTACK: self.attack() else: self.rest() def rest(self): self.last_path = None self.last_dir = None choices = [DIRECTION_UP, DIRECTION_RIGHT, DIRECTION_DOWN, DIRECTION_LEFT] while len(choices) != 0: d = random.choice(choices) if self.sector.move_possible(d): self.sector.occupant = None self.sector = self.sector.neighbors[d] self.sector.occupant = self self.disp.post(AgentMovedEvent(self)) return choices.remove(d) def attack(self): if self.count == 0 or self.last_path == None or len(self.last_path) == 0: print "Generating path..." def dst(a, b): return math.fabs(a.pos[0]-b.pos[0]) + math.fabs(a.pos[1]-b.pos[1]) gp = GreedyPath(dst) self.last_path = gp.find_path(self.sector, self.last_pacman_sector, Pacman) self.count = 10 self.count -= 1 if self.last_path == None or len(self.last_path) == 0: return next = self.last_path[0] self.last_path.remove(next) self.sector.occupant = None self.sector = next self.sector.occupant = self self.disp.post(AgentMovedEvent(self)) def notify(self, e): if isinstance(e, TickEvent): self.move() elif isinstance(e, AgentMovedEvent): if isinstance(e.agent, Pacman): self.last_pacman_sector = e.agent.sector class Wall(core.model.Agent): def __init__(self, disp): self.disp = disp self.sector = None class PacmanSimulation(core.model.Simulation): def __init__(self, disp, lev_path): self.level = PacmanLevel(disp, lev_path) # A pacman level is alway 28x30 env = core.model.ToricEnvironment(disp, 28, 30) core.model.Simulation.__init__(self, disp, env) def start(self): self.env.build(do_diags=False) self.pacman, self.ghosts = self.level.load(self.env) self.disp.post(SimulationStartedEvent(self)) self.state = PacmanSimulation.RUNNING def notify(self, e): core.model.Simulation.notify(self, e) if isinstance(e, SimulationStartedEvent): print "Go!"