Python迷宮生成和迷宮破解算法實(shí)例
迷宮生成
1.隨機(jī)PRIM
思路:先讓迷宮中全都是墻,不斷從列表(最初只含有一個(gè)啟始單元格)中選取一個(gè)單元格標(biāo)記為通路,將其周圍(上下左右)未訪問過的單元格放入列表并標(biāo)記為已訪問,再隨機(jī)選取該單元格與周圍通路單元格(若有的話)之間的一面墻打通。重復(fù)以上步驟直到列表為空,迷宮生成完畢。這種方式生成的迷宮難度高,岔口多。
效果:
代碼:
import random import numpy as np from matplotlib import pyplot as plt def build_twist(num_rows, num_cols): # 扭曲迷宮 # (行坐標(biāo),列坐標(biāo),四面墻的有無&訪問標(biāo)記) 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 # 標(biāo)記為通路 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 # 標(biāo)記為已訪問 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.深度優(yōu)先
思路:從起點(diǎn)開始隨機(jī)游走并在前進(jìn)方向兩側(cè)建立墻壁,標(biāo)記走過的單元格,當(dāng)無路可走(周圍無未訪問過的單元格)時(shí)重復(fù)返回上一個(gè)格子直到有新的未訪問單元格可走。最終所有單元格都被訪問過后迷宮生成完畢。這種方式生成的迷宮較為簡(jiǎn)單,由一條明顯但是曲折的主路徑和不多的分支路徑組成。
效果:
代碼:
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 # 標(biāo)記為已訪問 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.填坑法
思路:從起點(diǎn)開始,不斷隨機(jī)選擇沒墻的方向前進(jìn),當(dāng)處于一個(gè)坑(除了來時(shí)的方向外三面都是墻)中時(shí),退一步并建造一堵墻將坑封上。不斷重復(fù)以上步驟,最終就能抵達(dá)終點(diǎn)。
優(yōu)缺點(diǎn):可以處理含有環(huán)路的迷宮,但是處理時(shí)間較長(zhǎng)還需要更多的儲(chǔ)存空間。
代碼:
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) # 隨機(jī)選一個(gè)方向走 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() # 行動(dòng)坐標(biāo)記錄的反轉(zhuǎn) i = 0 while i < len(xy_list)-1: # 去掉重復(fù)的移動(dòng)步驟 j = (len(xy_list)-1) - r_list.index(xy_list[i]) if i != j: # 說明這兩個(gè)坐標(biāo)之間的行動(dòng)步驟都是多余的,因?yàn)橐活D移動(dòng)回到了原坐標(biāo) 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.回溯法
思路:遇到岔口則將岔口坐標(biāo)和所有可行方向壓入棧,從棧中彈出一個(gè)坐標(biāo)和方向,前進(jìn)。不斷重復(fù)以上步驟,最終就能抵達(dá)終點(diǎn)。
優(yōu)缺點(diǎn):計(jì)算速度快,需要空間小,但無法處理含有環(huán)路的迷宮。
代碼:
def solve_backtrack(num_rows, num_cols, map_arr): # 回溯法 move_list = ['R'] m = 1 # 回溯點(diǎn)組號(hào) 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())) # 記錄當(dāng)前坐標(biāo)和可行移動(dòng)方向 if mark: r, c, m, go = mark.pop() del move_list[m:] # 刪除回溯點(diǎn)之后的移動(dòng) 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
測(cè)試
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迷宮生成和迷宮破解算法實(shí)例就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- 如何用 Python 制作一個(gè)迷宮游戲
- Python 實(shí)現(xiàn)遞歸法解決迷宮問題的示例代碼
- 10分鐘教你用python動(dòng)畫演示深度優(yōu)先算法搜尋逃出迷宮的路徑
- Python解決走迷宮問題算法示例
- 一道python走迷宮算法題
- Python深度優(yōu)先算法生成迷宮
- Python使用Tkinter實(shí)現(xiàn)機(jī)器人走迷宮
- Python基于分水嶺算法解決走迷宮游戲示例
- Python使用回溯法子集樹模板解決迷宮問題示例
- Python基于遞歸算法實(shí)現(xiàn)的走迷宮問題
- 用Python代碼來解圖片迷宮的方法整理
- python實(shí)現(xiàn)的生成隨機(jī)迷宮算法核心代碼分享(含游戲完整代碼)
- 教你怎么用Python實(shí)現(xiàn)多路徑迷宮
相關(guān)文章
談?wù)凱ython:為什么類中的私有屬性可以在外部賦值并訪問
這篇文章主要介紹了談?wù)凱ython:為什么類中的私有屬性可以在外部賦值并訪問,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-03-03Python實(shí)現(xiàn)四舍五入的兩個(gè)方法總結(jié)
這篇文章主要介紹了python中實(shí)現(xiàn)四舍五入的兩種方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-09-09解決pycharm無法刪除invalid interpreter(無效解析器)的問題
這篇文章主要介紹了pycharm無法刪除invalid interpreter(無效解析器)的問題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07Python人工智能之混合高斯模型運(yùn)動(dòng)目標(biāo)檢測(cè)詳解分析
運(yùn)動(dòng)目標(biāo)檢測(cè)是計(jì)算機(jī)視覺領(lǐng)域中的一個(gè)重要內(nèi)容,其檢測(cè)效果將會(huì)對(duì)目標(biāo)跟蹤與識(shí)別造成一定的影響,本文將介紹用Python來進(jìn)行混合高斯模型運(yùn)動(dòng)目標(biāo)檢測(cè),感興趣的朋友快來看看吧2021-11-11Python一行代碼對(duì)話ChatGPT實(shí)現(xiàn)詳解
這篇文章主要為大家介紹了Python一行代碼對(duì)話ChatGPT實(shí)現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03python利用platform模塊獲取系統(tǒng)信息
這篇文章主要介紹了python利用platform模塊獲取系統(tǒng)信息,幫助大家更好的理解和使用python,感興趣的朋友可以了解下2020-10-10JPype實(shí)現(xiàn)在python中調(diào)用JAVA的實(shí)例
本篇文章主要介紹了JPype實(shí)現(xiàn)在python中調(diào)用JAVA的實(shí)例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07