Added first (still a tad ugly) draft of pathfinding. Added some small bits of documentation. Started working on unit tests (planettest.py).

This commit is contained in:
d3rped 2018-03-20 22:31:15 +01:00
parent 631d70aacc
commit 57d731409f
2 changed files with 66 additions and 6 deletions

View file

@ -25,12 +25,24 @@ Weight = int
''' '''
https://www.python.org/dev/peps/pep-0289/ https://www.python.org/dev/peps/pep-0289/
Node checking: Node checking examples:
((0,0),Direction.NORTH) in planetmap[0] ((0,0),Direction.NORTH) in planetmap[0]
Simplify this for node search: Simplify this for node search:
next(x for (x, y), direction in planetmap[0]) next(x for (x, y), direction in planetmap[0])
next(y for x, y in planetmap[0] if x == (0, 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')] planetmap[0][next((x, y) for x, y in planetmap[0] if y == 'North')]
formatting example of bidirectional map:
{
(0, 0): {
<Direction.EAST: 90>: ((0, 0), <Direction.WEST: 270>, 1),
<Direction.WEST: 270>: ((0, 0), <Direction.EAST: 90>, 1),
<Direction.NORTH: 0>: ((0, 1), <Direction.SOUTH: 180>, 2)
},
(0, 1): {
<Direction.SOUTH: 180>: ((0, 0), <Direction.NORTH: 0>, 2)
}
}
''' '''
#Contains the representation of the map and provides certain functions to manipulate it according to the specifications #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._planetmap = {}
self.target = None 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): 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): if(start[0] not in self._planetmap):
self._planetmap[start[0]] = {} 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]]]: def get_paths(self) -> Dict[Tuple[int, int], Dict[Direction, Tuple[Tuple[int, int], Direction, Weight]]]:
return self._planetmap 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]]]: 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.")

View file

@ -45,17 +45,39 @@ class YourFirstTestPlanet(unittest.TestCase):
MODEL YOUR TEST PLANET HERE (if you'd like): 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 # set your data structure
self.planet = Planet() self.planet = Planet()
# ADD YOUR PATHS HERE: # 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): def test_integrity(self):
# were all paths added correctly to the planet # were all paths added correctly to the planet
# check if add_path() works by using get_paths() # check if add_path() works by using get_paths()
self.fail('implement me!') self.planet.get_paths()
def test_empty_planet(self): def test_empty_planet(self):
self.fail('implement me!') self.fail('implement me!')