pygame从入门到放弃(下)--迷宫游戏随机迷宫生成算法

先上资源,图片资源,源代码及打包成的exe文件:

链接:https://pan.baidu.com/s/1ZjcOdeEVbBKlAn5M6UgaUA 
提取码:wnmq 

资源说明:game_test2_algorithm.py为纯算法调用,而game_test2.py则加上了游戏部分,

注:若解压game_test2.rar生成带exe的文件可以直接玩,但是进入的时候会很卡,占用内存,具体原因后文有介绍

上一篇pygame从入门到放弃(上)--构建沙雕迷宫游戏链接:https://blog.csdn.net/qq_36187544/article/details/87442425

上次写了一个沙雕迷宫游戏,这次为了让游戏具有随机性,写了些算法生成一个随机的迷宫,先接上次的说明一下,迷宫体现为一个10×10的矩阵,比如:

[0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
[0, 1, 1, 1, 0, 1, 1, 1, 1, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
[0, 1, 1, 1, 0, 1, 1, 0, 1, 0],
[0, 1, 0, 0, 0, 1, 1, 1, 1, 0],
[0, 1, 0, 1, 1, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 1, 0, 1, 1, 1, 1],
[0, 1, 0, 1, 1, 0, 0, 0, 0, 1],
[0, 1, 0, 1, 1, 0, 1, 1, 1, 1],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]

0表示可以走,1表示墙壁,允许上下左右行走,不能斜着,上一次构建好的迷宫就相当于实现了将这样一个矩阵具象为一个迷宫游戏,所以这次的算法实际上就是生成一个有连通路径的10×10矩阵

算法的大致核心是:随机生成0,1生成一个矩阵,然后判断矩阵是否有连通路径从[0,0]到[9,9],若没有再随机生成,再判断,直到成功。

于是干了好几个小时终于把代码码出来了,BUG排除完成。一测试,惊了,因为是随机生成矩阵,概率过低,导致生成矩阵的时间特别长,如下,运气不好几万次、几十万次才能生成合格的迷宫,运气好点数量级少一点。所以游戏运行时,开始会卡顿,因为在计算生成新迷宫。。。

后来想想,这样一个算法好像并不值得,不如人工写几十个合格的迷宫矩阵,放在源程序中,进入游戏时做一个random即可,这样运行时间还会即为加快。想起以前写过的AI象棋,从着棋分析进行算法评判时时间长、效果差,反而是记录了棋盘大数据的直接读取文档速度还很快,这就是大数据的优势吧。

算法部分的源代码(生成合格矩阵的源代码),因为加上游戏部分的代码就太长了,如果需要全部代码,请上文章开头提供的百度云盘下载,代码尽量加了说明注释,但是详细解释流程思想太冗杂,见谅见谅:

import random

# 定义迷宫的二维list,0为可走为空,1为填充砖块处
background_group = [
    [0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
    [0, 1, 1, 1, 0, 1, 1, 1, 1, 0],
    [0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
    [0, 1, 1, 1, 0, 1, 1, 0, 1, 0],
    [0, 1, 0, 0, 0, 1, 1, 1, 1, 0],
    [0, 1, 0, 1, 1, 0, 0, 0, 0, 0],
    [0, 1, 0, 1, 1, 0, 1, 1, 1, 1],
    [0, 1, 0, 1, 1, 0, 0, 0, 0, 1],
    [0, 1, 0, 1, 1, 0, 1, 1, 1, 1],
    [0, 0, 0, 0, 1, 0, 0, 0, 0, 0]]

# 算法生成随机迷宫
ready = False  # 判断迷宫是否生成成功

# 判断是否有重复元素,path_group是记录上下左右(对应0123)的List,通过该方法判断该list对应的走法是否会重复,比如环状
def isAgain(path_group):
    i = 0
    j = 0
    path_point_group = [[0, 0]]  # 用于记录详细的点的坐标
    for n in range(len(path_group)):
        if path_group[n] == 0:
            i -= 1
        if path_group[n] == 1:
            j -= 1
        if path_group[n] == 2:
            i += 1
        if path_group[n] == 3:
            j += 1

        for nn in range(len(path_point_group)):
            if path_point_group[nn][0] == i and  path_point_group[nn][1] == j:
                return True
        path_point_group.append([i, j])
    return False

count_while = 0     # 记录循环重复了多少次
while True:
    break_flag = False      # 后面有一个for循环判断是否生成了2×2的方形区域全是0,这种形式将导致严重错误,若生成了则直接重新循环
    # 随机生成矩阵
    for i in range(10):
        for j in range(10):
            background_group[i][j] = random.randint(0, 1)
    background_group[0][0] = 0
    background_group[9][9] = 0
    # 判断是否生成了2×2的方形区域全是0
    for i in range(9):
        for j in range(9):
            if background_group[i][j] == 0 and background_group[i+1][j] == 0 and background_group[i+1][j+1] == 0 and background_group[i][j+1] == 0:
                break_flag = True
    # 2×2的方形区域全是0则直接重新循环
    if break_flag:
        continue
    count_while += 1
    print("这是第"+str(count_while)+"次")
    for n in range(10):
        print(background_group[n])
    x = 0
    y = 0
    path_group_record = []  # 记录路径list历史记录,因为是先读取一条路径到头然后再返回,所以需要记录历史记录
    path_group = []  # 记录路径list
    # 这个while生成第一条路径(即沿着一条路走到末尾即停,不考虑分叉)
    while True:
        # 到达终点则停止循环
        if x == 9 and y == 9:
            ready = True
            break
        # print(str(x)+','+str(y))
        '''接下来多行意义在于
        模拟移动,首先判断是否超出界限,若没有,则判断当前是否有路可走,判断是否形成回路,有路可走则记录'''
        x -= 1
        if x < 0:
            x += 1
        else:
            if background_group[x][y] == 0:
                path_group.append(0)
                if isAgain(path_group):
                    path_group.pop(-1)
                    x += 1
                else:
                    continue
            else:
                x += 1

        y -= 1
        if y < 0:
            y += 1
        else:
            if background_group[x][y] == 0:
                path_group.append(1)
                if isAgain(path_group):
                    path_group.pop(-1)
                    y += 1
                else:
                    continue
            else:
                y += 1

        x += 1
        if x > 9:
            x -= 1
        else:
            if background_group[x][y] == 0:
                path_group.append(2)
                if isAgain(path_group):
                    path_group.pop(-1)
                    x -= 1
                else:
                    continue
            else:
                x -= 1

        y += 1
        if y > 9:
            y -= 1
        else:
            if background_group[x][y] == 0:
                path_group.append(3)
                if isAgain(path_group):
                    path_group.pop(-1)
                    y -= 1
                else:
                    continue
            else:
                y -= 1

        # 用path_group_record记录历史数据,而path_group之后可以随时改动
        for n in range(len(path_group)):
            path_group_record.append(path_group[n])

        break

    # 利用上一个while生成的第一条路径,搜索分叉路径,判断当前迷宫矩阵是否有路通向终点
    while True:
        if x == 9 and y == 9:
            ready = True
            break
        # 当path_group长度为0时,则认为所有分叉都走不到终点,break循环再生成下一个迷宫等
        if len(path_group) == 0:
            break
        # print(path_group_record)
        # print(path_group)
        # print("second:"+str(x)+","+str(y))

        if len(path_group_record) > len(path_group):       # 当记录的路径长度大于当前路径时才执行后续
            # 做一个说明,为了防止走记录过的重复的路径(上下左右对应了0123),所以新路径的数值不允许比记录低,这样保证了不会重复
            if path_group_record[len(path_group)] < 0:
                x -= 1
                if x < 0:
                    x += 1
                else:
                    if background_group[x][y] == 0:
                        path_group.append(0)
                        path_group_record[len(path_group) - 1] = 0
                        if isAgain(path_group):
                            path_group.pop(-1)
                            x += 1
                        else:
                            continue
                    else:
                        x += 1
            if path_group_record[len(path_group)] < 1:
                y -= 1
                if y < 0:
                    y += 1
                else:
                    if background_group[x][y] == 0:
                        path_group.append(1)
                        path_group_record[len(path_group)-1] = 1
                        if isAgain(path_group):
                            path_group.pop(-1)
                            y += 1
                        else:
                            continue
                    else:
                        y += 1
            if path_group_record[len(path_group)] < 2:
                x += 1
                if x > 9:
                    x -= 1
                else:
                    if background_group[x][y] == 0:
                        path_group.append(2)
                        path_group_record[len(path_group) - 1] = 2
                        if isAgain(path_group):
                            path_group.pop(-1)
                            x -= 1
                        else:
                            continue
                    else:
                        x -= 1
            if path_group_record[len(path_group)] < 3:
                y += 1
                if y > 9:
                    y -= 1
                else:
                    if background_group[x][y] == 0:
                        path_group.append(3)
                        path_group_record[len(path_group) - 1] = 3
                        if isAgain(path_group):
                            path_group.pop(-1)
                            y -= 1
                        else:
                            continue
                    else:
                        y -= 1

        # 这一对If...elif判断是为了回退,比如从[0,0]位置走到了[1,0]位置,path_group记录为[2](即向下),想回到[0,0]则做判断
        if path_group_record[len(path_group)-1] == 0:
            x += 1
            path_group.pop(-1)
        elif path_group_record[len(path_group)-1] == 1:
            y += 1
            path_group.pop(-1)
        elif path_group_record[len(path_group)-1] == 2:
            x -= 1
            path_group.pop(-1)
        elif path_group_record[len(path_group)-1] == 3:
            y -= 1
            path_group.pop(-1)
            continue

    if ready:
        break

猜你喜欢

转载自blog.csdn.net/qq_36187544/article/details/87613346
今日推荐