简易迷宫python

学习目标:


学习内容:

迷宫游戏是非常经典的游戏,在该题中要求随机生成一个迷宫,并求解迷宫;

要求查找并理解迷宫生成的算法,并尝试用两种不同的算法来生成随机的迷宫。

要求迷宫游戏支持玩家走迷宫,和系统走迷宫路径两种模式。玩家走迷宫,通过键盘方向键控         制,并在行走路径上留下痕迹;系统提示迷宫路径要求基于A*算法实现,输出玩家当前位置           到迷宫出口的最优路径。设计交互友好的游戏图形界面。


学习成果:

1.迷宫生成和求解的程序。

使用深度优先搜索算法来生成迷宫,并根据给定的起点和终点求解出迷宫的路径。

代码中的Point类表示迷宫中的一个点,具有行和列两个属性。copy()方法用于复制一个点。

代码最开始定义了一些变量和初始化工作,包括窗口大小、背景颜色等。然后定义了三个函数:lu_q()qi_l()xiangling()

lu_q()函数根据给定的点返回该点周围墙的位置。它遍历墙的列表,判断周围是否有墙与给定点相邻,如果有则将其加入到一个列表中并返回。

qi_l()函数根据给定的点返回该点周围路的位置。它遍历路的列表,判断周围是否有路与给定点相邻,如果有则将其加入到一个列表中并返回。

xiangling()函数根据给定的点返回该点周围路中距离最远的点。它遍历路的列表,判断周围是否有路与给定点相隔一个墙,如果有则将其加入到一个列表中。然后根据当前点在路列表中的位置,将该点从路列表中删除,并返回找到的点列表。

接下来是创建迷宫的过程。首先创建了墙的列表Qiang,该列表包含了迷宫内所有的墙。然后创建了路的列表lu,该列表包含了迷宫内所有的路。两个循环分别遍历每个位置,将符合条件的墙和路加入到对应的列表中。

然后根据一定的规则,将一些墙从墙列表中删除,以确保迷宫的连通性。处理完之后,定义了起点和路径列表,并将起点加入到路径列表和临时列表中。

2.实现迷宫的路径求解和绘制功能。

首先定义了目标点zhongdian和一个空列表lujin用于存储找到的路径。然后定义了变量x,并进入一个循环,循环条件是len(liebiao)不为0。

在每次循环中,使用random.randint(1, len(liebiao))随机选取一个索引值,将对应位置的点加入到路径列表lujing中。然后使用另一个循环遍历lujing列表中的点,并判断其相邻的点是否在路径列表lujing中。根据不同情况,将相邻点的位置添加到路径列表lujin中。最后调用xiangling()函数,获取与选取点距离最远的点,并将获取到的点列表拼接到liebiao列表末尾。

完成上述循环后,将路径列表lujin和之前生成的路径列表lujing拼接到迷宫路的列表lu中。

接下来,定义了一个函数rect()用于绘制迷宫地图的小方格。函数通过计算方格的左上角坐标和大小,调用pygame.draw.rect()方法绘制方格。

然后定义了函数rect2()用于绘制人物所在的位置。函数通过计算人物所在方格的左上角坐标,调用window.blit()方法绘制人物。

接下来定义了变量xx和yy用于表示人物的起始位置,以及空列表jilu_ren用于记录人物的移动轨迹。在迷宫中,人物的起始位置通常是(1, 1)。

最后,定义了函数Index()用于判断某个点是否在迷宫路径列表lu中。函数通过遍历路径列表,匹配行和列均相等的点,并返回布尔值。

这部分代码实现了求解迷宫路径和绘制迷宫地图、人物位置的功能。可能还有其他相关代码未包含在此处。

3.寻找最短路径的算法。

首先,定义了一个二维数组num,通过列表生成式初始化为全1的矩阵。然后,使用两个嵌套的循环遍历num中的每个元素,并通过Index函数判断是否为墙,如果是墙则将对应位置的元素设为0。接下来,定义了一个名为xunlu的函数,该函数实现了最短路径的寻找。在这个函数中,通过numpy库的mat函数将传入的列表转化为矩阵,然后定义了一系列辅助函数。在寻找最短路径的过程中,使用了A*算法,通过扩展节点、生成节点和回退节点的操作来逐步搜索到最短路径。最后,根据寻找结果将路径以及地图的状态进行打印输出。

