def initRoom(self):count =0roomCount =1while True:count +=1if count >300:breakif roomCount > self.roomNum:breakx = random.randint(1,self.width-1)y = random.randint(1,self.heigh-1)wd = random.randint(self.roomMin,self.roomMax)ht = random.randint(self.roomMin, self.roomMax)r1 =ceil(y - ht/2)r2 =ceil(y + ht/2)c1 =ceil(x - wd/2)c2 =ceil(x + wd/2)if r1 <1:r1 =1if r2 >= self.heigh -1:r2 = self.heigh -2if c1 <1:c1 =1if c2 >= self.width -1:c2 = self.width -2w = c2 - c1 +1h = r2 - r1 +1if h / w >=3 or w / h >=3: #保證房間不是細長的continuejudge = self.isValidRoom(r1,r2,c1,c2)if judge ==0:roomCount +=1self.room.append(Room(r1,r2,c1,c2))for i inrange(r1,r2):for j inrange(c1,c2):self.map[i,j]=1def isValidRoom(self,r1,r2,c1,c2):#檢測有無覆蓋for i inrange(r1,r2):for j inrange(c1,c2):if self.map[i,j]==1:return-1#檢測有無緊貼房間for i inrange(r1,r2):if self.map[i,c1-1]==1 or self.map[i,c2+1]==1:return2for i inrange(c1,c2):if self.map[r1-1,i]==1 or self.map[r2+1,i]==1:return2return0
看一下效果
生成墻壁
編寫initTile()生成包圍房間和通道的墻壁,直接貼代碼
def initTile(self):offset =[[-1,0],[0,-1],[1,0],[0,1],[-1,-1],[1,1],[1,-1],[-1,1]]for i inrange(self.heigh):for j inrange(self.width):if self.map[i,j]==0:tag =0for it in offset:if i+it[0]>= self.heigh or j+it[1]>= self.width or i+it[0]<0 or j+it[1]<0:continueif self.map[i+it[0],j+it[1]]!=3 and self.map[i+it[0],j+it[1]]!=4:tag += self.map[i+it[0],j+it[1]]if tag:self.map[i,j]=3
def aStar(self,p0,p1):open_list =[]close_list =[]offset =[[-1,0],[0,-1],[1,0],[0,1]]f = h =abs(p0[0]- p1[0])*10+abs(p0[1]- p1[1])*10g =0def isInClose(p):for it in close_list:if it.value[3]== p:return Truereturn Falsedef isInOpen(p):for it in open_list:if it.value[3]== p:return Truereturn Falsedef findFather(p):for it in close_list:if it.value[3]== p:return it.value[4]return[-1,-1]def findInOpen(p):for it in open_list:if it.value[3]== p:return itreturn Noneopen_list.append(Node([f,g,h,p0,[-1,-1]]))while open_list:#for it in open_list:# print(it.value)open_list.sort(key=(lambda x:x.value[0]))f_min = open_list[0]close_list.append(f_min)open_list.remove(f_min)for it in offset:p2 =[f_min.value[3][0]+it[0], f_min.value[3][1]+it[1]]if p2[0]== p1[0] and p2[1]== p1[1]:#找到close_list.append(Node([f,g,h,p2,f_min]))p_father = f_min.value[3]while True:self.map[p_father[0],p_father[1]]=2p_father =findFather(p_father)if p_father[0]==-1:breakself.map[p0[0], p0[1]]=4returnif p2[0]<0 or p2[0]>= self.heigh or p2[1]<0 or p2[1]>= self.width:continueif(self.map[p2[0],p2[1]]!=0 and self.map[p2[0],p2[1]]!=2 and self.map[p2[0],p2[1]]!=4) or isInClose(p2):continueh =abs(p2[0]- p1[0])*10+abs(p2[1]- p1[1])*10g = f_min.value[1]+10f = h + gif not isInOpen(p2):open_list.append(Node([f,g,h,p2,f_min.value[3]]))else:#比較最小的G 值temp =findInOpen(p2)if g < temp.value[1]:open_list.remove(temp)open_list.append(Node([f,g,h,p2,f_min.value[3]]))
效果
這樣,一個隨機房間的地牢就已經生成,貼上完整代碼
import random
import numpy as np
from math import ceilclassNode():def __init__(self, val=None):if val is None:val =[0,0,0,[-1,-1],[-1,-1]]self.value = valclassRoom():def __init__(self,r1,r2,c1,c2):w = c2 - c1h = r2 - r1self.width = wself.height = hself.cx = c1 +ceil(w/2)self.cy = r1 +ceil(h/2)self.xStart = c1self.xEnd = c2 -1self.yStart = r1self.yEnd = r2 -1def info(self):print('r1 c1 r2 c2: ',self.yStart,self.xStart,self.yEnd,self.xEnd)print('cx cy: ',self.cx,self.cy)print('width height: ',self.width,self.height)def randomTile(self):direction = random.randint(0,3)dir =[[0,1,-1,0],[1,0,0,-1],[1,0,0,self.height],[0,1,self.width,0]]x_off = random.randint(0,self.width-1)y_off = random.randint(0,self.height-1)x = self.xStart + x_off*dir[direction][0]+ dir[direction][2]y = self.yStart + y_off*dir[direction][1]+ dir[direction][3]if y ==0 or x ==0:return self.randomTile()else:return[y,x]classMap:def __init__(self):self.width =30self.heigh =30self.level =1self.roomNum =5#0 is null,1 is room,2 is path,3 is wall,4 is door,5 is up stair,6 is downstairself.map = np.zeros((self.width,self.heigh))self.roomMin =3self.roomMax =11self.room =[]self.door =[]self.initRoom()self.initTile()self.initPath()#self.initTile()#self.initDoor()def initRoom(self):count =0roomCount =1while True:count +=1if count >300:breakif roomCount > self.roomNum:breakx = random.randint(1,self.width-1)y = random.randint(1,self.heigh-1)wd = random.randint(self.roomMin,self.roomMax)if wd %2==0:wd +=1ht = random.randint(self.roomMin, self.roomMax)if ht %2==0:ht +=1r1 =ceil(y - ht/2)r2 =ceil(y + ht/2)c1 =ceil(x - wd/2)c2 =ceil(x + wd/2)if r1 <1:r1 =1if r2 >= self.heigh -1:r2 = self.heigh -2if c1 <1:c1 =1if c2 >= self.width -1:c2 = self.width -2w = c2 - c1 +1h = r2 - r1 +1if w ==0:continueif h ==0:continueif h / w >=3 or w / h >=3:continuejudge = self.isValidRoom(r1,r2,c1,c2)if judge ==0:roomCount +=1self.room.append(Room(r1,r2,c1,c2))for i inrange(r1,r2):for j inrange(c1,c2):self.map[i,j]=1def initPath(self):#初始化門rm = self.room.copy()whilelen(rm)>1:r1 = random.choice(rm)rm.remove(r1)r2 = random.choice(rm)rm.remove(r2)point0 = r1.randomTile()while point0[0]== self.heigh-1 or point0[1]== self.width-1:point0 = r1.randomTile()self.map[point0[0],point0[1]]=2self.door.append(point0)self.breakTile(point0)point1 = r2.randomTile()while point1[0]== self.heigh-1 or point1[1]== self.width-1:point1 = r2.randomTile()self.map[point1[0],point1[1]]=2self.breakTile(point1)self.door.append(point1)rn = random.randint(0,1)#a*算法尋找從point0到point1的路徑self.aStar(point0,point1)if rn ==0:rm.append(r1)else:rm.append(r2)def initDoor(self):for it in self.door:self.map[it[0],it[1]]=4def breakTile(self,p):# 打通堵住的周圍的墻壁if self.map[p[0]-1, p[1]]==1 and self.map[p[0]+1, p[1]]==3:self.map[p[0]+1, p[1]]=2elif self.map[p[0], p[1]-1]==1 and self.map[p[0], p[1]+1]==3:self.map[p[0], p[1]+1]=2elif self.map[p[0]+1, p[1]]==1 and self.map[p[0]-1, p[1]]==3:self.map[p[0]-1, p[1]]=2elif self.map[p[0], p[1]+1]==1 and self.map[p[0], p[1]-1]==3:self.map[p[0], p[1]-1]=2def initTile(self):offset =[[-1,0],[0,-1],[1,0],[0,1],[-1,-1],[1,1],[1,-1],[-1,1]]for i inrange(self.heigh):for j inrange(self.width):if self.map[i,j]==0:tag =0for it in offset:if i+it[0]>= self.heigh or j+it[1]>= self.width or i+it[0]<0 or j+it[1]<0:continueif self.map[i+it[0],j+it[1]]!=3 and self.map[i+it[0],j+it[1]]!=4:tag += self.map[i+it[0],j+it[1]]if tag:self.map[i,j]=3def isValidRoom(self,r1,r2,c1,c2):#檢測有無覆蓋for i inrange(r1,r2):for j inrange(c1,c2):if self.map[i,j]==1:return-1#檢測有無緊貼房間for i inrange(r1,r2):if self.map[i,c1-1]==1 or self.map[i,c2+1]==1:return2for i inrange(c1,c2):if self.map[r1-1,i]==1 or self.map[r2+1,i]==1:return2return0def aStar(self,p0,p1):open_list =[]close_list =[]offset =[[-1,0],[0,-1],[1,0],[0,1]]f = h =abs(p0[0]- p1[0])*10+abs(p0[1]- p1[1])*10g =0def isInClose(p):for it in close_list:if it.value[3]== p:return Truereturn Falsedef isInOpen(p):for it in open_list:if it.value[3]== p:return Truereturn Falsedef findFather(p):for it in close_list:if it.value[3]== p:return it.value[4]return[-1,-1]def findInOpen(p):for it in open_list:if it.value[3]== p:return itreturn Noneopen_list.append(Node([f,g,h,p0,[-1,-1]]))while open_list:#for it in open_list:# print(it.value)open_list.sort(key=(lambda x:x.value[0]))f_min = open_list[0]close_list.append(f_min)open_list.remove(f_min)for it in offset:p2 =[f_min.value[3][0]+it[0], f_min.value[3][1]+it[1]]if p2[0]== p1[0] and p2[1]== p1[1]:#找到close_list.append(Node([f,g,h,p2,f_min]))p_father = f_min.value[3]while True:self.map[p_father[0],p_father[1]]=2p_father =findFather(p_father)if p_father[0]==-1:breakself.map[p0[0], p0[1]]=4returnif p2[0]<0 or p2[0]>= self.heigh or p2[1]<0 or p2[1]>= self.width:continueif(self.map[p2[0],p2[1]]!=0 and self.map[p2[0],p2[1]]!=2 and self.map[p2[0],p2[1]]!=4) or isInClose(p2):continueh =abs(p2[0]- p1[0])*10+abs(p2[1]- p1[1])*10g = f_min.value[1]+10f = h + gif not isInOpen(p2):open_list.append(Node([f,g,h,p2,f_min.value[3]]))else:#比較最小的G 值temp =findInOpen(p2)if g < temp.value[1]:open_list.remove(temp)open_list.append(Node([f,g,h,p2,f_min.value[3]]))def printMap(self):for i inrange(self.heigh):for j inrange(self.width):print(int(self.map[i,j]),end='')print()def printRoom(self):for r in self.room:r.info()if __name__ =='__main__':map =Map()map.printMap()