问题描述
3 0 0 0 0 1 0 0 3 3 3 0 3 0 0 0 0 0 3 3 3 0 3 0 0 0 0 0 3 3 3 0 3 0 0 0 0 0 3 3 3 0 3 0 0 0 0 0 3 3 3 0 3 0 0 0 0 2 3 3 0 3 0 0 0 0 3 3 3 0 3 0 0 0 0 3 3 3 0 3 2 2 0 0 3 3 3 3 3 3 3 3 2 3 3 3
目标是读入文本文件,将其格式化为我能够做到的网格(即 10 x 10 网格),然后对列表列表进行排序以找到数字 3 所在的解决方案一个障碍,数字 1 是起点,数字 2 是解决方案,我正在尝试使用 BFS 算法,其中代理可以向上、向下、向左、向右移动。
我正在尝试打印从起点(即 1)到达最接近的解决方案(即 2)所采取的步骤序列。数字格式为字符串/文本。我编写的程序似乎正在运行,但它从不打印解决方案或终止。要打印为解决方案的移动序列的格式为:
'下移' '提升' 等等。每个移动都在换行符上
我在下面附上了我的代码,非常感谢可以提供的任何帮助
import queue
def read_user_input():
file_name = input('Enter the name of your file :\n')
return file_name
def read_to_grid():
file_name = read_user_input()
for nums in open(file_name):
line = list(nums.split())
result = []
for _ in range(0,len(line),10):
result.append(line[_:_ + 10])
return result
file_name.close()
def print_grid(result,path=''):
for x,pos in enumerate(result[0]):
if pos == '0':
start = x
i = start
j = 0
pos = set()
for move in path:
if move == 'Move Left':
i -= 1
elif move == 'Move Right':
i += 1
elif move == 'Move Up':
j -= 1
elif move == 'Move Down':
j += 1
pos.add((j,i))
for j,row in enumerate(result):
for i,col in enumerate(row):
if (j,i) in pos:
print('#',end='')
else:
print(col + ' ',end='')
print()
def valid(result,moves):
for x,pos in enumerate(result[0]):
if pos == '0':
start = x
i = start
j = 0
for move in moves:
if move == 'Move Left':
i -= 1
elif move == 'Move Right':
i += 1
elif move == 'Move Up':
j -= 1
elif move == 'Move Down':
j += 1
if not (0 <= i < len(result[0]) and 0 <= j < len(result)):
return False
elif (result[i][j] == '3'):
return False
return True
def find_goal(result,pos in enumerate(result[0]):
if pos == '0':
start = x
i = start
j = 0
for move in moves:
if move == 'Move Left':
i -= 1
elif move == 'Move Right':
i += 1
elif move == 'Move Up':
j -= 1
elif move == 'Move Down':
j += 1
if result[j][i] == '2':
print('Found: ' + moves)
print_grid(result,moves)
return True
return False
nums = queue.Queue()
nums.put('')
add = ''
result = read_to_grid()
while not find_goal(result,add):
add = nums.get()
for j in ['Move Left','Move Right','Move Up','Move Down']:
put = add + j
if valid(result,put):
nums.put(put)
解决方法
在调试您的代码时,当涉及到您的“valid”和“find_goal”函数时,我遇到了一些无限循环和其他错误。
根据我对广度优先搜索的经验,最好将每个点视为一个节点(在这种情况下是坐标),并使您的队列由当前正在尝试的路径列表组成。其中每条路径是横向的每个节点的列表。通常,您不想在给定路径中多次访问同一个节点,因此您必须跟踪此信息,而不仅仅是“左”、“右”等...
综上所述,我构建了您的代码并创建了一个函数,当给定一个考虑网格边界的节点时,该函数将返回有效的相邻节点,而不是 3 并且该节点是否已被访问。然后对于 BFS 部分,队列以包含起始节点的列表开始(我做了一个函数来查找 1 的位置)。然后当队列存在时,BFS 将从当前路径弹出,获取该路径中的最后一个节点,找到所有有效的相邻节点。对于每个有效的相邻节点,一个新的路径条目将被添加到由旧路径 + 相邻节点组成的队列中。如果相邻节点之一是目标,它将结束搜索并返回路径。我已经在路径中包含了方向信息,以便您可以解析它。
这应该打印到最近的 2 的路径:
[((5,0),''),((5,1),'Down'),((6,'Right'),2),((7,3),4),5),'Down')]
您会看到 ...sorted(path_queue,key=lambda...
该行不需要,但它是一种确定队列优先级的懒惰方式,总是尝试最短的当前路径。如果你删除它,你会看到你仍然得到一个有效的路径,但它更长。
def read_user_input():
file_name = input('Enter the name of your file :\n')
return file_name
def read_to_grid():
file_name = read_user_input()
for nums in open(file_name):
line = list(nums.split())
result = []
for _ in range(0,len(line),10):
result.append(line[_:_ + 10])
int_result = []
for i,row in enumerate(result):
int_result.append([])
for col in row:
int_result[i].append(int(col))
return int_result
def print_grid(result,path=''):
for x,pos in enumerate(result[0]):
if pos == 0:
start = x
i = start
j = 0
pos = set()
for move in path:
if move == 'Move Left':
i -= 1
elif move == 'Move Right':
i += 1
elif move == 'Move Up':
j -= 1
elif move == 'Move Down':
j += 1
pos.add((j,i))
for j,row in enumerate(result):
for i,col in enumerate(row):
if (j,i) in pos:
print('#',end='')
else:
print(str(col) + ' ',end='')
print()
def find_start_node(grid):
for i,row in enumerate(grid):
if 1 in row:
return ((row.index(1),i),'')
return (None,None)
def valid_adj(cur_node,grid,visited):
x = cur_node[0][0]
y = cur_node[0][1]
adj = []
if ((y + 1) < 10) and (grid[y + 1][x] != 3) and not (any((x,y + 1) in node for node in visited)):
adj.append(((x,y + 1),'Down'))
if ((x + 1) < 10) and (grid[y][x + 1] != 3) and not (any((x + 1,y) in node for node in visited)):
adj.append(((x + 1,y),'Right'))
if ((y - 1) >= 0) and (grid[y - 1][x] != 3) and not (any((x,y - 1) in node for node in visited)):
adj.append(((x,y - 1),'Up'))
if ((x - 1) >= 0) and (grid[y][x - 1] != 3) and not (any((x - 1,y) in node for node in visited)):
adj.append(((x - 1,"Left"))
return adj
def BFS(grid):
start_node = find_start_node(grid)
path_queue = [[start_node]]
while path_queue:
path_queue = sorted(path_queue,key=lambda x: len(x),reverse=True) # More optimized to guarantee shortest path,not needed
cur_path = path_queue.pop()
cur_node = cur_path[-1]
if cur_node not in cur_path[:].pop():
adj = valid_adj(cur_node,cur_path)
for node in adj:
new_path = list(cur_path)
new_path.append(node)
path_queue.append(new_path)
if grid[node[0][1]][node[0][0]] == 2:
print('path found')
return new_path
return -1
grid = read_to_grid()
print_grid(grid)
print(BFS(grid))
,
好的,Ryan 的回答已经说明了一切,但是这里是您的代码虽然效率不高,但我更改的唯一值得的事情是您可以使用列表而不是使用列表,并且有效函数现在检查行进路径,以便它知道它去过哪里,这样它就不会循环。
import queue
# Read name file from user
def read_user_input():
file_name = input('Enter the name of your file :\n')
return file_name
# Read file and return list of list[10]
def read_to_grid():
with open(read_user_input()) as file:
for nums in file:
line = list(nums.split())
return line
# Shows a text grid
def print_grid(result,path=[]):
for x,pos in enumerate(result):
if pos == '1':
start = x
i = start
#j = 0
pos = set()
for move in path:
if move == 'Move Left':
i -= 1
elif move == 'Move Right':
i += 1
elif move == 'Move Up':
i -= 10
elif move == 'Move Down':
i += 10
pos.add(i)
for i,celd in enumerate(result):
if i % 10 == 0:
print()
if i in pos:
print('# ',end='')
else:
print(celd + ' ',end='')
# Validates coordinates and traveled path
def valid(result,moves):
for x,pos in enumerate(result):
if pos == '1':
start = x
i = start % 10
j = start // 10
# Where we start
travel = [(j,i)]
for move in moves:
if move == 'Move Left':
i -= 1
elif move == 'Move Right':
i += 1
elif move == 'Move Up':
j -= 1
elif move == 'Move Down':
j += 1
# Check if we have already been there
if (j,i) in travel:
return False
else:
travel += [(j,i)]
# Check coordinates
if i >= 10 or i < 0 or j >= len(result) // 10 or j < 0:
return False
elif result[i+j*10] == '3':
return False
return True
# Return true if 2 is reached
def find_goal(result,pos in enumerate(result):
if pos == '1':
start = x
i = start
#j = 0
for move in moves:
if move == 'Move Left':
i -= 1
elif move == 'Move Right':
i += 1
elif move == 'Move Up':
i -= 10
elif move == 'Move Down':
i += 10
if result[i] == '2':
print('Found: ',' '.join(moves))
print_grid(result,moves[0:-1])
return True
return False
nums = queue.Queue()
result = read_to_grid()
add = []
while not find_goal(result,add):
if not nums.empty():
add = nums.get()
for j in ['Move Left','Move Right','Move Up','Move Down']:
put = add + [j]
if valid(result,put):
nums.put(put)
编辑:
我清理了一点:
import queue
# Read name file from user
def read_user_input():
file_name = input('Enter the name of your file :\n')
return file_name
# Read file and return list of list[10]
def read_to_grid():
with open(read_user_input()) as file:
for nums in file:
line = list(nums.split())
return line
# Shows a text grid
def print_grid(result,path=[]):
pos = set()
for (x,_ in path:
i = x + y*10
pos.add(i)
for i,moves):
# Unpack
(i,j),_ = moves[-1]
# Check if already traveled
if any(x == i and y == j for (x,__ in moves[:-1]):
return False
# Check coordinates
if i >= 10 or i < 0 or j >= len(result) // 10 or j < 0:
return False
elif result[i+j*10] == '3':
return False
return True
# Return true if 2 is reached
def find_goal(result,_ = moves[-1]
if result[i+j*10] == '2':
#Print moves
output = 'Found: '
for (x,_ in moves:
output += " "+_
print(output)
#Print grid
print_grid(result,moves[1:-1])
return True
return False
# Return new position and which movement was done.
def move(pos,dir):
(x,_ = pos
if dir == 'Move Left':
x -= 1
elif dir == 'Move Right':
x += 1
elif dir == 'Move Up':
y -= 1
elif dir == 'Move Down':
y += 1
return (x,dir
nums = queue.Queue()
result = read_to_grid()
# Find the starting position
for x,pos in enumerate(result):
if pos == '1':
start = x
add = [((start % 10,start // 10),'')]
while not find_goal(result,'Move Down']:
put = add + [move(add[-1],j)]
if valid(result,put):
nums.put(put)