from queue import PriorityQueue
start = [1, 5, 2,
4, 8, 3,
0, 7, 6]
goal = [1, 2, 3,
4, 5, 6,
7, 8, 0]
# 评估函数h(n)
# 计算结点的 h 值 f=g+h. 按照不在位的个数进行计算
def heuristic(state, goal):
return sum(s != g for s, g in zip(state, goal))
# 扩展函数extends
def extends(state):
# 找到空格所在的位置
i = state.index(0)
# 可能进行的移动
extends = []
if i % 3 > 0: extends.append(('left', i - 1))
if i % 3 < 2: extends.append(('right', i + 1))
if i // 3 > 0: extends.append(('up', i - 3))
if i // 3 < 2: extends.append(('down', i + 3))
return extends
# 根据当前状态,返回扩展后的新状态
def result(state, extends):
# 复制当前状态
new_state = state[:]
# 找到空格的位置
i = state.index(0)
# 执行动作
if extends[0] == 'up':
new_state[i], new_state[i - 3] = new_state[i - 3], new_state[i] #交换索引
elif extends[0] == 'down':
new_state[i], new_state[i + 3] = new_state[i + 3], new_state[i]
elif extends[0] == 'left':
new_state[i], new_state[i - 1] = new_state[i - 1], new_state[i]
elif extends[0] == 'right':
new_state[i], new_state[i + 1] = new_state[i + 1], new_state[i]
return new_state
# A*算法
def astar(start, goal):
open = PriorityQueue()
open.put((heuristic(start, goal), 0, start))
visited = set()
parents = {tuple(start): None} # 记录父状态
while not open.empty():
print(list(open.queue))
priority, cost, state = open.get()
if state == goal:
return cost, parents # 返回最小步数和父状态
if tuple(state) in visited:
continue
visited.add(tuple(state))
for extend in extends(state):
next_state = result(state, extend)
if tuple(next_state) not in visited:
priority = cost + 1 + heuristic(next_state, goal)
open.put((priority, cost + 1, next_state))
parents[tuple(next_state)] = state # 记录父状态
return None, None
if __name__ == '__main__':
start = [1, 5, 2,
4, 8, 3,
0, 7, 6]
goal = [1, 2, 3,
4, 5, 6,
7, 8, 0]
steps, parents = astar(start, goal)
print("最优的步数是:", steps)
# 打印最优路径
path = []
state = goal
while state is not None:
path.append(state)
state = parents[tuple(state)]
path.reverse()
print("最优的路径是:")
for state in path:
# 将状态转换为3x3的形式并打印
for i in range(0, 9, 3):
print(state[i:i + 3])
print()
# 将起始点加入open表
#
# 当open表不为空时:
#
# 寻找open表中f值最小的点current
#
# 它是终止点,则找到结果,程序结束。
#
# 否则,Open表移出current,对current表中的每一个临近点
#
# 若它不可走或在close表中,略过
#
# 若它不在open表中,加入。
#
# 若它在open表中,计算g值,若g值更小,替换其父节点为current,更新它的g值。
#
# 若open表为空,则路径不存在。
10-28
1995
![](https://csdnimg.cn/release/blogv2/dist/pc/img/readCountWhite.png)