吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2298|回复: 4
收起左侧

[Python 转载] Python练习——走迷宫

  [复制链接]
Pangpangyu 发表于 2021-7-22 11:52
迷宫地图是随机生成的,部分结果如下:
X@{}EOQESGP(RDPA~]H{0SO.png

下边是代码:
import random
import turtle
from random import randint, choice

CELL_SIZE = 16      # 设置用于绘制迷宫的单元格的尺寸
DOT_SIZE = 5          # 设置起点和终点的尺寸
LINE_SIZE = 3       # 设置探索路径的尺寸
scr = turtle.Screen()  # 建立屏幕对象 src
scr.colormode(255)  # 设置颜色模式为rgb数值模式
wallPen = turtle.Turtle()  # 建立画笔对象 wallPen 用于绘制墙体
pointPen = turtle.Turtle()  # 建立画笔对象 pointPen 用于绘制点
linePen = turtle.Turtle()  # 建立画笔对象 linePen 用于绘制探索路径
linePen.pensize(LINE_SIZE)  #设置画笔粗细为路径尺寸
difficulty=[15,25,45]

class CellType:
    ROAD = 0
    WALL = 1

# 墙的方向
class Direction:
    LEFT = 0,
    UP = 1,
    RIGHT = 2,
    DOWN = 3,

# 迷宫地图
class Maze:

    def __init__(self, width, height):
        self.width = width
        self.height = height
        #生成规定长宽的且内部元素全为0的二维表
        self.maze = [[0 for x in range(self.width)] for y in range(self.height)]

    def reset_maze(self, value):
        for y in range(self.height):
            for x in range(self.width):
                self.set_maze(x, y, value)

    def set_maze(self, x, y, value):
        self.maze[x][y] = CellType.ROAD if value == CellType.ROAD else CellType.WALL

    def visited(self, x, y):
        return self.maze[x][y] != 1

def check_neighbors(maze, x, y, width, height, checklist):
    directions = []
    #判断点的上下左右是否有邻居点
    if x > 0:
        if not maze.visited(2 * (x - 1) + 1, 2 * y + 1):
            directions.append(Direction.LEFT)
    if y > 0:
        if not maze.visited(2 * x + 1, 2 * (y - 1) + 1):
            directions.append(Direction.DOWN)
    if x < width - 1:
        if not maze.visited(2 * (x + 1) + 1, 2 * y + 1):
            directions.append(Direction.RIGHT)
    if y < height - 1:
        if not maze.visited(2 * x + 1, 2 * (y + 1) + 1):
            directions.append(Direction.UP)
    #对邻居点之间的墙进行拆墙并把新的添加到checklist中进行下一次的判断
    if len(directions):
        direction = choice(directions)
        if direction == Direction.LEFT:
            maze.set_maze(2 * (x - 1) + 1, 2 * y + 1, CellType.ROAD)
            maze.set_maze(2 * x, 2 * y + 1, CellType.ROAD)
            checklist.append((x - 1, y))
        elif direction == Direction.DOWN:
            maze.set_maze(2 * x + 1, 2 * (y - 1) + 1, CellType.ROAD)
            maze.set_maze(2 * x + 1, 2 * y, CellType.ROAD)
            checklist.append((x, y - 1))
        elif direction == Direction.RIGHT:
            maze.set_maze(2 * (x + 1) + 1, 2 * y + 1, CellType.ROAD)
            maze.set_maze(2 * x + 2, 2 * y + 1, CellType.ROAD)
            checklist.append((x + 1, y))
        elif direction == Direction.UP:
            maze.set_maze(2 * x + 1, 2 * (y + 1) + 1, CellType.ROAD)
            maze.set_maze(2 * x + 1, 2 * y + 2, CellType.ROAD)
            checklist.append((x, y + 1))
        return True
    return False

def random_prime(map, width, height):
    start_x, start_y = (randint(0, width - 1), randint(0, height - 1))
    #把二维表中所有下标x,y为奇数的元素设置为通路(即值为0)
    map.set_maze(2 * start_x + 1, 2 * start_y + 1, CellType.ROAD)
    checklist = [(start_x, start_y)]
    while len(checklist):
        #在通路中随机找到一个通路点位
        entry = choice(checklist)
        #判断该点位是否有邻居点位,若没有就移除该点位,之后不再参与搜索
        if not check_neighbors(map, entry[0], entry[1], width, height, checklist):
            checklist.remove(entry)

def do_random_prime(map):
    #把二维表中所有的元素都设置为墙(即值为1)
    map.reset_maze(CellType.WALL)
    random_prime(map, (map.width - 1) // 2, (map.height - 1) // 2)

def set_entrance_exit(maze):
    entrance = []
    for i in range(maze.height):
        #找到第一个maze[1] == 0的元素,并把maze[0]设置为通路(即值为0)
        if maze.maze[1] == 0:
            maze.set_maze(0, i, 0)
            entrance = [0, i]
            #把起点标记为A,方便后面对起点的填充
            maze.maze[0] = "A"
            break
    exit = []
    for i in range(maze.height - 1, 0, -1):
        # 找到第一个maze[maze.width -2] == 0的元素,并把maze[maze.width-1]设置为通路(即值为0)
        if maze.maze[maze.width - 2] == 0:
            maze.set_maze(maze.width - 1, i, 0)
            exit = [maze.width - 1, i]
            #把终点标记为B,方便后面对终点的填充
            maze.maze[maze.width - 1] = "B"
            break
    return entrance, exit

def generate_maze(width, height):
    # 初始化迷宫
    maze = Maze(width, height)
    # 生成地图
    do_random_prime(maze)
    # 选择起点和终点
    entrance, exit = set_entrance_exit(maze)
    # 返回地图
    return maze.maze, entrance, exit

#绘制墙体单元格
def draw_cell(y0, x0):
    # y0: 单元格所在列序号  x0: 单元格所在行序号
    #计算出单元格左上角的坐标
    tx = y0 * CELL_SIZE - L * CELL_SIZE / 2     #L-列序号  H-行序号
    ty = H * CELL_SIZE / 2 - x0 * CELL_SIZE
    wallPen.penup()  # 提起墙画笔
    #turtle.goto(x,y)       x负左移正右移,y负下移正上移
    wallPen.goto(tx, ty)  # 根据计算出来的坐标移动到单元格左上角
    wallPen.pendown()  # 放下画笔
    wallPen.begin_fill()  # 开启填充,此时经过的形状会被填充
    # 由单元格左上角开始绘制一个边长为CELL_SIZE的正方形
    for i in range(4):
        wallPen.fd(CELL_SIZE)       #向前走cell_size(单元格)像素
        wallPen.right(90)           #基于当前角度向右转90度
    wallPen.end_fill()  # 关闭填充

# 在单元格绘制圆点
def draw_dot(y0, x0, color="black"):
     # x0: 单元格所在行序号  y0: 单元格所在列序号    color: 圆点的颜色
    # 计算出单元格左上角的坐标
    tx = y0 * CELL_SIZE - L * CELL_SIZE / 2
    ty = H * CELL_SIZE / 2 - x0 * CELL_SIZE
    # 计算出所在单元格中心的坐标
    cx = tx + CELL_SIZE / 2
    cy = ty - CELL_SIZE / 2
    pointPen.penup()    #提起画笔

    pointPen.goto(cx, cy)       #根据计算出来的坐标移动到单元格中心
        #turtle.dot(r)绘制一个指定直径和颜色的圆点
    pointPen.dot(DOT_SIZE, color)       #绘制一个直径为DOT_SIZE和颜色为color的圆点

def draw_mazeMap(mazeMap):      #画迷宫
    scr.tracer(0)  # 跳过绘制动画
    for h in range(len(mazeMap)):      #  h,行号
        row = mazeMap[h]
        for l in range(len(row)):   # l,列号
            item = row[l]
            if item == CellType.WALL:
                draw_cell(l, h)         # 绘制具体的单元格
            elif item == "A":           # 设置起点颜色为红色
                draw_dot(l, h, "red")
            elif item == "B":              # 设置终点颜色为蓝色
                draw_dot(l, h, "blue")

# 绘制路径,以画笔当前所在位置为起点,以单元格(y0, x0)中心作为终点,绘制路径。
def draw_path(y0, x0, color="blue"):
    # 计算出单元格左上角的坐标
    tx = y0 * CELL_SIZE - L * CELL_SIZE / 2
    ty = H * CELL_SIZE / 2 - x0 * CELL_SIZE
    # 计算出所在单元格中心的坐标
    cx = tx + CELL_SIZE / 2
    cy = ty - CELL_SIZE / 2

    linePen.color(color)            #设置填充颜色为color(蓝色)
    linePen.goto(cx, cy)            #根据计算出来的坐标移动到单元格中心

def DFS(mazeMap,y0,x0):
    # 1,找到终点,探索完成,
    if [x0,y0] == exit:
        draw_path(y0, x0)
        return True
    # 2,找到墙或者试探过的点或者越界,试探失败,然后告诉上一步这一步试探是失败的
    if not (0 <= y0 < len(mazeMap) and 0 <= x0 < len(mazeMap)):
        return False
    if mazeMap[x0][y0] in [CellType.WALL, "#"]:
        return False

    mazeMap[x0][y0] = "#"           # 试探后标记该点为已试探过
    draw_path(y0, x0)               #填充路径

    # 右下左上四个探索的方向
    direction = [(0, 1),(0,-1),(1, 0),(-1, 0)]

    for d in direction:         #试探四个方向
        dx, dy = d
        found = DFS(mazeMap, y0 + dy, x0 + dx)
        if found:
        # 3,向某个方向的试探得出的结论是成功的,那么探索完成,不再试探,并且告诉上一步试探这一方向是能够试探成功的
            draw_path(y0, x0, "blue")                 #填充路径为蓝色
            return True
        else:
            # 4,向某个方向的试探得出的结论是失败的,那么换一个方向进行试探
            draw_path(y0, x0, "red")                #填充走过的错误路径为红色
    # 5,向所有方向试探都失败了,那么试探失败,并告诉上一步这一方向试探是失败的
    return False

#  开始迷宫探索
def find_path(mazeMap):
    # 获取起点所在行和列的序号
    starty, startx = 0, 0                    #  h,行号
    for h in range(len(mazeMap)):
        row = mazeMap[h]
        for l in range(len(row)):           # l,列号
            item = row[l]
            if item == "A":
                starty, startx = l, h
    linePen.penup()                 #提起路径画笔
    draw_path(starty, startx)       #填充路径
    linePen.pendown()               #放下路径画笔
    DFS(mazeMap, starty, startx)    #进入递归搜索

if __name__=="__main__":
    num=random.randint(0,2)
    t=difficulty[num]
    mazeMap, entrance, exit = generate_maze(t, t)
    H, L = len(mazeMap), len(mazeMap[0])        # 获取迷宫的长宽,H-行数,L-列数
    scr.setup(width=L * CELL_SIZE+20, height=H * CELL_SIZE+20)  # 设置屏幕尺寸大小,显示所有迷宫的单元格
    draw_mazeMap(mazeMap)       #绘制迷宫
    scr.tracer(8)           #绘制速度
    find_path(mazeMap)      #探索出路
    turtle.done()           # 防止绘制完窗口自动退出

免费评分

参与人数 3吾爱币 +3 热心值 +1 收起 理由
lua11 + 1 + 1 用心讨论,共获提升!
从零学习的歪经小 + 1 写的挺好的,不过不建议代码这样直接粘贴
拾捌壹. + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| Pangpangyu 发表于 2021-7-23 14:26
由于是第一次发帖,代码插入不够规范,之后我会慢慢注意,感谢指正!
xzzhjian 发表于 2021-8-17 11:56
linxizuiyan 发表于 2021-8-17 18:35
crlong33 发表于 2021-8-17 20:53
出个视频教程就iu完美了
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-25 14:44

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表