python实现地牢迷宫生成的完整步骤

目录
  • 基本属性
  • 生成房间
  • 生成墙壁
  • 生成门口
  • 生成通道
  • 总结

基本属性

定义当前地牢的等级,地图长宽,房间数量,房间的最小最大长度,如下

class Map:
    def __init__(self):
        self.width = 30
        self.heigh = 30
        self.level = 1
        self.roomNum = 5
        self.map = np.zeros((self.heigh,self.width))
        self.roomMin = 3
        self.roomMax = 11

生成房间

编写initRoom()随机生成房间,限制最多循环次数,为了简单起见,先做一个不会重叠的房间。基本思路是:随机房间的中心点,随机房间的长宽,再进行判断房间有无重叠(在后续会生成通道,简单起见在这里也保证房间不会紧贴),若无重叠,房间有效,房间数加1。贴代码

    def initRoom(self):
        count = 0
        roomCount = 1
        while True:
            count += 1
            if count > 300:
                break
            if roomCount > self.roomNum:
                break
            x = 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 = 1
            if r2 >= self.heigh - 1:
                r2 = self.heigh - 2
            if c1 < 1:
                c1 = 1
            if c2 >= self.width - 1:
                c2 = self.width - 2
            w = c2 - c1 + 1
            h = r2 - r1 + 1
            if h / w >= 3 or w / h >= 3: #保证房间不是细长的
                continue
            judge = self.isValidRoom(r1,r2,c1,c2)
            if judge == 0:
                roomCount += 1
                self.room.append(Room(r1,r2,c1,c2))
                for i in range(r1,r2):
                    for j in range(c1,c2):
                        self.map[i,j] = 1

    def isValidRoom(self,r1,r2,c1,c2):
        #检测有无覆盖
        for i in range(r1,r2):
            for j in range(c1,c2):
                if self.map[i,j] == 1:
                    return -1
        #检测有无紧贴房间
        for i in range(r1,r2):
            if self.map[i,c1-1] == 1 or self.map[i,c2+1] == 1:
                return 2
        for i in range(c1,c2):
            if self.map[r1-1,i] == 1 or self.map[r2+1,i] == 1:
                return 2
        return 0

看一下效果

生成墙壁

编写initTile()生成包围房间和通道的墙壁,直接贴代码

    def initTile(self):
        offset = [[-1,0],[0,-1],[1,0],[0,1],[-1,-1],[1,1],[1,-1],[-1,1]]
        for i in range(self.heigh):
            for j in range(self.width):
                if self.map[i,j] == 0:
                    tag = 0
                    for 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:
                            continue
                        if 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

效果

生成门口

随机选取房间的一个外围点当做房门,思路是在房间的长宽内随机两个数作为偏移量,预定义好四个方向的覆盖模板对偏移量进行加权和偏置,在这里我编写房间的类,加进地图的属性列表里。

除此之外,房间连通的思路是:在所有房间列表中随机抽出两个房间,将这两个房间连通,再随机选一个房间加回原来的房间列表,直至最后列表里只剩下一个房间。那么现在先来生成房门,代码如下

class Room():
    def __init__(self,r1,r2,c1,c2):
        w = c2 - c1
        h = r2 - r1
        self.width = w
        self.height = h
        self.cx = c1 + ceil(w/2)
        self.cy = r1 + ceil(h/2)
        self.xStart = c1
        self.xEnd = c2 - 1
        self.yStart = r1
        self.yEnd = r2 - 1

    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]
class Map:
    def initPath(self):
        #初始化门
        rm = self.room.copy()
        while len(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]] = 2
            self.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]] = 2
            self.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 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]] = 2
        elif self.map[p[0], p[1] - 1] == 1 and self.map[p[0], p[1] + 1] == 3:
            self.map[p[0], p[1] + 1] = 2
        elif self.map[p[0] + 1, p[1]] == 1 and self.map[p[0] - 1, p[1]] == 3:
            self.map[p[0] - 1, p[1]] = 2
        elif self.map[p[0], p[1] + 1] == 1 and self.map[p[0], p[1] - 1] == 3:
            self.map[p[0], p[1] - 1] = 2