在主循环中,使用了pygame库来可视化地展示寻找最短路径的过程。根据不同的按键事件,可以控制角色的移动以及选择不同的最短路径长度比例进行显示。


学习产出:

import pygame
import random
import numpy as np
import time



class Point:
    def __init__(self, row=0, col=0):
        self.row = row
        self.col = col

    def copy(self):
        return Point(self.row, self.col)

w = 707
h = 707
Row = 101
Col = 101

size = (w, h)
pygame.init()
window = pygame.display.set_mode(size)
pygame.display.set_caption("迷宫")
bak_color = (0, 0, 0)

showWindow = True
showjiesu = True
Shengli = False
clock = pygame.time.Clock()  # 时钟控制

#深度优先搜索
#整体思路是通过不断地将路径上的点加入到liebiao列表中,
#并利用lu_q()、qi_l()和xiangling()函数来扩展路径。
#路 内部循环墙列表
def lu_q(point):
    a = []
    for i in range(0, len(Qiang)):
        if point.col - 1 == Qiang[i].col and point.row == Qiang[i].row:
            a.append(Qiang[i])
        if point.col + 1 == Qiang[i].col and point.row == Qiang[i].row:
            a.append(Qiang[i])
        if point.col == Qiang[i].col and point.row - 1 == Qiang[i].row:
            a.append(Qiang[i])
        if point.col == Qiang[i].col and point.row + 1 == Qiang[i].row:
            a.append(Qiang[i])
    return a

#根据给定的点,返回其周围的路(lu)的位置。
def qi_l(point):
    a = []
    for i in range(0, len(lu)):
        if point.col - 1 == lu[i].col and point.row == lu[i].row:
            a.append(lu[i])
        if point.col + 1 == lu[i].col and point.row == lu[i].row:
            a.append(lu[i])
        if point.col == lu[i].col and point.row - 1 == lu[i].row:
            a.append(lu[i])
        if point.col == lu[i].col and point.row + 1 == lu[i].row:
            a.append(lu[i])
    return a

#根据给定的点,返回其周围的路(lu)中距离最远的点
def xiangling(point):
    global s
    a = []
    for i in range(0, len(lu)):
        if point.col - 2 == lu[i].col and point.row == lu[i].row:
            a.append(lu[i])
        if point.col + 2 == lu[i].col and point.row == lu[i].row:
            a.append(lu[i])
        if point.col == lu[i].col and point.row - 2 == lu[i].row:
            a.append(lu[i])
        if point.col == lu[i].col and point.row + 2 == lu[i].row:
            a.append(lu[i])
    for j in range(0, len(lu)):
        if point.col == lu[j].col and point.row == lu[j].row:
            s = j
    genghuan = []
    for i in range(0, len(a)):
        for j in liebiao:
            if a[i].col == j.col:
                if a[i].row == j.row:
                    genghuan.append(i)

    genghuan.sort(reverse=True)

    for i in genghuan:
        a.pop(i)
    if a != None:
        lu.pop(s)
    return a

Qiang = []
for i in range(1, Row - 1):
    for j in range(1, Col - 1):
        Qiang.append(Point(i, j))

lu = []
for i in range(1, Row, 2):
    for j in range(1, Col, 2):
        lu.append(Point(i, j))
lu2 = lu

genghuan = []
for i in range(0, len(Qiang)):
    for j in lu:
        if Qiang[i].col == j.col:
            if Qiang[i].row == j.row:
                genghuan.append(i)

genghuan.sort(reverse=True)

for i in genghuan:
    Qiang.pop(i)

qidian = Point(1, 1)
lujing = []
liebiao = []
liebiao.append(qidian)
lujing.append(qidian)

zhongdian = Point(Row - 2, Col - 2)
lujin = []
x = 0
while len(liebiao):
#for i in range(0,10):
    ran = random.randint(1, len(liebiao))
    lujing.append(liebiao[ran - 1])
    for i in range(0, len(lujing)):
        if lujing[i].row - 2 == lujing[x + 1].row and lujing[i].col == lujing[x + 1].col:
            lujin.append(Point(lujing[i].row - 1, lujing[i].col))
            break
        if lujing[i].row + 2 == lujing[x + 1].row and lujing[i].col == lujing[x + 1].col:
            lujin.append(Point(lujing[i].row + 1, lujing[i].col))
            break
        if lujing[i].row == lujing[x + 1].row and lujing[i].col - 2 == lujing[x + 1].col:
            lujin.append(Point(lujing[i].row, lujing[i].col - 1))
            break
        if lujing[i].row == lujing[x + 1].row and lujing[i].col + 2 == lujing[x + 1].col:
            lujin.append(Point(lujing[i].row, lujing[i].col + 1))
            break
        # lujin.append(Point(int((lujing[x].row+lujing[x+1].row)/2),int((lujing[x].col+lujing[x+1].col)/2)))
    guo = xiangling(liebiao[ran - 1])
    liebiao.pop(ran - 1)
    liebiao.extend(guo)
    x = x + 1
