def expand(self): agent = self.moves.index(None) position = self.positions[agent] new_nodes = [] for neighbour in self.grid.valid_neighbours(position): # Check if cell is occupied by moved agent if neighbour in self.moves: continue # Check for crossing edges move_edge = Edge(position, neighbour) if any(move_edge.conflicts(edge) for edge in self.taken_edges): continue # Check for illegal moves, if given if self.grid.is_move_illegal(self.cost, position, neighbour): continue # Check for new conflicts with other groups new_conflicts = self.conflicts if self.grid.is_move_conflicting(self.cost, position, neighbour): new_conflicts += 1 new_moves = self.moves[:] new_moves[agent] = neighbour new_taken_edges = self.taken_edges[:] new_taken_edges.append(move_edge) # Check if this means a new waypoint is now visited for this agent new_visited_waypoints = self.visited_waypoints if self.grid.on_visitable_waypoint(agent, neighbour, self.visited_waypoints[agent]): new_visited_waypoints = [ ws.copy() for ws in new_visited_waypoints ] new_visited_waypoints[agent].add(neighbour) # Agents can wait at goal for no cost, unless they will move again # in the future, so we need to keep track of this 'credit' additional_cost = 1 new_goal_waits = self.goal_waits if self.agent_done(agent): additional_cost = 0 new_goal_waits = self.goal_waits[:] new_goal_waits[agent] += 1 elif self.goal_waits[agent]: additional_cost = self.goal_waits[agent] + 1 new_goal_waits = self.goal_waits[:] new_goal_waits[agent] = 0 # Calculate the new heuristic by looking at the difference for # only this agent h_before = self.grid.heuristic(agent, position, self.visited_waypoints[agent]) h_after = self.grid.heuristic(agent, neighbour, new_visited_waypoints[agent]) h_difference = h_after - h_before new_heuristic = self.heuristic + h_difference new_node = Node(self.grid, self.positions, new_moves, self.cost + additional_cost, new_goal_waits, new_conflicts, new_taken_edges, self, new_visited_waypoints, new_heuristic) new_nodes.append(new_node) return new_nodes