看下效果

生成通道

接着完善上述函数,在随机选取房门后,连接两个房门。

在这我选择的是A星算法,打通两个房门,直接上代码

    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]) * 10
        g = 0

        def isInClose(p):
            for it in close_list:
                if it.value[3] == p:
                    return True
            return False
        def isInOpen(p):
            for it in open_list:
                if it.value[3] == p:
                    return True
            return False
        def 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 it
            return None

        open_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]] = 2
                        p_father = findFather(p_father)
                        if p_father[0] == -1:
                            break
                    self.map[p0[0], p0[1]] = 4
                    return
                if p2[0] < 0 or p2[0] >= self.heigh or p2[1] < 0 or p2[1] >= self.width:
                    continue
                if (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):
                    continue
                h = abs(p2[0] - p1[0]) * 10 + abs(p2[1] - p1[1]) * 10
                g = f_min.value[1] + 10
                f = h + g
                if 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 ceil

class Node():
    def __init__(self, val=None):
        if val is None:
            val = [0, 0, 0, [-1, -1], [-1, -1]]
        self.value = val

class Room():
    def __init__(self,r1,r2,c1,c2):
        w = c2 - c1
        h = r2 - r1
        self.width = w
        self.height = h
        self.cx = c1 + ceil(w/2)
        self.cy = r1 + ceil(h/2)
        self.xStart = c1
        self.xEnd = c2 - 1
        self.yStart = r1
        self.yEnd = r2 - 1

    def 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]