lu.extend(lujin)
lu.extend(lujing)

def rect(point, color):
    cell_width = w / Col
    cell_height = h / Row
    left = (point.col) * cell_width
    top = (point.row) * cell_height
    pygame.draw.rect(
        window, color,
        (left, top, cell_width, cell_height)
    )

# 传入一个Point类型的参数,用于绘制地图中的一个小方格(即一个单元格)。
# 变量xx和yy分别表示起始位置的行和列。
# renwu用于表示当前人物所在的位置,初始化为(1, 1),即地图左上角。
# jilu_ren用于记录人物的移动轨迹。
def rect2(point):
    cell_width = w / Col
    cell_height = h / Row
    left = point.col * cell_width
    top = point.row * cell_height
    # py.draw.rect(
    #     window, color,
    #     (left, top, cell_width, cell_height)
    # )
    window.blit(
        (left, top)
    )
xx = 1
yy = 1
renwu = Point(xx, yy)
jilu_ren = []
jilu_ren.append(renwu)

def Index(point):
    for i in range(0, len(lu)):
        if point.col == lu[i].col and point.row == lu[i].row:
            return True
    return False

# A*算法自动寻路
#寻找最短路径的算法实现。首先定义了一个二维列表num,表示地图中的每个位置的状态,1表示墙,0表示路。
#然后定义了一个函数xunlu用于进行路径搜索。在函数内部,通过广度优先搜索的方式逐步扩展节点,直到找到终点或无法再扩展节点为止
#搜索过程中使用了启发式函数来评估节点的优先级,并根据优先级选择下一个节点进行扩展。最终返回找到的最短路径。
num = [[1 for i in range(0, Row - 2)] for j in range(0, Col - 2)]
for i in range(0, Row - 2):
    for j in range(0, Col - 2):
        if Index(Point(i + 1, j + 1)):
            num[i][j] = 0

