def go_to_xy(self, x, y): d = int_distance(self.x, self.y, x, y) if d > self.radius: self.o = int_angle(self.x, self.y, x, y) # turn toward the goal self._reach(d) else: return True
def go_to_xy(self, x, y): d = int_distance(self.x, self.y, x, y) if d > self.radius: # execute action self.o = int_angle(self.x, self.y, x, y) # turn towards the goal self._reach(d) else: return True
def action_reach_and_use(self): target = self.action_target if not self._near_enough_to_use(target): d = int_distance(self.x, self.y, target.x, target.y) self.o = int_angle(self.x, self.y, target.x, target.y) # turn toward the goal self._reach(d - target.collision_range(self)) else: self.walked = [] target.be_used_by(self)
def _shortest_path_to(self, dest, player): """Returns the next exit to the shortest path from self to dest and the distance of the shortest path from self to dest.""" # TODO: remove the duplicate exits in the graph if dest is self: return None, 0 ## if not dest.exits: # small optimization ## return None, None # no path exists # add start and end to the graph G = self.world.g for v in (self, dest): G[v] = {} for e in v.exits: G[v][e] = G[e][v] = int_distance(v.x, v.y, e.x, e.y) start = self end = dest # apply Dijkstra's algorithm (with priority list) D = {} # dictionary of final distances P = {} # dictionary of predecessors Q = priorityDictionary() # est.dist. of non-final vert. Q[start] = (0, ) for v in Q: if hasattr(v, "is_blocked") and v.is_blocked(player, ignore_enemy_walls=True): continue D[v] = Q[v][0] if v == end: break for w in G[v]: if hasattr(w, "is_blocked") and w.is_blocked(player, ignore_enemy_walls=True): continue vwLength = D[v] + G[v][w] if w in D: pass elif w not in Q or vwLength < Q[w][0]: Q[w] = (vwLength, int(w.id),) # the additional value makes the result "cross-machine deterministic" P[w] = v # restore the graph for v in (start, end): del G[v] for e in v.exits: del G[e][v] # exploit the results if end not in P: return None, None # no path exists Path = [] while 1: Path.append(end) if end == start: break end = P[end] Path.reverse() return Path[1], D[dest]
def _ground_graph(self): g = {} for z in self.squares: for e in z.exits: g[e] = {} for f in z.exits: if f is not e: g[e][f] = int_distance(e.x, e.y, f.x, f.y) g[e][e.other_side] = 0 return g
def action_reach_and_stop(self): target = self.action_target if not self._near_enough(target): d = int_distance(self.x, self.y, target.x, target.y) self.o = int_angle(self.x, self.y, target.x, target.y) # turn toward the goal self._reach(d - self._collision_range(target)) else: self.walked = [] self.target = None
def _create_passages(self): for t, squares in self.west_east: for i in squares: passage(self._we_places(i), t) for t, squares in self.south_north: for i in squares: passage(self._sn_places(i), t) self.g = {} for z in self.squares: for e in z.exits: self.g[e] = {} for f in z.exits: if f is not e: self.g[e][f] = int_distance(e.x, e.y, f.x, f.y) self.g[e][e.other_side] = 0
def _water_graph(self): g = {} for z in self.squares: g[z] = {} if not z.is_water: continue # This is not perfect. Some diagonals will be missing. if [z2 for z2 in z.strict_neighbors if not z2.is_water]: n = z.strict_neighbors else: n = z.neighbors for z2 in n: if not z2.is_water: continue g[z][z2] = int_distance(z.x, z.y, z2.x, z2.y) return g
def _d(o): # o.id to make sure that the result is the same on any computer return (int_distance(o.x, o.y, unit.x, unit.y), o.id)
def _shortest_path_to(self, dest, plane, player, places=False, avoid=False): """Returns the next exit to the shortest path from self to dest and the distance of the shortest path from self to dest.""" # TODO: remove the duplicate exits in the graph if avoid: avoid = player.is_very_dangerous else: avoid = lambda x: False if dest is self: return [self] if places else (None, 0) ## if not dest.exits: # small optimization ## return None, None # no path exists # add start and end to the graph G = self.world.g[plane] if plane == "ground": for v in (self, dest): G[v] = {} for e in v.exits: G[v][e] = G[e][v] = int_distance(v.x, v.y, e.x, e.y) start = self end = dest # apply Dijkstra's algorithm (with priority list) D = {} # dictionary of final distances P = {} # dictionary of predecessors Q = priorityDictionary() # est.dist. of non-final vert. Q[start] = (0, ) for v in Q: if hasattr(v, "is_blocked") and v.is_blocked(player, ignore_enemy_walls=True) or avoid(v): continue D[v] = Q[v][0] if v == end: break for w in G[v]: if hasattr(w, "is_blocked") and w.is_blocked(player, ignore_enemy_walls=True) or avoid(w): continue vwLength = D[v] + G[v][w] if w in D: pass elif w not in Q or vwLength < Q[w][0]: Q[w] = (vwLength, int(w.id),) # the additional value makes the result "cross-machine deterministic" P[w] = v # restore the graph if plane == "ground": for v in (start, end): del G[v] for e in v.exits: del G[e][v] # exploit the results if end not in P: # no path exists return [] if places else (None, None) Path = [] while 1: Path.append(end) if end == start: break end = P[end] Path.reverse() if places: return [e.place for e in Path if hasattr(e, "other_side")] else: return Path[1], D[dest]