Pangpangyu 发表于 2021-7-22 11:52

Python练习——走迷宫

迷宫地图是随机生成的,部分结果如下:


下边是代码:
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=

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 = [ 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 = CellType.ROAD if value == CellType.ROAD else CellType.WALL

    def visited(self, x, y):
      return self.maze != 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, entry, 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 == 0的元素,并把maze设置为通路(即值为0)
      if maze.maze == 0:
            maze.set_maze(0, i, 0)
            entrance =
            #把起点标记为A,方便后面对起点的填充
            maze.maze = "A"
            break
    exit = []
    for i in range(maze.height - 1, 0, -1):
      # 找到第一个maze == 0的元素,并把maze设置为通路(即值为0)
      if maze.maze == 0:
            maze.set_maze(maze.width - 1, i, 0)
            exit =
            #把终点标记为B,方便后面对终点的填充
            maze.maze = "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
      for l in range(len(row)):   # l,列号
            item = row
            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 == exit:
      draw_path(y0, x0)
      return True
    # 2,找到墙或者试探过的点或者越界,试探失败,然后告诉上一步这一步试探是失败的
    if not (0 <= y0 < len(mazeMap) and 0 <= x0 < len(mazeMap)):
      return False
    if mazeMap in :
      return False

    mazeMap = "#"         # 试探后标记该点为已试探过
    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
      for l in range(len(row)):         # l,列号
            item = row
            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
    mazeMap, entrance, exit = generate_maze(t, t)
    H, L = len(mazeMap), len(mazeMap)      # 获取迷宫的长宽,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()         # 防止绘制完窗口自动退出

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完美了
页: [1]
查看完整版本: Python练习——走迷宫