[英]Python BFS program not returning grid and path, on maze with obstacles and solutions
我已經導入了一個帶有數字的文本文件,如下例所示:
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 3 0 3 0 0 0 0 3 3 3 0 3 0 0 0 0 3 3 3 3 0 3 2 2 0 0 3 3 3 3 3 3 3 2 0 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, 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 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)
在調試您的代碼時,當涉及到您的“有效”和“查找目標”函數時,我遇到了一些無限循環和其他錯誤。
根據我的廣度優先搜索經驗,最好將每個點視為一個節點(在這種情況下為坐標),並讓您的隊列由當前正在嘗試的路徑列表組成。 其中每條路徑是橫向的每個節點的列表。 通常,您不想在給定路徑中多次訪問同一節點,因此您必須跟蹤此信息,而不是單獨“左”、“右”等...
話雖如此,我構建了您的代碼並創建了一個 function ,當給定一個考慮網格邊界的節點時,它將返回有效的相鄰節點,而不是 3 並且該節點是否已被訪問。 然后對於 BFS 部分,隊列以包含起始節點的列表開始(我創建了一個 function 來查找 1 的位置)。 然后,當隊列存在時,BFS 將彈出當前路徑,獲取該路徑中的最后一個節點,找到所有有效的相鄰節點。 對於每個有效的相鄰節點,一個新的路徑條目將被添加到由舊路徑 + 相鄰節點組成的隊列中。 如果相鄰節點之一是目標,它將結束搜索並返回路徑。 我已經在路徑中包含了方向信息,以便您可以解析出來。
這應該打印出最接近 2 的路徑,如下所示:
[((5, 0), ''), ((5, 1), 'Down'), ((6, 1), 'Right'), ((6, 2), 'Down'), ((7, 2), 'Right'), ((7, 3), 'Down'), ((7, 4), 'Down'), ((7, 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, y), "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, grid, 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 的回答已經說明了一切,但是您的代碼工作雖然效率不高,但我改變的唯一值得的是,您可以使用列表而不是使用列表列表,並且有效的 function 現在檢查行進的路徑,這樣它就可以知道它在哪里,所以它不會循環。
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, moves):
for x, 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,y), _ in path:
i = x + y*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):
# Unpack
(i,j), _ = moves[-1]
# Check if already traveled
if any(x == i and y == j for (x,y), __ 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):
# Unpack
(i,j), _ = moves[-1]
if result[i+j*10] == '2':
#Print moves
output = 'Found: '
for (x,y), _ 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, y), _ = 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, y), 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, add):
if not nums.empty():
add = nums.get()
for j in ['Move Left', 'Move Right', 'Move Up', 'Move Down']:
put = add + [move(add[-1],j)]
if valid(result, put):
nums.put(put)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.