Advertisement
Guest User

Untitled

a guest
Aug 21st, 2019
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.79 KB | None | 0 0
  1. def __init__(self):
  2. """ Initializes the data structure """
  3. self.target = None
  4. self.start = None
  5. self.end = None
  6. self.arriving_direction = Direction.NORTH
  7. # edges are tuples like (start, end, weight); start and end are tuples of the coordinates and the direction
  8. self.edges = set() # if changed, adapt add_path for blocked paths
  9.  
  10. def add_path(self, start: Tuple[Tuple[int, int], Direction], target: Tuple[Tuple[int, int], Direction],
  11. weight: int):
  12. """
  13. Adds a bidirectional path defined between the start and end coordinates to the map and assigns the weight to it
  14.  
  15. Example:
  16. add_path(((0, 3), Direction.NORTH), ((0, 3), Direction.WEST), 1)
  17. :param start: 2-Tuple
  18. :param target: 2-Tuple
  19. :param weight: Integer
  20. :return: void
  21. """
  22.  
  23. # OWN CODE HEREAFTER
  24. self.edges.add((start, target, weight))
  25. self.edges.add((target, start, weight)) # bidirectional graph
  26. # if edges gets changed to not being a set, blocked paths should not get inserted twice!
  27.  
  28. def get_paths(self) -> Dict[Tuple[int, int], Dict[Direction, Tuple[Tuple[int, int], Direction, Weight]]]:
  29. """
  30. Returns all paths
  31.  
  32. Example:
  33. {
  34. (0, 3): {
  35. Direction.NORTH: ((0, 3), Direction.WEST, 1),
  36. Direction.EAST: ((1, 3), Direction.WEST, 2)
  37. },
  38. (1, 3): {
  39. Direction.WEST: ((0, 3), Direction.EAST, 2),
  40. ...
  41. },
  42. ...
  43. }
  44. :return: Dict
  45. """
  46.  
  47. # OWN CODE HEREAFTER
  48. all_paths = {}
  49. for start, target, weight in self.edges:
  50. # unpack start
  51. coordinates, direction = start
  52. # if not yet existent, create new dictionary
  53. if coordinates not in all_paths:
  54. all_paths[coordinates] = {}
  55. # add target to dictionary
  56. all_paths[coordinates][direction] = (target[0], target[1], weight)
  57. return all_paths
  58.  
  59. def shortest_path(self, start: Tuple[int, int], target: Tuple[int, int]) ->
  60. Optional[List[Tuple[Tuple[int, int], Direction]]]:
  61. """
  62. Returns a shortest path between two nodes
  63.  
  64. Examples:
  65. shortest_path((0,0), (2,2)) returns: [((0, 0), Direction.EAST), ((1, 0), Direction.NORTH)]
  66. shortest_path((0,0), (1,2)) returns: None
  67. :param start: 2-Tuple
  68. :param target: 2-Tuple
  69. :return: 2-Tuple[List, Direction]
  70. """
  71.  
  72. # OWN CODE HEREAFTER ==> DIJKSTRA
  73. discovered_vertices = {}
  74. finished_vertices = {}
  75. # format of tuples: (previous vertex, direction out of previous vertex, weight from start)
  76. # keys are coordinate-tuples
  77. discovered_vertices[start] = (None, None, 0)
  78.  
  79. while len(discovered_vertices) > 0:
  80. # figure out discovered vertex with minimum weight as working_vertex
  81. min_weight = math.inf
  82. working_vertex = None
  83. for coordinates, edge in discovered_vertices.items():
  84. vertex_weight = edge[2]
  85. if vertex_weight < min_weight:
  86. working_vertex = (coordinates, edge)
  87. min_weight = vertex_weight
  88.  
  89. # move working_vertex from discovered to finished
  90. finished_vertices[working_vertex[0]] = working_vertex[1]
  91. discovered_vertices.pop(working_vertex[0])
  92.  
  93. # if target is finished, unfinished vertices don't matter
  94. if working_vertex[0] == target:
  95. break
  96.  
  97. # update discovered vertices
  98. for direction, end in self.get_paths()[working_vertex[0]].items():
  99. current_coordinate = working_vertex[0]
  100. end_coordinates = end[0]
  101. current_weight = working_vertex[1][2]
  102. path_weight = end[2]
  103.  
  104. # blocked path
  105. if path_weight <= 0:
  106. continue
  107.  
  108. if end_coordinates in finished_vertices:
  109. pass
  110. elif end_coordinates not in discovered_vertices:
  111. discovered_vertices[end_coordinates] = (current_coordinate, direction,
  112. current_weight + path_weight)
  113. else:
  114. if current_weight + path_weight < discovered_vertices[end_coordinates][2]:
  115. discovered_vertices[end_coordinates] = (current_coordinate, direction,
  116. current_weight + path_weight)
  117.  
  118. # construct path
  119. if target not in finished_vertices:
  120. return None
  121. path = [(finished_vertices[target][0], finished_vertices[target][1])]
  122. while path[0][0] != start:
  123. current_vertex = path[0][0]
  124. path.insert(0, (finished_vertices[current_vertex][0], finished_vertices[current_vertex][1]))
  125. return path
  126.  
  127. @staticmethod
  128. def direction_from_char(char):
  129. if char == "N":
  130. return Direction.NORTH
  131. elif char == "E":
  132. return Direction.EAST
  133. elif char == "S":
  134. return Direction.SOUTH
  135. elif char == "W":
  136. return Direction.WEST
  137. else:
  138. print("invalid character for direction")
  139.  
  140. @staticmethod
  141. def char_from_direction(direction):
  142. if direction == Direction.NORTH:
  143. return "N"
  144. elif direction == Direction.EAST:
  145. return "E"
  146. elif direction == Direction.SOUTH:
  147. return "S"
  148. elif direction == Direction.WEST:
  149. return "W"
  150. else:
  151. print("invalid direction for character")
  152.  
  153. def rel_to_abs_direction(self, dir_rel):
  154. if dir_rel == "front":
  155. return self.arriving_direction
  156. elif dir_rel == "left":
  157. if self.arriving_direction == Direction.NORTH:
  158. return Direction.WEST
  159. elif self.arriving_direction == Direction.WEST:
  160. return Direction.SOUTH
  161. elif self.arriving_direction == Direction.SOUTH:
  162. return Direction.EAST
  163. elif self.arriving_direction == Direction.EAST:
  164. return Direction.NORTH
  165. elif dir_rel == "right":
  166. if self.arriving_direction == Direction.NORTH:
  167. return Direction.EAST
  168. elif self.arriving_direction == Direction.WEST:
  169. return Direction.NORTH
  170. elif self.arriving_direction == Direction.SOUTH:
  171. return Direction.WEST
  172. elif self.arriving_direction == Direction.EAST:
  173. return Direction.SOUTH
  174. elif dir_rel == "back":
  175. if self.arriving_direction == Direction.NORTH:
  176. return Direction.SOUTH
  177. elif self.arriving_direction == Direction.WEST:
  178. return Direction.EAST
  179. elif self.arriving_direction == Direction.SOUTH:
  180. return Direction.NORTH
  181. elif self.arriving_direction == Direction.EAST:
  182. return Direction.WEST
  183.  
  184. def get_next_dir_rel(self):
  185. current_dir = self.arriving_direction
  186. next_dir = self.start[1]
  187. if current_dir == Direction.NORTH:
  188. if next_dir == Direction.NORTH:
  189. return "front"
  190. elif next_dir == Direction.WEST:
  191. return "left"
  192. elif next_dir == Direction.SOUTH:
  193. return "back"
  194. elif next_dir == Direction.EAST:
  195. return "right"
  196. elif current_dir == Direction.WEST:
  197. if next_dir == Direction.NORTH:
  198. return "right"
  199. elif next_dir == Direction.WEST:
  200. return "front"
  201. elif next_dir == Direction.SOUTH:
  202. return "left"
  203. elif next_dir == Direction.EAST:
  204. return "back"
  205. elif current_dir == Direction.SOUTH:
  206. if next_dir == Direction.NORTH:
  207. return "back"
  208. elif next_dir == Direction.WEST:
  209. return "right"
  210. elif next_dir == Direction.SOUTH:
  211. return "front"
  212. elif next_dir == Direction.EAST:
  213. return "left"
  214. elif current_dir == Direction.EAST:
  215. if next_dir == Direction.NORTH:
  216. return "left"
  217. elif next_dir == Direction.WEST:
  218. return "back"
  219. elif next_dir == Direction.SOUTH:
  220. return "right"
  221. elif next_dir == Direction.EAST:
  222. return "front"
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement