first_search.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. # ----------
  2. # User Instructions:
  3. #
  4. # Define a function, search() that returns a list
  5. # in the form of [optimal path length, row, col]. For
  6. # the grid shown below, your function should output
  7. # [11, 4, 5].
  8. #
  9. # If there is no valid path from the start point
  10. # to the goal, your function should return the string
  11. # 'fail'
  12. # ----------
  13. # Grid format:
  14. # 0 = Navigable space
  15. # 1 = Occupied space
  16. import heapq
  17. from collections import deque
  18. import numpy as np
  19. from icecream import ic
  20. grid = np.array([[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
  21. [1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
  22. [0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0],
  23. [0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0],
  24. [0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
  25. [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
  26. [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
  27. [0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0],
  28. [0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0],
  29. [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0]])
  30. init = np.array([0, 0])
  31. # goal = np.array([len(grid)-1, len(grid[0])-1])
  32. goal = np.array([0, 10])
  33. cost = 1
  34. delta = np.array([[-1, 0], # go up
  35. [0, -1], # go left
  36. [1, 0], # go down
  37. [0, 1]]) # go right
  38. delta_name = ['^', '<', 'v', '>']
  39. def check_navigable(grid, goal) -> bool:
  40. goal = np.array(goal)
  41. if all(goal >= np.array([0, 0])) and all(goal <= np.array([len(grid)-1, len(grid[0])-1])):
  42. if not grid[int(goal[0]), int(goal[1])]:
  43. return True
  44. return False
  45. def heuristic(now_pos, goal) -> float:
  46. """Returns the Euclidian distance between two points
  47. Parameters
  48. ----------
  49. now_pos : np.ndarray
  50. The current position
  51. goal : np.ndarray
  52. The goal position
  53. Returns
  54. -------
  55. float
  56. Distance
  57. """
  58. if type(now_pos) is not np.ndarray:
  59. now_pos = np.array(now_pos)
  60. if type(goal) is not np.ndarray:
  61. goal = np.array(goal)
  62. return np.linalg.norm(now_pos-goal)
  63. def search(grid: np.ndarray, init: list, goal: list, cost: list):
  64. # ----------------------------------------
  65. # insert code here
  66. # ----------------------------------------
  67. next_check = []
  68. heapq.heappush(next_check, np.concatenate(
  69. ([heuristic(init, goal), 0], init)))
  70. already_checked = dict()
  71. already_checked[tuple(init)] = 0
  72. cost_map = np.zeros([len(grid), len(grid[0])]) + float('inf')
  73. cost_map[init[0], init[1]] = 0
  74. expand_map = np.zeros([len(grid), len(grid[0])]) - float('inf')
  75. current_expand_num = 0
  76. expand_map[init[0], init[1]] = current_expand_num
  77. while next_check:
  78. current_center_grid = heapq.heappop(next_check)
  79. current_center_grid = current_center_grid[2:4] # type: list[int]
  80. if check_navigable(grid, current_center_grid):
  81. for move_num in range(len(delta)):
  82. next = current_center_grid+delta[move_num] # type: np.ndarray
  83. if check_navigable(grid, next) and tuple(next) not in already_checked:
  84. current_expand_num += 1
  85. gg = [heuristic(next, goal),
  86. current_expand_num] + list(next)
  87. heapq.heappush(next_check, gg)
  88. # next_check.append(next)
  89. current_cost = already_checked[current_center_grid[0],
  90. current_center_grid[1]]+cost
  91. already_checked[tuple(next)] = current_cost
  92. cost_map[int(next[0]), int(next[1])] = current_cost
  93. expand_map[int(next[0]), int(next[1])] = current_expand_num
  94. if all(next == goal):
  95. ic(cost_map)
  96. ic(expand_map)
  97. # return [cost_now, next[0], next[1]]
  98. return cost_map
  99. # ic(cost_map)
  100. # ic(expand_map)
  101. return "fail"
  102. def show_path(grid, init, goal, cost):
  103. cost_map = search(grid, init, goal, cost)
  104. motion_map = np.array([[' ' for x in range(len(grid[0]))]
  105. for y in range(len(grid))])
  106. motion_map[goal[0], goal[1]] = '*'
  107. if type(cost_map) == np.ndarray:
  108. print('success')
  109. now_position = goal
  110. while any(now_position != init):
  111. dlt_opst = deque(['v', '>', '^', '<'])
  112. neighbor_grid = np.array([now_position for _ in range(4)])+delta
  113. neighbor_grid = map(lambda pos: pos if check_navigable(
  114. grid, pos) else False, neighbor_grid)
  115. neighbor_cost = {cost_map[pos[0], pos[1]] if type(pos) == np.ndarray else float(
  116. 'INF'): [dlt_opst.popleft(), pos] for pos in neighbor_grid}
  117. next_move, now_position = neighbor_cost[min(neighbor_cost.keys())]
  118. motion_map[now_position[0], now_position[1]] = next_move
  119. return motion_map
  120. elif cost_map == 'fail':
  121. print('Fail to generate a feasible path.')
  122. return motion_map
  123. ic(show_path(grid, init, goal, cost))