您好,登錄后才能下訂單哦!
小編給大家分享一下Python迷宮生成和迷宮破解算法的示例分析,希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
迷宮生成
1.隨機PRIM
思路:先讓迷宮中全都是墻,不斷從列表(最初只含有一個啟始單元格)中選取一個單元格標記為通路,將其周圍(上下左右)未訪問過的單元格放入列表并標記為已訪問,再隨機選取該單元格與周圍通路單元格(若有的話)之間的一面墻打通。重復以上步驟直到列表為空,迷宮生成完畢。這種方式生成的迷宮難度高,岔口多。
效果:
代碼:
import random import numpy as np from matplotlib import pyplot as plt def build_twist(num_rows, num_cols): # 扭曲迷宮 # (行坐標,列坐標,四面墻的有無&訪問標記) m = np.zeros((num_rows, num_cols, 5), dtype=np.uint8) r, c = 0, 0 trace = [(r, c)] while trace: r, c = random.choice(trace) m[r, c, 4] = 1 # 標記為通路 trace.remove((r, c)) check = [] if c > 0: if m[r, c - 1, 4] == 1: check.append('L') elif m[r, c - 1, 4] == 0: trace.append((r, c - 1)) m[r, c - 1, 4] = 2 # 標記為已訪問 if r > 0: if m[r - 1, c, 4] == 1: check.append('U') elif m[r - 1, c, 4] == 0: trace.append((r - 1, c)) m[r - 1, c, 4] = 2 if c < num_cols - 1: if m[r, c + 1, 4] == 1: check.append('R') elif m[r, c + 1, 4] == 0: trace.append((r, c + 1)) m[r, c + 1, 4] = 2 if r < num_rows - 1: if m[r + 1, c, 4] == 1: check.append('D') elif m[r + 1, c, 4] == 0: trace.append((r + 1, c)) m[r + 1, c, 4] = 2 if len(check): direction = random.choice(check) if direction == 'L': # 打通一面墻 m[r, c, 0] = 1 c = c - 1 m[r, c, 2] = 1 if direction == 'U': m[r, c, 1] = 1 r = r - 1 m[r, c, 3] = 1 if direction == 'R': m[r, c, 2] = 1 c = c + 1 m[r, c, 0] = 1 if direction == 'D': m[r, c, 3] = 1 r = r + 1 m[r, c, 1] = 1 m[0, 0, 0] = 1 m[num_rows - 1, num_cols - 1, 2] = 1 return m
2.深度優先
思路:從起點開始隨機游走并在前進方向兩側建立墻壁,標記走過的單元格,當無路可走(周圍無未訪問過的單元格)時重復返回上一個格子直到有新的未訪問單元格可走。最終所有單元格都被訪問過后迷宮生成完畢。這種方式生成的迷宮較為簡單,由一條明顯但是曲折的主路徑和不多的分支路徑組成。
效果:
代碼:
def build_tortuous(num_rows, num_cols): # 曲折迷宮 m = np.zeros((num_rows, num_cols, 5), dtype=np.uint8) r = 0 c = 0 trace = [(r, c)] while trace: m[r, c, 4] = 1 # 標記為已訪問 check = [] if c > 0 and m[r, c - 1, 4] == 0: check.append('L') if r > 0 and m[r - 1, c, 4] == 0: check.append('U') if c < num_cols - 1 and m[r, c + 1, 4] == 0: check.append('R') if r < num_rows - 1 and m[r + 1, c, 4] == 0: check.append('D') if len(check): trace.append([r, c]) direction = random.choice(check) if direction == 'L': m[r, c, 0] = 1 c = c - 1 m[r, c, 2] = 1 if direction == 'U': m[r, c, 1] = 1 r = r - 1 m[r, c, 3] = 1 if direction == 'R': m[r, c, 2] = 1 c = c + 1 m[r, c, 0] = 1 if direction == 'D': m[r, c, 3] = 1 r = r + 1 m[r, c, 1] = 1 else: r, c = trace.pop() m[0, 0, 0] = 1 m[num_rows - 1, num_cols - 1, 2] = 1 return m
迷宮破解
效果:
1.填坑法
思路:從起點開始,不斷隨機選擇沒墻的方向前進,當處于一個坑(除了來時的方向外三面都是墻)中時,退一步并建造一堵墻將坑封上。不斷重復以上步驟,最終就能抵達終點。
優缺點:可以處理含有環路的迷宮,但是處理時間較長還需要更多的儲存空間。
代碼:
def solve_fill(num_rows, num_cols, m): # 填坑法 map_arr = m.copy() # 拷貝一份迷宮來填坑 map_arr[0, 0, 0] = 0 map_arr[num_rows-1, num_cols-1, 2] = 0 move_list = [] xy_list = [] r, c = (0, 0) while True: if (r == num_rows-1) and (c == num_cols-1): break xy_list.append((r, c)) wall = map_arr[r, c] way = [] if wall[0] == 1: way.append('L') if wall[1] == 1: way.append('U') if wall[2] == 1: way.append('R') if wall[3] == 1: way.append('D') if len(way) == 0: return False elif len(way) == 1: # 在坑中 go = way[0] move_list.append(go) if go == 'L': # 填坑 map_arr[r, c, 0] = 0 c = c - 1 map_arr[r, c, 2] = 0 elif go == 'U': map_arr[r, c, 1] = 0 r = r - 1 map_arr[r, c, 3] = 0 elif go == 'R': map_arr[r, c, 2] = 0 c = c + 1 map_arr[r, c, 0] = 0 elif go == 'D': map_arr[r, c, 3] = 0 r = r + 1 map_arr[r, c, 1] = 0 else: if len(move_list) != 0: # 不在坑中 come = move_list[len(move_list)-1] if come == 'L': if 'R' in way: way.remove('R') elif come == 'U': if 'D' in way: way.remove('D') elif come == 'R': if 'L' in way: way.remove('L') elif come == 'D': if 'U' in way: way.remove('U') go = random.choice(way) # 隨機選一個方向走 move_list.append(go) if go == 'L': c = c - 1 elif go == 'U': r = r - 1 elif go == 'R': c = c + 1 elif go == 'D': r = r + 1 r_list = xy_list.copy() r_list.reverse() # 行動坐標記錄的反轉 i = 0 while i < len(xy_list)-1: # 去掉重復的移動步驟 j = (len(xy_list)-1) - r_list.index(xy_list[i]) if i != j: # 說明這兩個坐標之間的行動步驟都是多余的,因為一頓移動回到了原坐標 del xy_list[i:j] del move_list[i:j] r_list = xy_list.copy() r_list.reverse() i = i + 1 return move_list
2.回溯法
思路:遇到岔口則將岔口坐標和所有可行方向壓入棧,從棧中彈出一個坐標和方向,前進。不斷重復以上步驟,最終就能抵達終點。
優缺點:計算速度快,需要空間小,但無法處理含有環路的迷宮。
代碼:
def solve_backtrack(num_rows, num_cols, map_arr): # 回溯法 move_list = ['R'] m = 1 # 回溯點組號 mark = [] r, c = (0, 0) while True: if (r == num_rows-1) and (c == num_cols-1): break wall = map_arr[r, c] way = [] if wall[0] == 1: way.append('L') if wall[1] == 1: way.append('U') if wall[2] == 1: way.append('R') if wall[3] == 1: way.append('D') come = move_list[len(move_list) - 1] if come == 'L': way.remove('R') elif come == 'U': way.remove('D') elif come == 'R': way.remove('L') elif come == 'D': way.remove('U') while way: mark.append((r, c, m, way.pop())) # 記錄當前坐標和可行移動方向 if mark: r, c, m, go = mark.pop() del move_list[m:] # 刪除回溯點之后的移動 else: return False m = m + 1 move_list.append(go) if go == 'L': c = c - 1 elif go == 'U': r = r - 1 elif go == 'R': c = c + 1 elif go == 'D': r = r + 1 del move_list[0] return move_list
測試
rows = int(input("Rows: ")) cols = int(input("Columns: ")) Map = build_twist(rows, cols) plt.imshow(draw(rows, cols, Map), cmap='gray') fig = plt.gcf() fig.set_size_inches(cols/10/3, rows/10/3) plt.gca().xaxis.set_major_locator(plt.NullLocator()) plt.gca().yaxis.set_major_locator(plt.NullLocator()) plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0) plt.margins(0, 0) fig.savefig('aaa.png', format='png', transparent=True, dpi=300, pad_inches=0) move = solve_backtrack(rows, cols, Map) plt.imshow(draw_path(draw(rows, cols, Map), move), cmap='hot') fig = plt.gcf() fig.set_size_inches(cols/10/3, rows/10/3) plt.gca().xaxis.set_major_locator(plt.NullLocator()) plt.gca().yaxis.set_major_locator(plt.NullLocator()) plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0) plt.margins(0, 0) fig.savefig('bbb.png', format='png', transparent=True, dpi=300, pad_inches=0)
看完了這篇文章,相信你對“Python迷宮生成和迷宮破解算法的示例分析”有了一定的了解,如果想了解更多相關知識,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。