def test_find_isolated_vertices(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, c], e: [c], f: []} graph = Graph(g) assert graph.find_isolated_vertices() == [f]
def test_astar_no_valid_path(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, b, c], e: [c], f: []} graph = Graph(g) path = graph.astar(a, f) assert path.path is None
def __init__( self, grid: AGrid, connect_adjacents: bool = True, connect_diagonals: bool = True, ): self._diagonal_connections = {} self._connect_adjacents = connect_adjacents self._connect_diagonals = connect_diagonals self.grid = grid self.pos_node_map = self._build_position_node_map( ncols=self.grid.nColumns, nrows=self.grid.nRows) graph_dict = self.graph_dict_provider(self.pos_node_map) self.graph = Graph(graph_dict=graph_dict)
def test_nodes_at__single(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, c], e: [c], f: []} graph = Graph(g) nodes = graph.nodes_at_point(Vector2(0, 0)) assert nodes == [a]
def test_closest_node__base(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, b, c], e: [c], f: []} graph = Graph(g) test = Vector2(0, 1) closest = graph.closest_nodes(test)[0] assert closest == a f"{closest}"
def test__path_length(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, c], e: [c, f], f: []} graph = Graph(g) path = [a, d, c, e] length = graph.path_length(path) assert length == d.pos.distance_from(a.pos) + c.pos.distance_from( d.pos) + e.pos.distance_from(c.pos)
def test_add_node_with_connnections__base(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, b, c], e: [c], f: []} graph = Graph(g) h = Node('H', Vector2(100, 100)) graph.add_node_with_connnections(h, { a: EdgeDirection.FROM, b: EdgeDirection.TO, c: EdgeDirection.TWOWAY }) assert h in graph.nodes assert graph.edge_between(a, h) is not None assert graph.edge_between(h, a) is None assert graph.edge_between(b, h) is None assert graph.edge_between(h, b) is not None assert graph.edge_between(c, h) is not None assert graph.edge_between(h, c) is not None
def test_copy__base(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, b, c], e: [c], f: []} graph = Graph(g) copy = graph.copy() assert len(copy.nodes) == len(graph.nodes) assert len(copy.edges) == len(graph.edges) assert (edge.disablers() == graph.edge_between(edge.start, edge.end).disablers() for edge in copy.edges)
def test_add_node(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, c], e: [c, f], f: []} graph = Graph(g) assert len(graph.nodes) == 6 assert graph.nodes == [a, b, c, d, e, f] h = Node(name='H', pos=Vector2(6, 5)) graph.add_node(h) assert len(graph.nodes) == 7 assert graph.nodes == [a, b, c, d, e, f, h]
def init_a_test_graph(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, c], e: [c, f], f: []} return Graph(g)
def test__edge_by_id(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, b, c], e: [c], f: []} graph = Graph(g) edge = graph.edge_between(a, d) self.assertIsNotNone(edge, "Edge was returned none when expected value") edge_ret = graph.edges_by_id([edge.id])[0] self.assertEqual( edge, edge_ret, f"returned edge {edge_ret} [{edge_ret.id}] does not match {edge} [{edge.id}]" )
def test_disable_edges(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, b, c], e: [c, f], f: []} graph = Graph(g) graph.disable_edges(graph.edge_between(d, c), "BLOCK") assert graph.edge_between(d, c).disablers() == {"BLOCK"}
def test__astar_with_disablers(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, b, c], e: [c, f], f: []} graph = Graph(g) graph.disable_edges(graph.edge_between(d, c), "BLOCK") path = graph.astar(a, e) assert path.path == [a, d, b, c, e]
def test_edges_to_node(self): a = Node(name='A', pos=Vector2(0, 0)) b = Node(name='B', pos=Vector2(3, 3)) c = Node(name='C', pos=Vector2(2, 0)) d = Node(name='D', pos=Vector2(2, 1)) e = Node(name='E', pos=Vector2(3, 4)) f = Node(name='F', pos=Vector2(5, 5)) g = {a: [d], b: [c], c: [b, d, e], d: [a, c], e: [c, f], f: []} graph = Graph(g) assert set(graph.edges_to_node(c)) == { graph.edge_between(b, c), graph.edge_between(d, c), graph.edge_between(e, c), graph.edge_between(c, b), graph.edge_between(c, d), graph.edge_between(c, e) }
class GridGraph: def __init__( self, grid: AGrid, connect_adjacents: bool = True, connect_diagonals: bool = True, ): self._diagonal_connections = {} self._connect_adjacents = connect_adjacents self._connect_diagonals = connect_diagonals self.grid = grid self.pos_node_map = self._build_position_node_map( ncols=self.grid.nColumns, nrows=self.grid.nRows) graph_dict = self.graph_dict_provider(self.pos_node_map) self.graph = Graph(graph_dict=graph_dict) def _build_position_node_map(self, ncols: int, nrows: int): pos_node_map = {} for col in range(0, ncols): for row in range(0, nrows): pos = Vector2(row, col) pos_node_map[pos] = Node(str(pos), pos) return pos_node_map def graph_dict_provider( self, pos_node_map: Dict[IVector, Node]) -> Dict[Node, List[Node]]: return self.build_graph_dict(pos_node_map, connect_adjacents=self._connect_adjacents, connect_diagonals=self._connect_diagonals) def build_graph_dict( self, pos_node_map: Dict[IVector, Node], connect_adjacents: bool = True, connect_diagonals: bool = True) -> Dict[Node, List[Node]]: graph_dict = {} for pos in pos_node_map.keys(): graph_dict[pos_node_map[pos]] = [] adjacents = [ Vector2(pos.x - 1, pos.y) if pos_node_map.get( Vector2(pos.x - 1, pos.y), None) else None, # left Vector2(pos.x + 1, pos.y) if pos_node_map.get( Vector2(pos.x + 1, pos.y), None) else None, # right Vector2(pos.x, pos.y - 1) if pos_node_map.get( Vector2(pos.x, pos.y - 1), None) else None, # up Vector2(pos.x, pos.y + 1) if pos_node_map.get( Vector2(pos.x, pos.y + 1), None) else None, # down ] diagonals = [ Vector2(pos.x - 1, pos.y - 1) if pos_node_map.get(Vector2(pos.x - 1, pos.y - 1), None) else None, # UpLeft Vector2(pos.x + 1, pos.y - 1) if pos_node_map.get(Vector2(pos.x + 1, pos.y - 1), None) else None, # UpRight Vector2(pos.x - 1, pos.y + 1) if pos_node_map.get(Vector2(pos.x - 1, pos.y + 1), None) else None, # DownLeft Vector2(pos.x + 1, pos.y + 1) if pos_node_map.get(Vector2(pos.x + 1, pos.y + 1), None) else None # DownRight ] connections = [] # add adjacents to connections list if connect_adjacents: connections += adjacents # add diagonals to connections list if connect_diagonals: connections += diagonals # add diagonal connections to a saved dict for quick id later for connection in diagonals: if connection: self._diagonal_connections.setdefault( pos, []).append(connection) # add connections to the graph_dict for each node for connection_pos in connections: try: if connection_pos: graph_dict[pos_node_map[pos]].append( pos_node_map[connection_pos]) except: print(f"{connection_pos} \n" f"{pos_node_map}") print(f"connection pos: {type(connection_pos)}") print( f"first pos_node_map pos: {type([x for x in pos_node_map.keys()][0])}" ) raise return graph_dict def toggle_allow_diagonal_connections(self, disabler): self._allow_diagonal_connections = not self._allow_diagonal_connections print( f"{len(self._diagonal_connections)}\n {self._diagonal_connections}" ) import time print("start") tic = time.perf_counter() if self._allow_diagonal_connections: print("enable") self.graph.enable_edges(self._diagonal_connections, disabler) else: print("disable") self.graph.disable_edges(self._diagonal_connections, disabler) toc = time.perf_counter() print(f"Toggled the diagonal connections in {toc - tic:0.4f} seconds") def astar_between_grid_pos(self, start: Vector2, end: Vector2) -> AStarResults: start = self.graph.nodes_at_point(start)[0] end = self.graph.nodes_at_point(end)[0] results = self.graph.astar(start, end) return results