def xunlu(liebiao, qi, zhong):
    a = np.mat(liebiao)
    def gs(i, j):
        return abs(i - startx) + abs(j - starty)
    def h1(i, j):
        return 10 * (abs(i - endx) + abs(j - endy))
    def h2(i, j):
        return pow(i - endx, 2) + pow(j - endy, 2)
    print("地图为:(1表示墙,0表示路)")
    for l in range(len(a)):
        for m in range(a[0].size):
            print(a[l, m], end=' ')
        print('')
    print('')

    startx, starty = qi.row, qi.col
    endx, endy = zhong.row, zhong.col
    if a[startx - 1, starty - 1] == 1:
        print("起点%s位置为墙,最短路径寻找失败!" % ([startx, starty]))
    else:
        # 存储已扩展结点,即所有寻找的节点
        Close = [[startx, starty]]
        # 存储已生成节点,即最终走过的节点
        Opens = [[startx, starty]]
        # 存储未走的分叉节点
        crossings = []
        # 设置在原地图行走的路径值
        road = 100
        start = time.time()
        rows, cols = a.shape
        while True:
            # 判断最后走过的节点是否为终点
            if Close[-1] != [endx, endy]:
                Open = []
                # 减1得到数组下标值
                i, j = Close[-1][0] - 1, Close[-1][1] - 1
                # 对当前节点上下左右四个节点进行判断
                for ni, nj in [(i - 1, j), (i + 1, j), (i, j - 1), (i, j + 1)]:
                    if [ni + 1, nj + 1] not in Opens and 0 <= ni < rows and 0 <= nj < cols and a[ni, nj] == 0:
                        Open.append([ni + 1, nj + 1])
                # 将已走过的节点值修改为路径值,并将路径值加1
                a[i, j] = road
                road = road + 1
                if Open:
                    # 对所有扩展到的节点进行排序,reverse=True 结果从大到小,即尾部存储代价最小的节点
                    Open = sorted(Open, key=lambda x: gs(x[0], x[1]) + h2(x[0], x[1]), reverse=True)
                    Opens.extend(Open)
                    # 将代价最小的节点存储到 Close 表
                    Close.append(Open.pop())
                    # 如果 pop 后 Open 表不为空,说明存在岔路,将岔路存储到 crossings 中
                    if Open:
                        crossings.extend(Open)
                # 判断是否存在未走过的分叉节点
                elif crossings:
                    next_way = crossings.pop()
                    # 实现路径回退,循环条件为回退节点与分叉节点不相邻
                    while sum((np.array(Close[-1]) - np.array(next_way)) ** 2) != 1:
                        # 当一条路径寻找失败后,是否将该路径岔路后的部分恢复为原地图
                        # i, j = Close[-1]
                        # a[i-1, j-1] = 0
                        # 每次 while 循环路径值 road 减1,并弹出 Close 表中的节点
                        road -= 1
                        Close.pop()
                    # 将 crossings 中最后一个节点添加到 Close 表
                    Close.append(next_way)
                else:
                    print("最短路径寻找失败,失败位置为:%s,路径为:" % Close[-1])
                    break
            else:
                a[endx - 1, endy - 1] = road
                print("最短路径寻找成功,路径为:")
                break
        for r in range(rows):
            for c in range(cols):
                # 0表示format中第一个元素,>表示右对齐输出,4表示占四个字符
                print("{0: >4}".format(a[r, c]), end='')
            print('')
        end = time.time()
        print("\n扩展节点数为:%d, 生成节点数为:%d, 用时为 %.8f" % (len(Opens), len(Close), float(end - start)))

        print('Close表为:%s' % Close)
        print("点的移动轨迹为:")
        for k in range(len(Close)):
            print(Close[k], end='')
            if k < len(Close) - 1:
                print("-->", end='')
    luxian = []
    for i in range(0, len(Close)):
        luxian.append(Point(Close[i][0], Close[i][1]))
    return luxian
print(num)
xianlu = []
while showWindow:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            showWindow = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_UP and Index(Point(renwu.row - 1, renwu.col)):
                renwu.row -= 1
            elif event.key == pygame.K_DOWN and Index(Point(renwu.row + 1, renwu.col)):
                renwu.row += 1
            elif event.key == pygame.K_LEFT and Index(Point(renwu.row, renwu.col - 1)):
                renwu.col -= 1
            elif event.key == pygame.K_RIGHT and Index(Point(renwu.row, renwu.col + 1)):
                renwu.col += 1
            elif event.key == pygame.K_q:
                print(renwu.row)
                print(renwu.col)
                print(zhongdian.row)
                print(zhongdian.col)
            elif event.key == pygame.K_1:
                xianlu = []
                xianlu_1 = xunlu(num, renwu, zhongdian)
                xianlu = xianlu_1[0:int(len(xianlu_1) / 3)]
            elif event.key == pygame.K_2:
                xianlu = []
                xianlu_1 = xunlu(num, renwu, zhongdian)
                xianlu = xianlu_1[0:int(len(xianlu_1) / 3 * 2)]
            elif event.key == pygame.K_3:
                xianlu = []
                xianlu_1 = xunlu(num, renwu, zhongdian)
                xianlu = xianlu_1
    # jilu_ren.append(renwu)
    jilu_ren.insert(0, renwu.copy())
    if renwu.col == zhongdian.col and renwu.row == zhongdian.row:
        showWindow = False
        while showjiesu:
            pygame.display.flip()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    showjiesu = False
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_s :
                        showjiesu=False
    pygame.draw.rect(window, (200, 200, 200), (0, 0, w, h))
    for i in Qiang:
        rect(i, (200, 200, 200))
    for i in lujing:
        rect(i, (255, 255, 255,0))
    for i in lujin:
        rect(i, (255, 255, 255,0))
    for i in jilu_ren:
        rect(i,(110, 255, 110))
    for i in xianlu:
        rect(i, (200, 255, 200))

    rect(Point(1, 1), (0, 255, 255))
    rect(Point(Row - 2, Col - 2), (0, 0, 255))
    rect(renwu,(0,0,0))
    pygame.display.update()
    clock.tick(10000)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值