Guest User

Untitled

a guest
Nov 21st, 2017
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.70 KB | None | 0 0
  1. import heapq
  2. import fileinput
  3.  
  4.  
  5. class Node:
  6.  
  7. def __init__(self, state, parent=None, action=None, cost=0):
  8. self.state = state
  9. self.parent = parent
  10. self.action = action
  11. self.cost = cost
  12.  
  13. def get_path_action(self):
  14. path_actions = []
  15. node = self
  16.  
  17. while node.parent is not None:
  18. path_actions.append(node.action)
  19. node = node.parent
  20.  
  21. path_actions.reverse()
  22. return path_actions
  23.  
  24. def __str__(self):
  25. return "-- Node {0} --\n Parent: {1}\n Action: {2}\n Cost: {3}" \
  26. .format(self.state, self.parent, self.action, self.cost)
  27.  
  28. def __lt__(self, other):
  29. return self.cost < other.cost
  30.  
  31.  
  32. class MazeSolver(object):
  33.  
  34. def __init__(self, maze_rows):
  35. self.maze_rows = maze_rows
  36. self.start, self.end = self._get_start_end()
  37. self.FRINGE = 0
  38. self.EXPANDED = 1
  39. self.path = None
  40.  
  41. def _get_start_end(self):
  42. start = end = (0, 0)
  43. for i, _ in enumerate(self.maze_rows):
  44. for j, _ in enumerate(self.maze_rows[i]):
  45. if self.maze_rows[i][j] == 'A':
  46. start = (i, j)
  47. continue
  48. if self.maze_rows[i][j] == 'B':
  49. end = (i, j)
  50. continue
  51. return start, end
  52.  
  53. def solve(self):
  54. # Solved with A* algorithm
  55. fringe = []
  56. nss = dict()
  57.  
  58. heapq.heappush(fringe, (0, Node(self.start)))
  59. nss[self.start] = (self.FRINGE, 0)
  60.  
  61. while fringe:
  62. n = heapq.heappop(fringe)[1]
  63. state = n.state
  64. if nss[state] == self.EXPANDED:
  65. continue
  66.  
  67. if state == self.end:
  68. self.path = n.get_path_action()
  69.  
  70. nss[n] = (self.EXPANDED, n.cost)
  71.  
  72. for s, a, c in self._get_successors(n):
  73. cost = n.cost + c
  74. heuristic_cost = self._manhattan_distance(s)
  75. ns = Node(s, n, a, cost)
  76.  
  77. if ns.state not in nss:
  78. total_cost = ns.cost + heuristic_cost
  79. heapq.heappush(fringe, (total_cost, ns))
  80. nss[ns.state] = (self.FRINGE, ns.cost)
  81. elif nss[ns.state][1] > ns.cost and nss[ns.state][0] == self.FRINGE:
  82. nss[ns.state] = (self.FRINGE, ns.cost)
  83.  
  84. def _get_successors(self, node):
  85. x = node.state[0]
  86. y = node.state[1]
  87.  
  88. actions = ['Right', 'Left', 'Up', 'Down']
  89. states = [(x,y+1), (x,y-1), (x-1,y), (x+1,y)]
  90. act_dict = {a: s for a, s in zip(actions, states) if self._is_valid_state(s)}
  91. for a in act_dict:
  92. yield act_dict[a], a, 1
  93.  
  94. def _is_valid_state(self, state):
  95. x = state[0]
  96. y = state[1]
  97. return x >= 0 and x < len(self.maze_rows) and \
  98. y >= 0 and y < len(self.maze_rows[0]) and \
  99. self.maze_rows[x][y] != '#'
  100.  
  101. def _manhattan_distance(self, state):
  102. return abs(self.end[0] - state[0]) + abs(self.end[1] - state[1])
  103.  
  104. def draw(self):
  105. if not self.path:
  106. print('Error! Path is not computed!')
  107. return
  108.  
  109. curr_x = self.start[0]
  110. curr_y = self.start[1]
  111. prev_act = None
  112. act = None
  113. next_act = None
  114.  
  115. for i in range(len(self.path)):
  116. prev_act = self.path[i-1] if i > 0 else None
  117. act = self.path[i]
  118. next_act = self.path[i+1] if i < len(self.path) - 1 else None
  119.  
  120. if act == 'Right':
  121. curr_y += 1
  122. elif act == 'Left':
  123. curr_y -= 1
  124. elif act == 'Up':
  125. curr_x -= 1
  126. elif act == 'Down':
  127. curr_x += 1
  128.  
  129. if act == 'Right' and next_act == 'Up':
  130. self._set_char(curr_x, curr_y, '┘')
  131. elif act == 'Right' and next_act == 'Down':
  132. self._set_char(curr_x, curr_y, '┐')
  133. elif act == 'Left' and next_act == 'Up':
  134. self._set_char(curr_x, curr_y, '└')
  135. elif act == 'Left' and next_act == 'Down':
  136. self._set_char(curr_x, curr_y, '┌')
  137. elif act == 'Up' and next_act == 'Left':
  138. self._set_char(curr_x, curr_y, '┐')
  139. elif act == 'Up' and next_act == 'Right':
  140. self._set_char(curr_x, curr_y, '┌')
  141. elif act == 'Down' and next_act == 'Left':
  142. self._set_char(curr_x, curr_y, '┘')
  143. elif act == 'Down' and next_act == 'Right':
  144. self._set_char(curr_x, curr_y, '└')
  145. elif act == 'Down' or act == 'Up':
  146. self._set_char(curr_x, curr_y, '|')
  147. elif act == 'Right' or act == 'Left':
  148. self._set_char(curr_x, curr_y, '-')
  149.  
  150. def _set_char(self, x, y, c):
  151. if self.maze_rows[x][y] != 'A' and self.maze_rows[x][y] != 'B':
  152. row = list(self.maze_rows[x])
  153. row[y] = c
  154. self.maze_rows[x] = "".join(row)
  155.  
  156. def print_maze(self):
  157. for r in self.maze_rows:
  158. print(r)
  159.  
  160.  
  161. def main():
  162. n_mazes = 0
  163. current_maze = 0
  164. mazes = dict()
  165. solved_mazes = dict()
  166.  
  167. # Parse input
  168. for line in fileinput.input():
  169. line = line.strip()
  170. if n_mazes == 0:
  171. n_mazes = int(line)
  172. else:
  173. if line.isdigit():
  174. current_maze = int(line)
  175. mazes[current_maze] = []
  176. else:
  177. mazes[current_maze].append(line)
  178.  
  179. # Solve input mazes
  180. print(n_mazes)
  181. for m in mazes.keys():
  182. print(m)
  183. maze_solver = MazeSolver(mazes[m])
  184. maze_solver.solve()
  185. maze_solver.draw()
  186. maze_solver.print_maze()
  187.  
  188.  
  189. if __name__ == '__main__':
  190. main()
Add Comment
Please, Sign In to add comment