Python 用A-star搜索算法求解N-难题
我正在用Python中的*为我的人工智能课程制作一个n字谜解算器。我的解决方案存在的问题是,solve_puzzle()没有正常工作。当搜索节点时,它会变得越来越深,但永远不会结束,深度会变得非常高(例如,某个子节点的深度是5k) 我认为它陷入了某种循环中,并且一直循环通过相同的节点(这正是我所想的,我不确定)。我真的不知道,我尝试了3种不同的A*解决方案,但结果是一样的——搜索循环永远不会结束,也永远不会达到目标 我可以解决非常原始的难题,如Python 用A-star搜索算法求解N-难题,python,a-star,puzzle,sliding-tile-puzzle,state-space,Python,A Star,Puzzle,Sliding Tile Puzzle,State Space,我正在用Python中的*为我的人工智能课程制作一个n字谜解算器。我的解决方案存在的问题是,solve_puzzle()没有正常工作。当搜索节点时,它会变得越来越深,但永远不会结束,深度会变得非常高(例如,某个子节点的深度是5k) 我认为它陷入了某种循环中,并且一直循环通过相同的节点(这正是我所想的,我不确定)。我真的不知道,我尝试了3种不同的A*解决方案,但结果是一样的——搜索循环永远不会结束,也永远不会达到目标 我可以解决非常原始的难题,如 开始->0,1,2,3,4,5,6,7,8目标->
开始->0,1,2,3,4,5,6,7,8
目标->1,2,0,3,4,5,6,7,8(只向左移动两步)
但是对于像
这样的更复杂的谜题 开始=0,1,2,3,4,5,6,7,8
目标=1,2,5,0,3,4,6,7,8这是一个永无止境的搜索 < >我用数字移动瓷砖,而不是空白瓷砖。 以下是全部代码:
'''
class Node():
def __init__(self, n_size, m_size, current_state, goal_state, choosen_heuristic, parent):
self.n_size = n_size
self.m_size = m_size
self.dimension = self.n_size * self.m_size
self.current_state = current_state
self.goal_state = goal_state
self.choosen_heuristic = choosen_heuristic
self.parent = parent
self.child = [None, None, None, None]
self.last_operator = None
self.heuristic_cost = 0
self.depth = 0
self.priority = self.depth + self.heuristic_cost
def check_if_goal_is_reached(self):
if (self.heuristic_cost == 0):
print("GOAL IS REACHED!")
exit(1) #for now
#return
def get_blank_tile_position(self):
blank_position = 0
for i in range(self.dimension):
if (self.current_state[i] == 0):
blank_position = i
return blank_position
def misplaced_tiles_heuristic(self):
misplaced_sum = 0
for i in range(self.dimension):
if self.current_state[i] != self.goal_state[i]:
misplaced_sum += 1
#print("Count of misplaced tiless in this node is : ", misplaced_sum)
self.heuristic_cost = "misplaced"
self.heuristic_cost = misplaced_sum
self.check_if_goal_is_reached()
return misplaced_sum
def manhattan_distance(self):
distance_sum = 0
for i in range(self.dimension):
current_x = self.current_state[i] % self.n_size
goal_x = self.goal_state[i] % self.n_size
current_y = self.current_state[i] // self.m_size
goal_y = self.goal_state[i] // self.m_size
distance_sum += abs(current_x - goal_x) + abs(current_y - goal_y)
#print("Sum of Manhattan distance for this node is : ", distance_sum)
self.heuristic_cost = "manhattan"
#print("Hĺbka tohto uzla : ", self.depth)
self.check_if_goal_is_reached()
return distance_sum
def generate_children(self, choosen_heuristic):
possible_directions = []
current_node_blank_position = self.get_blank_tile_position()
# UP - I move a tile with number on it, not the blank tile
if current_node_blank_position < (self.dimension - self.n_size):
self.child[0] = Node(self.n_size, self.m_size, self.current_state, self.goal_state, self.choosen_heuristic, self.current_state)
self.child[0] = copy.deepcopy(self)
self.child[0].parent = self.current_state
self.child[0].last_operator = "UP"
self.child[0].depth = self.depth + 1
new_blank_position = current_node_blank_position + self.m_size
temp = self.child[0].current_state[current_node_blank_position]
self.child[0].current_state[current_node_blank_position] = self.child[0].current_state[new_blank_position]
self.child[0].current_state[new_blank_position] = temp
if choosen_heuristic == "misplaced":
self.child[0].misplaced_tiles_heuristic()
if choosen_heuristic == "manhattan":
self.child[0].manhattan_distance()
possible_directions.append("UP")
print("Depth of this node is : : ", self.child[0].depth)
else:
self.child[0] = None
# DOWN - I move a tile with number on it, not the blank tile
if current_node_blank_position > (self.n_size - 1):
self.child[1] = Node(self.n_size, self.m_size, self.current_state, self.goal_state, self.choosen_heuristic, self.current_state)
self.child[1] = copy.deepcopy(self)
self.child[1].parent = self.current_state
self.child[1].last_operator = "DOWN"
self.child[1].depth = self.depth + 1
new_blank_position = current_node_blank_position - self.m_size
temp = self.child[1].current_state[current_node_blank_position]
self.child[1].current_state[current_node_blank_position] = self.child[1].current_state[new_blank_position]
self.child[1].current_state[new_blank_position] = temp
if choosen_heuristic == "misplaced":
self.child[1].misplaced_tiles_heuristic()
if choosen_heuristic == "manhattan":
self.child[1].manhattan_distance()
possible_directions.append("DOWN")
#print("Depth of this node is : : ", self.child[1].depth)
else:
self.child[1] = None
# RIGHT - I move a tile with number on it, not the blank tile
if (current_node_blank_position + self.n_size) % self.m_size:
self.child[2] = Node(self.n_size, self.m_size, self.current_state, self.goal_state, self.choosen_heuristic, self.current_state)
self.child[2] = copy.deepcopy(self)
self.child[2].parent = self.current_state
self.child[2].last_operator = "RIGHT"
self.child[2].depth = self.depth + 1
new_blank_position = current_node_blank_position - 1
temp = self.child[2].current_state[current_node_blank_position]
self.child[2].current_state[current_node_blank_position] = self.child[2].current_state[new_blank_position]
self.child[2].current_state[new_blank_position] = temp
if choosen_heuristic == "misplaced":
self.child[2].misplaced_tiles_heuristic()
if choosen_heuristic == "manhattan":
self.child[2].manhattan_distance()
possible_directions.append("RIGHT")
#print("Depth of this node is : : ", self.child[2].depth)
else:
self.child[2] = None
# LEFT - I move a tile with number on it, not the blank tile
if (current_node_blank_position + 1) % self.m_size:
self.child[3] = Node(self.n_size, self.m_size, self.current_state, self.goal_state, self.choosen_heuristic, self.current_state)
self.child[3] = copy.deepcopy(self)
self.child[3].parent = self.current_state
self.child[3].last_operator = "LEFT"
self.child[3].depth = self.depth + 1
new_blank_position = current_node_blank_position + 1
temp = self.child[3].current_state[current_node_blank_position]
self.child[3].current_state[current_node_blank_position] = self.child[3].current_state[new_blank_position]
self.child[3].current_state[new_blank_position] = temp
if choosen_heuristic == "misplaced":
self.child[3].misplaced_tiles_heuristic()
if choosen_heuristic == "manhattan":
self.child[3].manhattan_distance()
possible_directions.append("LEFT")
#print("Depth of this node is : ", self.child[3].depth)
else:
self.child[3] = None
#print("From this node (the parent node) I can move to -> ", possible_directions)
def get_node_priority(node):
return node.priority
def solve_puzzle(n_size, m_size, current_state, goal_state, choosen_heuristic):
open_list = []
closed_list = []
init_node_parent = None
init_node = Node(n_size, m_size, current_state, goal_state, choosen_heuristic, init_node_parent)
open_list.append(init_node)
while len(open_list) != 0:
if (len(open_list) == 0):
print("Fail - solution not found !")
else:
node = open_list.pop(0)
if (node.parent != None):
node.check_if_goal_is_reached()
node.generate_children(choosen_heuristic)
closed_list.append(node)
temp_list = []
for i in range(4):
if node.child[i] != None:
temp_list.insert(0, node.child[i])
sorted_temp_list = sorted(temp_list, key=get_node_priority, reverse=True)
for x in range(len(sorted_temp_list)):
if sorted_temp_list[x] != None:
open_list.insert(0, sorted_temp_list[x])
def print_current_node(current_node):
puzzle = ""
if current_node is None:
puzzle = ""
print(puzzle)
else:
puzzle = ""
count_lines = 0
for i in range(current_node.dimension):
puzzle += (str(current_node.current_state[i]) + " ")
count_lines += 1
if (count_lines % current_node.m_size == 0):
puzzle += "\n"
print(puzzle)
def main():
###################
# Static Data #
###################
# static for now, later I will let user to choose
n_size = 3
m_size = 3
current_state = [0, 1, 2, 3, 4, 5, 6, 7, 8]
goal_state = [8, 0, 6, 5, 4, 7, 2, 3, 1]
choosen_heuristic = "manhattan"
start_time = time.process_time()
solve_puzzle(n_size, m_size, current_state, goal_state, choosen_heuristic)
end_time = time.process_time()
search_time = end_time - start_time
print("Solved in : ", search_time, "seconds.")
main()
'''
“”
类节点():
定义初始(自我、n大小、m大小、当前状态、目标状态、选择启发式、父项):
self.n\u size=n\u size
self.m_size=m_size
self.dimension=self.n\u大小*self.m\u大小
self.current_state=当前_状态
self.goal\u state=目标状态
self.choosen\u启发式=choosen\u启发式
self.parent=parent
self.child=[无,无,无,无]
self.last_运算符=无
self.u成本=0
self.depth=0
self.priority=self.depth+self.lu成本
def检查是否达到目标(自我):
如果(自我启发成本==0):
打印(“达到目标!”)
退出(1)#暂时退出
#返回
def get_blank_tile_位置(自身):
空白位置=0
对于范围内的i(自身尺寸):
如果(自身当前状态[i]==0):
空白位置=i
返回空白位置
def错误放置的瓷砖启发式(自我):
放错位置的总和=0
对于范围内的i(自身尺寸):
if self.current_state[i]!=自我目标状态[i]:
错位_和+=1
#打印(“此节点中错位平铺的计数为:”,错位总和)
self.heuristic_cost=“错位”
self.heuristic\u cost=放错位置的\u和
自我检查。检查是否达到目标()
返回错放的金额
def曼哈顿_距离(自身):
距离之和=0
对于范围内的i(自身尺寸):
当前\u x=自身。当前\u状态[i]%self.n\u大小
目标x=自我。目标状态[i]%self.n\u大小
current\u y=self.current\u state[i]//self.m\u size
goal\u y=self.goal\u state[i]//self.m\u size
距离总和+=abs(当前x-目标x)+abs(当前y-目标y)
#打印(“此节点的曼哈顿距离之和为:”,距离\u之和)
self.u成本=“曼哈顿”
#印刷品(“Hĺbka tohto uzla:”,自我深度)
自我检查。检查是否达到目标()
返回距离
def生成子项(自我、选择):
可能的方向=[]
当前\u节点\u blank\u position=self.get\u blank\u tile\u position()
我用一个数字移动一个瓦片,而不是空白的瓦片。
如果当前节点\u空白\u位置<(self.dimension-self.n\u size):
self.child[0]=节点(self.n\u大小、self.m\u大小、self.current\u状态、self.goal\u状态、self.choosen\u启发式、self.current\u状态)
self.child[0]=copy.deepcopy(self)
self.child[0]。parent=self.current\u状态
self.child[0]。last_operator=“UP”
self.child[0]。深度=self.depth+1
新建\u空白\u位置=当前\u节点\u空白\u位置+self.m\u大小
temp=self.child[0]。当前\u状态[当前\u节点\u空白\u位置]
self.child[0]。当前\u状态[当前\u节点\u空白\u位置]=self.child[0]。当前\u状态[新\u空白\u位置]
self.child[0]。当前\u状态[新\u空白\u位置]=临时
如果选择启发式==“错位”:
self.child[0]。放置错误的\u tiles\u启发式()
如果选择启发式==“曼哈顿”:
self.child[0].曼哈顿距离()
可能的方向。附加(“向上”)
打印(“此节点的深度为::”,self.child[0].Depth)
其他:
self.child[0]=无
我向下移动一个有数字的瓦片,而不是空白的瓦片。
如果当前节点\u空白\u位置>(self.n\u大小-1):
self.child[1]=节点(self.n\u大小、self.m\u大小、self.current\u状态、self.goal\u状态、self.choosen\u启发式、self.current\u状态)
self.child[1]=copy.deepcopy(self)
self.child[1]。parent=self.current\u state
self.child[1]。last_operator=“DOWN”
self.child[1]。深度=self.depth+1
新建\u空白\u位置=当前\u节点\u空白\u位置-self.m\u大小
temp=self.child[1]。当前\u状态[当前\u节点\u空白\u位置]
self.child[1]。当前\u状态[当前\u节点\u空白\u位置]=self.child[1]。当前\u状态[新\u空白\u位置]
self.child[1]。当前\u状态[新\u空白\u位置]=临时
如果选择启发式==“错位”:
self.child[1]。放错位置的\u tiles\u启发式()
如果选择启发式==“曼哈顿”:
self.child[1].曼哈顿距离()
可能的方向。附加(“向下”)
#打印(“此节点的深度为::”,self.child[1].Depth)
其他:
self.child[1]=无
我用一个数字移动一个瓦片,而不是空白的瓦片。
如果(当前节点\u空白\u位置+self.n\u大小)%self.m\u大小:
self.child[2]=节点(self.n\u大小、self.m\u大小、self.current\u状态、self.goal\u状态、self.choosen\u启发式、self.current\u状态)
goal: {1,2,3,4,5,6,7,8,0}
6 steps: {1,3,5,4,0,2,7,8,6}
18 steps: {1,4,0,5,2,8,7,6,3}
26 steps: {2,1,7,5,0,8,3,4,6}
27 steps: {8,5,3,4,7,0,6,1,2}
28 steps: {0,6,7,3,8,5,4,2,1}
30 steps: {5,7,0,4,6,8,1,2,3}
31 steps: {8,6,7,2,5,4,3,0,1} (highest number of steps possible for 3x3 )