Python/graphs/uniform_search_cost.py
2023-08-08 14:39:05 +06:00

273 lines
9.2 KiB
Python

import heapq
# diagonal clockwise
dxy1 = [
(1, 1),
(1, 0),
(1, -1),
(0, -1),
(-1, -1),
(-1, 0),
(-1, 1),
(0, 1),
]
# diagonal anti-clockwise
dxy2 = [
(-1, -1),
(-1, 0),
(0, -1),
(0, 1),
(1, 1),
(1, 0),
(1, -1),
(-1, 1),
]
# start point and end point on same row and column right side
dxy3 = [
(0, -1),
(-1, -1),
(-1, 0),
(0, 1),
(1, 1),
(1, 0),
(1, -1),
(-1, 1),
]
# start point and end point on same row and column left side
dxy4 = [
(0, 1),
(1, 1),
(1, 0),
(1, -1),
(0, -1),
(-1, -1),
(-1, 0),
(-1, 1),
]
# start point and end point on same column and row down side
dxy5 = [
(1, 0),
(0, 1),
(1, 1),
(1, -1),
(0, -1),
(-1, -1),
(-1, 0),
(-1, 1),
]
# start point and end point on same column and row up side
dxy6 = [
(0, -1),
(0, 1),
(1, 1),
(1, 0),
(1, -1),
(-1, -1),
(-1, 0),
(-1, 1),
]
class UniformCostSearch:
def __init__(self, grid: list[list[int]]) -> None:
self.m = len(grid[0])
self.n = len(grid)
def get_shortest_path(
self,
start: list[int],
end: list[int],
dist: list[list[int]],
dxy: list[tuple],
) -> list[list[int]]:
"""
Return 2D list where optimal path is stored.
>>> start = [0,0]
>>> end = [1, 2]
>>> dist = [[1,0],[0,2]]
>>> dxy = [(1, 1),(1, 0),(1, -1),(0, -1),(-1, -1),(-1, 0),(-1, 1),(0, 1)]
>>> get_shortest_path(start,end,dist,dxy)
[[0,0],[1,1]]
"""
shortest_path = []
curr_node = end
while curr_node != start:
shortest_path.append(curr_node)
row, col = curr_node
min_cell = float("inf")
next_cell = None
for dr, dc in dxy:
if (
0 <= row + dr < self.m
and 0 <= col + dc < self.n
and [row + dr, col + dc] not in shortest_path
):
if dist[row + dr][col + dc] <= min_cell:
min_cell = dist[row + dr][col + dc]
next_cell = [row + dr, col + dc]
curr_node = next_cell
shortest_path.append(start)
return shortest_path
def ucs(
self,
current: list[int],
final: list[list[int]],
grid: list[list[int]],
prev: list[list[int]],
dxy: list[tuple],
goal_answer: list,
) -> list[list[int]]:
"""
Return 2D list where optimal path is stored.
>>> current = [0, 0]
>>> final = [[1, 1]]
>>> grid = [[0,0],[0,0]]
>>> prev = [[None, None],[None, None]]
>>> dxy = [(1, 1),(1, 0),(1, -1),(0, -1),(-1, -1),(-1, 0),(-1, 1),(0, 1)]
>>> goal_answer = [1000000, 100000]
>>> ucs(current,final,grid,dxy,prev,goal_answer)
[[0,2],[1,1]]
"""
dist = [[float("inf") for _ in range(self.m)] for _ in range(self.n)]
visited = [[0 for _ in range(self.m)] for _ in range(self.n)]
x = current[0]
y = current[1]
dist[x][y] = 0
final_cnt = 0
heap = [(0, x, y)]
while heap:
d, x, y = heapq.heappop(heap)
if visited[x][y]:
continue
visited[x][y] = 1
if [x, y] in final:
idxs = [ix for ix, iy in enumerate(final) if iy == [x, y]]
if len(idxs) > 1:
return None
if goal_answer[idxs[0]] == 10**8:
final_cnt += 1
if goal_answer[idxs[0]] > d:
goal_answer[idxs[0]] = d
if final_cnt == len(final):
path = self.get_shortest_path(current, final[0], dist, dxy)
return path
for dx, dy in dxy:
if (
0 <= x + dx < self.m
and 0 <= y + dy < self.n
and grid[x + dx][y + dy] != 1
):
weight = 1
diagonal_weight = 1.414
if (
(dx == -1 and dy == -1)
or (dx == 1 and dy == 1)
or (dx == 1 and dy == -1)
or (dx == -1 and dy == 1)
):
new_dist = d + diagonal_weight
else:
new_dist = d + weight
if new_dist < dist[x + dx][y + dy]:
dist[x + dx][y + dy] = new_dist
prev[x + dx][y + dy] = (x, y)
heapq.heappush(heap, (new_dist, x + dx, y + dy))
def your_algorithm(
self, start_point: list[int], end_point: list[int], grid: list[list[int]]
) -> list[list[int]]:
"""
Return 2D list where optimal path is stored.
>>> start_point = [0, 0]
>>> end_point = [1, 1]
>>> grid = [[0,0],[0,0]]
>>> your_algorithm(start_point, end_point, grid)
[[0,0],[1,1]]
"""
prev = [[None for _ in range(self.m)] for _ in range(self.n)]
dxy = []
if start_point[1] - end_point[1] == 0 and start_point[0] - end_point[0] < 0:
dxy = dxy5
elif start_point[1] - end_point[1] == 0 and start_point[0] - end_point[0] > 0:
dxy = dxy6
elif start_point[0] - end_point[0] == 0 and start_point[1] - end_point[1] < 0:
dxy = dxy4
elif start_point[0] - end_point[0] == 0 and start_point[1] - end_point[1] > 0:
dxy = dxy3
elif start_point[0] - end_point[0] > 0:
dxy = dxy2
elif start_point[0] - end_point[0] < 0:
dxy = dxy1
goal_answer = []
for _ in range(0, len(end_point)):
goal_answer.append(10**8)
path = self.ucs(start_point, [end_point], grid, prev, dxy, goal_answer)
return path
def run() -> None:
"""
Return None. Its just running the UCS algorithm class.
>>> run()
None
"""
executed_object = UniformCostSearch(
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
],
)
path_result = executed_object.your_algorithm(
[0, 7],
[19, 17],
[
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
],
)
print(path_result)
if __name__ == "__main__":
run()