簡單介紹Python迷宮生成和迷宮破解演算法
1迷宮生成
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
2.迷宮破解
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)
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69945560/viewspace-2688143/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Python迷宮生成器Python
- PHP 生成迷宮路線PHP
- 1744 迷宮
- 509迷宮
- 走迷宮
- 3090 走迷宮
- 3089 探索迷宮
- 迷宮問題
- 迷宮可行路徑數
- 迷宮的最短路徑
- 迷宮城堡(HDU-1269)
- 解密迷宮問題:三種高效演算法Java實現,讓你輕鬆穿越未知迷宮解密演算法Java
- 創造你的專屬迷宮 《磚塊迷宮建造者》上架WeGameGAM
- 【Javascript + Vue】實現隨機生成迷宮圖片JavaScriptVue隨機
- C++實現迷宮的生成與解決C++
- 如何用js寫一個簡單的迷宮和打地鼠遊戲JS遊戲
- 回溯法求迷宮問題
- POJ3984-迷宮問題
- 藍橋杯-走迷宮(BFS)
- PHP 解迷宮之 H 最小PHP
- 內容是超正統的迷宮RPG?PSP遊戲《迷宮旅人2》深度解析遊戲
- 使用A*演算法解迷宮最短路徑問題演算法
- 自動走迷宮小遊戲~遊戲
- [SDOI2012] 走迷宮 題解
- UOJ #810. 【UNR #7】位元迷宮
- 藍橋杯-迷宮(BFS+DFS)
- PHP 解迷宮之 G + H 最小PHP
- 【ybtoj】【BFS】【例題1】走迷宮
- POJ3984 迷宮問題【BFS】
- hdu 1728 逃離迷宮 搜尋
- 用 Canvas + WASM 畫一個迷宮CanvasASM
- Python 精靈模組_迷宮房間類遊戲Python遊戲
- 用python深度優先遍歷解迷宮問題Python
- c++迷宮問題回溯法遞迴演算法C++遞迴演算法
- 基於RL(Q-Learning)的迷宮尋路演算法演算法
- 10.16 CW 模擬賽 D. 迷宮(maze)
- 7-12 求迷宮最短通道(整合版)
- 回溯和遞迴實現迷宮問題(C語言)遞迴C語言