From 57d731409f3e991886a9f14ce1d1cc379de78665 Mon Sep 17 00:00:00 2001 From: d3rped Date: Tue, 20 Mar 2018 22:31:15 +0100 Subject: [PATCH] Added first (still a tad ugly) draft of pathfinding. Added some small bits of documentation. Started working on unit tests (planettest.py). --- src/planet.py | 46 ++++++++++++++++++++++++++++++++++++++++++---- src/planettest.py | 26 ++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/src/planet.py b/src/planet.py index 5c1153a..f904bb7 100644 --- a/src/planet.py +++ b/src/planet.py @@ -25,12 +25,24 @@ Weight = int ''' https://www.python.org/dev/peps/pep-0289/ -Node checking: +Node checking examples: ((0,0),Direction.NORTH) in planetmap[0] Simplify this for node search: next(x for (x, y), direction in planetmap[0]) next(y for x, y in planetmap[0] if x == (0, 0)) planetmap[0][next((x, y) for x, y in planetmap[0] if y == 'North')] + +formatting example of bidirectional map: +{ +(0, 0): { + : ((0, 0), , 1), + : ((0, 0), , 1), + : ((0, 1), , 2) + }, +(0, 1): { + : ((0, 0), , 2) + } +} ''' #Contains the representation of the map and provides certain functions to manipulate it according to the specifications @@ -40,7 +52,7 @@ class Planet: self._planetmap = {} self.target = None - #Adds a bidirectional path defined between the start and end coordinates to the map and assigns the weight to it. + # Adds a bidirectional path defined between the start and end coordinates to the map and assigns the weight to it. def add_path(self, start: Tuple[Tuple[int, int], Direction], target: Tuple[Tuple[int, int], Direction], weight: int): if(start[0] not in self._planetmap): self._planetmap[start[0]] = {} @@ -54,6 +66,32 @@ class Planet: def get_paths(self) -> Dict[Tuple[int, int], Dict[Direction, Tuple[Tuple[int, int], Direction, Weight]]]: return self._planetmap - #Returns a shortest path between two nodes + ''' + Returns a shortest path between two nodes. + Used Algorithm: Dijkstra's Algorithm, will be "replaced" by A* later + Formatting: + List = [(total_len, (current_node, [((node), Direction)]))] + ''' def shortest_path(self, start: Tuple[int, int], target: Tuple[int, int]) -> Optional[List[Tuple[Tuple[int, int], Direction]]]: - pass + if((start in self._planetmap) and (target in self._planetmap)): + self.path_found = [] + self.path_search = [(0, (start, []))] + while True: + for srcdir, (destnode, destdir, weight) in self._planetmap[self.path_search[0][1][0]].items(): + if(destnode not in self.path_found and weight > 0): # check if in shortest_found + for x, (s_node, s_pathlist) in self.path_search: + if (destnode == s_node and self.path_search[0][0] + weight < x): + self.path_search.remove((x, (s_node, s_pathlist))) + if(s_weight for s_weight, (s_node, s_pathlist) in self.path_search if s_node == destnode): + self.path_search.append((self.path_search[0][0]+weight, (destnode, self.path_search[0][1][1] + [(self.path_search[0][1][0], srcdir)]))) + self.path_found.append(self.path_search[0][1][0]) + self.path_search.pop(0) + if(self.path_search == []): # if map is empty + break + self.path_search.sort() + if(self.path_search[0][1][0] == target): + return self.path_search[0][1][1] + else: + print("Destination is not reachable from start.") + else: + print("Cannot calculate shortest Path. Start or target is not in known.") diff --git a/src/planettest.py b/src/planettest.py index 4582188..5341f44 100755 --- a/src/planettest.py +++ b/src/planettest.py @@ -45,17 +45,39 @@ class YourFirstTestPlanet(unittest.TestCase): MODEL YOUR TEST PLANET HERE (if you'd like): + (_target) + +-0,3-----2,3 +---+ + | | | | | + | 0,2-----2,2-3,2 | + | | / | | + | 0,1 / +---+ + | | / + +-0,0-1,0-----3.0-4.0 + | + (start) + """ # set your data structure self.planet = Planet() # ADD YOUR PATHS HERE: - # self.planet.add_path(...) + self.planet.add_path(((0, 0), Direction.NORTH), ((0, 1), Direction.SOUTH), 1) + self.planet.add_path(((0, 0), Direction.EAST), ((1, 0), Direction.WEST), 1) + self.planet.add_path(((0, 0), Direction.WEST), ((0, 3), Direction.WEST), 2) + self.planet.add_path(((0, 1), Direction.NORTH), ((0, 2), Direction.SOUTH), 1) + self.planet.add_path(((0, 2), Direction.NORTH), ((0, 3), Direction.SOUTH), 1) + self.planet.add_path(((0, 2), Direction.EAST), ((2, 2), Direction.WEST), 2) + self.planet.add_path(((0, 3), Direction.EAST), ((2, 3), Direction.WEST), -1) + self.planet.add_path(((1, 0), Direction.NORTH), ((2, 2), Direction.SOUTH), 2) + self.planet.add_path(((1, 0), Direction.EAST), ((3, 0), Direction.WEST), 1) + self.planet.add_path(((2, 2), Direction.NORTH), ((2, 3), Direction.SOUTH), 3) + self.planet.add_path(((3, 0), Direction.EAST), ((4, 0), Direction.WEST), -1) + self.planet.add_path(((3, 2), Direction.NORTH), ((3, 2), Direction.SOUTH), 1) def test_integrity(self): # were all paths added correctly to the planet # check if add_path() works by using get_paths() - self.fail('implement me!') + self.planet.get_paths() def test_empty_planet(self): self.fail('implement me!')