程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

Python Prim 算法 生成迷宮

編輯:Python

之前,我們在另外一篇文章中使用Prim算法生成了一個完美迷宮,利用的是遍歷網格的方法,這一次,我們要教教大家用遍歷牆的方法生成,上一篇文章鏈接:Python Prim 算法 生成迷宮_Leleprogrammer的博客-CSDN博客_prim算法生成迷宮Prim算法生成完美迷宮矩陣https://blog.csdn.net/leleprogrammer/article/details/124205148?spm=1001.2014.3001.5501


我們需要用到隨機庫random,以及用來計算算法使用時間的time模塊

導入這些模塊

import random as rd
import time

我們定義一個函數

def createMaze(a,b): # a:width b:height

添加一個變量儲存算法開始的時間

startTime=time.time()

定義maze

maze={}

maze用來儲存迷宮地圖,格式如下:

{(n,"u"):0}

n表示第n個塊,u d l r分別表示上下左右的牆壁,0表示沒有牆壁,1表示有牆壁,初始是全部為1,生成的代碼如下:

 for n in range(a*b):
for face in ["u","d","l","r"]:
maze[(n,face)]=1

創建兩個變量

 history=[]
walls=[]

先初始隨機選一個塊並添加到遍歷過的方塊之中

block=rd.choice(list(maze.keys()))[0]
history.append(block)

將這個方塊的四個面的對應的牆都添加到候選牆的列表之中

 for face in ["u","d","l","r"]:
walls.append((block,face))

只要候選牆不為空就一直循環

while len(walls)!=0:

選擇一面牆,獲取這個牆壁分割開來的兩個塊,如果已經到達邊界外,則為None。注意,在最後一個elif之中,獲取len(maze)要除以4,因為我們每個塊有4個不同方向的牆壁,這個也是很容易疏忽的一點。

 wall=rd.choice(walls)
twoBlocks=[wall[0]]
faces=[wall[1]]
if wall[1]=="u":
if wall[0]-a<0:
twoBlocks.append(None)
else:
twoBlocks.append(wall[0]-a)
faces.append("d")
elif wall[1]=="r":
if (wall[0]+1)%a!=0:
twoBlocks.append(wall[0]+1)
faces.append("l")
else:
twoBlocks.append(None)
elif wall[1]=="l":
if wall[0]%a!=0:
twoBlocks.append(wall[0]-1)
faces.append("r")
else:
twoBlocks.append(None)
elif wall[1]=="d":
if wall[0]+a>len(maze)/4-1:
twoBlocks.append(None)
else:
twoBlocks.append(wall[0]+a)
faces.append("u")

再定義兩個列表

 ins=[]
infaces=[]

獲取這兩個方塊中有被添加到history的

 for i,oneBlock in enumerate(twoBlocks):
if oneBlock in history:
ins.append(oneBlock)
infaces.append(faces[i])

因為只有一個被遍歷過,所以我們就需要把這兩個塊中間的牆刪掉,其實這裡有兩面,一面是第一個塊的,另一個是第二個塊相反方向的,只是重疊了,我們需要把這兩面牆對應的值都設置為0,首先獲取mirrorFace,也就是相反的方向,如果None在這兩個方塊的列表之中,那麼就說明其中一個塊在邊上,所以就不需要再把這面牆刪掉,保留這面牆,直接從候選牆之中刪掉這面牆並開始新的循環,使用continue;如果他不是邊上的塊,也就是說twoBlocks裡面沒有None,就先把第一個塊的那面牆去掉(改為0),然後獲取另一個塊放在other變量中,再把這第二個塊的牆改為0,然後把這第二個塊添加到history中,然後將這第二個塊的四面牆都添加到候選牆中,注意,這裡要添加的牆的值必須是1,也就是沒有被檢查遍歷過的牆,如果候選牆已經有這面牆,就無需再添加,用for循環和if語句搭配,就可以簡簡單單寫出這段代碼,邏輯理清楚就不難寫啦!代碼如下:

 if len(ins)==1:
mirrorFace=None
if infaces[0]=="u":
mirrorFace="d"
elif infaces[0]=="d":
mirrorFace="u"
elif infaces[0]=="r":
mirrorFace="l"
elif infaces[0]=="l":
mirrorFace="r"
if not (None in twoBlocks):
maze[(ins[0],infaces[0])]=0
other=None
if ins[0]==twoBlocks[0]:
other=twoBlocks[1]
else:
other=twoBlocks[0]
maze[(other,mirrorFace)]=0
walls.remove(wall)
history.append(other)
for face in ["u","l","r","d"]:
if maze.get((other,face))==1 and not ((other,face) in walls):
walls.append((other,face))
else:
walls.remove(wall)
continue
elif len(ins)==2:
walls.remove(wall)

寫到這兒,我們的算法就差不多結束了,最後添加endTime獲取算法結束時間

endTime=time.time()

並將它輸出到控制台

print(f"生成迷宮使用時間:{endTime-startTime}秒")

返回迷宮

return maze

這個算法速度挺快的,99x99的迷宮只用了三秒多,一般三十多乘三十多的也只生成了30毫秒,效率很高!


下期預告:

下一篇文章,我們將要用Pygame將這個迷宮生成的全過程繪制出來,別忘了關注我,查看更多教學哦!


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved