2022-12-12 20:55:37 +00:00
|
|
|
from heapq import heappush, heappop
|
|
|
|
|
2022-12-17 04:53:39 +00:00
|
|
|
def search(start, is_goal, neighbors, heuristic=None):
|
2022-12-12 20:55:37 +00:00
|
|
|
if heuristic == None:
|
|
|
|
def heuristic(x):
|
|
|
|
return 0
|
2022-12-17 04:53:39 +00:00
|
|
|
if not callable(is_goal):
|
|
|
|
goal = is_goal
|
|
|
|
def is_goal(this):
|
|
|
|
return this == goal
|
2022-12-12 20:55:37 +00:00
|
|
|
if not isinstance(start, list):
|
|
|
|
start = [start]
|
|
|
|
i = 0 # tiebreaker
|
|
|
|
q = []
|
|
|
|
for s in start:
|
|
|
|
i += 1
|
|
|
|
heappush(q, (heuristic(s), i, s, None))
|
|
|
|
done = {}
|
|
|
|
while q:
|
|
|
|
z, _, this, prev = heappop(q)
|
|
|
|
if this in done:
|
|
|
|
continue
|
|
|
|
cost_so_far = z - heuristic(this)
|
|
|
|
#print(this,z, cost_so_far)
|
|
|
|
|
|
|
|
done[this] = (cost_so_far, prev)
|
|
|
|
|
2022-12-17 04:53:39 +00:00
|
|
|
if is_goal(this):
|
2022-12-12 20:55:37 +00:00
|
|
|
print("astar: visited", len(done), "nodes")
|
2022-12-18 03:29:26 +00:00
|
|
|
print("astar: pending", len(q), "nodes")
|
2022-12-12 20:55:37 +00:00
|
|
|
# reconsruct the path
|
|
|
|
n = this
|
|
|
|
path = []
|
|
|
|
while n is not None:
|
|
|
|
path.append(n)
|
|
|
|
_, n = done[n]
|
|
|
|
path.reverse()
|
|
|
|
return cost_so_far, this, path
|
|
|
|
|
|
|
|
for c, n in neighbors(this):
|
2022-12-18 03:27:28 +00:00
|
|
|
c = cost_so_far + c
|
|
|
|
if n not in done or c < done[n][0]:
|
|
|
|
h = heuristic(n)
|
|
|
|
if h is None:
|
|
|
|
continue
|
2022-12-12 20:55:37 +00:00
|
|
|
i += 1
|
2022-12-18 03:27:28 +00:00
|
|
|
heappush(q, (c+h, i, n, this))
|
2022-12-12 20:55:37 +00:00
|
|
|
|
2022-12-17 23:22:18 +00:00
|
|
|
return float('inf'), None, []
|
2022-12-12 20:55:37 +00:00
|
|
|
|
|
|
|
def test():
|
|
|
|
data = [
|
|
|
|
"aabqponm",
|
|
|
|
"abcryxxl",
|
|
|
|
"accszzxk",
|
|
|
|
"acctuvwj",
|
|
|
|
"abdefghi",
|
|
|
|
]
|
|
|
|
#data = [
|
|
|
|
# "aabbaaba",
|
|
|
|
# "abcbaaba",
|
|
|
|
# "accabcbb",
|
|
|
|
# "accbbbba",
|
|
|
|
# "abbbabab",
|
|
|
|
#]
|
|
|
|
start = (0,0)
|
|
|
|
goal = (5,2)
|
|
|
|
|
|
|
|
def get(x,y):
|
|
|
|
return ord(data[y][x])
|
|
|
|
|
|
|
|
def neighbors(src):
|
|
|
|
x,y = src
|
|
|
|
here = get(x,y)
|
|
|
|
n = []
|
|
|
|
def push(x,y):
|
|
|
|
if 0 <= y < len(data):
|
|
|
|
if 0 <= x < len(data[y]):
|
|
|
|
if get(x,y) <= here+1:
|
|
|
|
n.append((1, (x,y)))
|
|
|
|
push(x-1, y)
|
|
|
|
push(x+1,y)
|
|
|
|
push(x, y-1)
|
|
|
|
push(x, y+1)
|
|
|
|
return n
|
|
|
|
|
|
|
|
def heuristic(n):
|
|
|
|
return abs(goal[0] - n[0]) + abs(goal[1] - n[1])
|
|
|
|
|
|
|
|
c, _, path = search(start, goal, neighbors, heuristic)
|
|
|
|
print(*data, sep="\n")
|
|
|
|
print(*path, sep="\n")
|
|
|
|
assert c == 31, c
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
test()
|