class Map:
    def __init__(self):
        self.width = 30
        self.heigh = 30
        self.level = 1
        self.roomNum = 5
        #0 is null, 1 is room, 2 is path, 3 is wall, 4 is door, 5 is up stair, 6 is downstair
        self.map = np.zeros((self.width,self.heigh))
        self.roomMin = 3
        self.roomMax = 11
        self.room = []
        self.door = []

        self.initRoom()
        self.initTile()
        self.initPath()
        #self.initTile()
        #self.initDoor()

    def initRoom(self):
        count = 0
        roomCount = 1
        while True:
            count += 1
            if count > 300:
                break
            if roomCount > self.roomNum:
                break
            x = 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 += 1
            ht = random.randint(self.roomMin, self.roomMax)
            if ht % 2 == 0:
                ht += 1
            r1 = ceil(y - ht/2)
            r2 = ceil(y + ht/2)
            c1 = ceil(x - wd/2)
            c2 = ceil(x + wd/2)
            if r1 < 1:
                r1 = 1
            if r2 >= self.heigh - 1:
                r2 = self.heigh - 2
            if c1 < 1:
                c1 = 1
            if c2 >= self.width - 1:
                c2 = self.width - 2
            w = c2 - c1 + 1
            h = r2 - r1 + 1
            if w == 0:
                continue
            if h == 0:
                continue
            if h / w >= 3 or w / h >= 3:
                continue
            judge = self.isValidRoom(r1,r2,c1,c2)
            if judge == 0:
                roomCount += 1
                self.room.append(Room(r1,r2,c1,c2))
                for i in range(r1,r2):
                    for j in range(c1,c2):
                        self.map[i,j] = 1

    def initPath(self):
        #初始化门
        rm = self.room.copy()
        while len(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]] = 2
            self.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]] = 2
            self.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]] = 4

    def 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]] = 2
        elif self.map[p[0], p[1] - 1] == 1 and self.map[p[0], p[1] + 1] == 3:
            self.map[p[0], p[1] + 1] = 2
        elif self.map[p[0] + 1, p[1]] == 1 and self.map[p[0] - 1, p[1]] == 3:
            self.map[p[0] - 1, p[1]] = 2
        elif self.map[p[0], p[1] + 1] == 1 and self.map[p[0], p[1] - 1] == 3:
            self.map[p[0], p[1] - 1] = 2

    def initTile(self):
        offset = [[-1,0],[0,-1],[1,0],[0,1],[-1,-1],[1,1],[1,-1],[-1,1]]
        for i in range(self.heigh):
            for j in range(self.width):
                if self.map[i,j] == 0:
                    tag = 0
                    for 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:
                            continue
                        if 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 isValidRoom(self,r1,r2,c1,c2):
        #检测有无覆盖
        for i in range(r1,r2):
            for j in range(c1,c2):
                if self.map[i,j] == 1:
                    return -1
        #检测有无紧贴房间
        for i in range(r1,r2):
            if self.map[i,c1-1] == 1 or self.map[i,c2+1] == 1:
                return 2
        for i in range(c1,c2):
            if self.map[r1-1,i] == 1 or self.map[r2+1,i] == 1:
                return 2
        return 0

    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]) * 10
        g = 0

        def isInClose(p):
            for it in close_list:
                if it.value[3] == p:
                    return True
            return False
        def isInOpen(p):
            for it in open_list:
                if it.value[3] == p:
                    return True
            return False
        def 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 it
            return None

        open_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]] = 2
                        p_father = findFather(p_father)
                        if p_father[0] == -1:
                            break
                    self.map[p0[0], p0[1]] = 4
                    return
                if p2[0] < 0 or p2[0] >= self.heigh or p2[1] < 0 or p2[1] >= self.width:
                    continue
                if (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):
                    continue
                h = abs(p2[0] - p1[0]) * 10 + abs(p2[1] - p1[1]) * 10
                g = f_min.value[1] + 10
                f = h + g
                if 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 in range(self.heigh):
            for j in range(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()

可视化一下

总结

到此这篇关于python实现地牢迷宫生成的文章就介绍到这了,更多相关python地牢迷宫生成内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 一道python走迷宫算法题

    前几天逛博客时看到了这样一道问题,感觉比较有趣,就自己思考了下方案顺便用python实现了一下.题目如下: 用一个二维数组表示一个简单的迷宫,用0表示通路,用1表示阻断,老鼠在每个点上可以移动相邻的东南西北四个点,设计一个算法,模拟老鼠走迷宫,找到从入口到出口的一条路径. 如图所示: 先说下我的思路吧: 1.首先用一个列表source存储迷宫图,一个列表route_stack存储路线图,一个列表route_history存储走过的点,起点(0,0),终点(4,4). 2.老鼠在每个点都有上下左右

  • Python基于分水岭算法解决走迷宫游戏示例

    本文实例讲述了Python基于分水岭算法解决走迷宫游戏.分享给大家供大家参考,具体如下: #Solving maze with morphological transformation """ usage:Solving maze with morphological transformation needed module:cv2/numpy/sys ref: 1.http://www.mazegenerator.net/ 2.http://blog.leanote.com

  • Python基于递归算法实现的走迷宫问题

    本文实例讲述了Python基于递归算法实现的走迷宫问题.分享给大家供大家参考,具体如下: 什么是递归? 简单地理解就是函数调用自身的过程就称之为递归. 什么时候用到递归? 如果一个问题可以表示为更小规模的迭代运算,就可以使用递归算法. 迷宫问题:一个由0或1构成的二维数组中,假设1是可以移动到的点,0是不能移动到的点,如何从数组中间一个值为1的点出发,每一只能朝上下左右四个方向移动一个单位,当移动到二维数组的边缘,即可得到问题的解,类似的问题都可以称为迷宫问题. 在python中可以使用list

  • python实现的生成随机迷宫算法核心代码分享(含游戏完整代码)

    完整代码下载:http://xiazai.jb51.net/201407/tools/python-migong.rar 最近研究了下迷宫的生成算法,然后做了个简单的在线迷宫游戏.游戏地址和对应的开源项目地址可以通过上面的链接找到.开源项目中没有包含服务端的代码,因为服务端的代码实在太简单了.下面将简单的介绍下随机迷宫的生成算法.一旦理解后你会发现这个算法到底有多简单. 1.将迷宫地图分成多个房间,每个房间都有四面墙. 2.让"人"从地图任意一点A出发,开始在迷宫里游荡.从A房间的1/

  • Python使用Tkinter实现机器人走迷宫

    这本是课程的一个作业研究搜索算法,当时研究了一下Tkinter,然后写了个很简单的机器人走迷宫的界面,并且使用了各种搜索算法来进行搜索,如下图: 使用A*寻找最优路径: 由于时间关系,不分析了,我自己贴代码吧.希望对一些也要用Tkinter的人有帮助. from Tkinter import * from random import * import time import numpy as np import util class Directions: NORTH = 'North' SOU

  • Python解决走迷宫问题算法示例

    本文实例讲述了Python解决走迷宫问题算法.分享给大家供大家参考,具体如下: 问题: 输入n * m 的二维数组 表示一个迷宫 数字0表示障碍 1表示能通行 移动到相邻单元格用1步 思路: 深度优先遍历,到达每一个点,记录从起点到达每一个点的最短步数 初始化案例: 1   1   0   1   1 1   0   1   1   1 1   0   1   0   0 1   0   1   1   1 1   1   1   0   1 1   1   1   1   1 1 把图周围加上

  • Python深度优先算法生成迷宫

    本文实例为大家分享了Python深度优先算法生成迷宫,供大家参考,具体内容如下 import random #warning: x and y confusing sx = 10 sy = 10 dfs = [[0 for col in range(sx)] for row in range(sy)] maze = [[' ' for col in range(2*sx+1)] for row in range(2*sy+1)] #1:up 2:down 3:left 4:right opera

  • Python使用回溯法子集树模板解决迷宫问题示例

    本文实例讲述了Python使用回溯法解决迷宫问题.分享给大家供大家参考,具体如下: 问题 给定一个迷宫,入口已知.问是否有路径从入口到出口,若有则输出一条这样的路径.注意移动可以从上.下.左.右.上左.上右.下左.下右八个方向进行.迷宫输入0表示可走,输入1表示墙.为方便起见,用1将迷宫围起来避免边界问题. 分析 考虑到左.右是相对的,因此修改为:北.东北.东.东南.南.西南.西.西北八个方向.在任意一格内,有8个方向可以选择,亦即8种状态可选.因此从入口格子开始,每进入一格都要遍历这8种状态.

  • Python 实现递归法解决迷宫问题的示例代码

    迷宫问题 问题描述: 迷宫可用方阵 [m, n] 表示,0 表示可通过,1 表示不能通过.若要求左上角 (0, 0) 进入,设计算法寻求一条能从右下角 (m-1, n-1) 出去的路径. 示例图: 此示例图基本参数为: m:对应 x 轴n:对应 y 轴 绿色线代表期望输出的路径 算法思路 标记当前所在位置 如果此时所在位置为终点,说明可以到达终点,退出递归: 否则,则存在 4 种可能的移动方向即上.下.左.右,遍历这 4 个方向,如果这 4 个方向存在相邻值为 0 的点,则将当前点坐标标记为该相

  • 用Python代码来解图片迷宫的方法整理

    译注:原文是StackOverflow上一个如何用程序读取迷宫图片并求解的问题,几位参与者热烈地讨论并给出了自己的代码,涉及到用Python对图片的处理以及广度优先(BFS)算法等. 问题by Whymarrh: 当给定上面那样一张JPEG图片,如何才能更好地将这张图转换为合适的数据结构并且解出这个迷宫? 我的第一直觉是将这张图按像素逐个读入,并存储在一个包含布尔类型元素的列表或数组中,其中True代表白色像素,False代表非白色像素(或彩色可以被处理成二值图像).但是这种做法存在一个问题,那

随机推荐