数据结构小设计--(迷宫问题Python版本)

363 阅读4分钟

@[TOC]

说明

本文为2021 12 14 所著,实现语言为python。设计需求:

1.设计迷宫 2.让人物自动寻找迷宫出口 3.动态显示该过程 4.保存迷宫路径(这里只是简单的stdout)

功能说明

在这里插入图片描述

模块说明

在这里插入图片描述

函数接口参数说明

在这里插入图片描述

项目结构

在这里插入图片描述

算法实现

这个是重点,但还是比较基础的。至于具体实现原理,自行百度。

import copy
class ALgorithm:

    @staticmethod
    def DFSAutoFindingWay(maze_list_r,start,end_row,end_col):

        def dfs(lst,maze_list_,row_,col_):
            while lst:
                now = lst[-1]
                row, col = now
                maze_list_[row][col] = 2

                if (row == row_ and col == col_):

                    return lst
                if (row + 1 < len(maze_list_) and maze_list_[row + 1][col] == 0):
                    lst.append((row + 1, col))
                    continue
                elif (col + 1 < len(maze_list_[0]) and maze_list_[row][col + 1] == 0):
                    lst.append((row, col + 1))
                    continue
                elif (row - 1 >= 0 and maze_list_[row - 1][col] == 0):
                    lst.append((row - 1, col))
                    continue
                elif (col - 1 >= 0 and maze_list_[row][col - 1] == 0):
                    lst.append((row, col - 1))
                    continue
                else:
                    lst.pop()

        start = start
        end_col = end_col
        end_row = end_row
        #一开始往下走


        ways = [] #存储多条路径
        has_way = len(end_row)
        lst = [start]
        for i in range(has_way):

            maze_list_ = copy.deepcopy(maze_list_r)
            zz = copy.deepcopy(lst)

            res = dfs(zz,maze_list_,end_row[i],end_col[i])
            ways.append(res)

        if ways:
            for i in range(has_way):
                print("DFS搜索路径{}为{}".format(i,ways[i]))
            return ways
        else:
            return []


    @staticmethod
    def BFSAutoFindingWay(maze_list,start,end_row,end_col):

        pre_route = list()  # 广度度搜索得到的节点
        q = list()  # 队列结构控制循环次数
        xx = [0, 1, 0, -1]  # 右移、下移、左移、上移
        yy = [1, 0, -1, 0]
        visited = list()  # 记录节点是否已遍历
        father = list()  # 每一个pre_route节点的父节点
        route = list()
        maze_list = copy.deepcopy(maze_list)
        def bfs(maze_list, x, y, m, n):
            visited = [[0 for i in range(len(maze_list[0]))] for j in range(len(maze_list))]
            visited[x][y] = 1  # 入口节点设置为已遍历
            q.append([x, y])
            while q:  # 队列为空则结束循环

                now = q.pop(0)  # 移除队列头结点
                maze_list[now[0]][now[1]] = 2
                for i in range(4):
                    point = [now[0] + xx[i], now[1] + yy[i]]  # 当前节点
                    if point[0] >= 0 and point[1] >= 0 and point[0] < len(maze_list) and point[1] < len(maze_list[0]) and visited[point[0]][point[1]] != 1 and maze_list[point[0]][point[1]]==0:
                        father.append(now)
                        visited[point[0]][point[1]] = 1
                        q.append(point)
                        pre_route.append(point)


                    if point[0] in m and point[1] in n:

                        return 1

            return 0

        def get_route(father, pre_route):  # 输出最短迷宫路径
            route = [pre_route[-1], father[-1]]
            for i in range(len(pre_route) - 1, -1, -1): # 从后往前拿
                if pre_route[i] == route[-1]:
                    route.append(father[i])
            route.reverse()

            return route


        if bfs(maze_list,start[0],start[1],end_row,end_col)==1:
                route=get_route(father,pre_route)
                print("BFS最佳路径:",route)
                return route
        else:
            return []


if __name__ == "__main__":
    maze_list = [
        [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1],
        [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
        [1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1],
        [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1],
        [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1],
        [1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1],
        [1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1],
        [1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1],
        [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1],
        [1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1]
    ]

    # result = algorithm.DFSAutoFindingWay((0,5),[12],[7,9])
    # print(result)
    res = ALgorithm.BFSAutoFindingWay(maze_list,(0,5),[12,12],[9,7])


控制代码

from turtle import Turtle
import turtle
import time
from ALgorithm import ALgorithm

class Controller(Turtle):
  def __init__(self,playper):
    # 父类初始化
    Turtle.__init__(self)
    # 初始值设置
    self.go_up = playper.go_up
    self.go_down = playper.go_down
    self.go_left = playper.go_left
    self.go_right = playper.go_right
    self.move = playper.move
    self.maze_list = playper.maze_list
    self.start = (playper.m,playper.n)
    self.end_row  = playper.end_m
    self.end_col = playper.end_n
    self.ALgorithm = ALgorithm

    # 绘制控制器
    self.hideturtle()
    self.speed(0)
    self.draw_btn('上', -15, 165)
    self.draw_btn('下', -15, -135)
    self.draw_btn('左', -165, 15)
    self.draw_btn('右', 135, 15)
    self.draw_btn("自动寻路DFS",-150,250)
    self.draw_btn("自动寻路BFS", 60, 250)
    self.draw_btn("重置",200,-220)

    # 绑定点击事件
    screen = self.getscreen()
    screen.onclick(self.handlescreenclick)


  def draw_btn(self, name, x, y):
    self.penup()
    self.goto(x, y)
    self.begin_fill()
    self.fillcolor('#ffffff')
    for i in range(4):
      self.forward(30)
      self.right(90)
    self.end_fill()
    self.color('#000000')
    self.goto(x + 7, y - 20)
    self.write(name, font = ('SimHei', 12, 'bold'))

  def autopathfindingB(self):
      #自动寻路功能,也就是走迷宫功能
      print("自动寻路BFS")

      res = self.ALgorithm.BFSAutoFindingWay(self.maze_list,self.start,self.end_row,self.end_col)
      for path in res:

          m,n=path
          time.sleep(0.5)
          self.move(m,n)
      pass
  def autopathfindingD(self):
      #自动寻路功能,也就是走迷宫功能
      print("自动寻路DFS")

      res2 = self.ALgorithm.DFSAutoFindingWay(self.maze_list,self.start,self.end_row,self.end_col)
      for paths in res2:
          for path in paths:
              m,n=path
              time.sleep(0.5)
              self.move(m,n)
      pass

  def RestPlayes(self):

        self.move(self.start[0],self.start[1])


  #当点击事件发生时利用abs函数进行比较判断
  def handlescreenclick(self, x, y):

    if ( 220 < abs(y) < 250  ):

        if(x>=-150 and x<-40 ):
            self.autopathfindingD()
        if(x>60 and x<160):
            self.autopathfindingB()
        if(x>200 and x<240):
            self.RestPlayes()


    else:
        if y > 0 and abs(x) < y:
            self.go_up()

        if y < 0 and abs(x) < -y:
            self.go_down()

        if x < 0 and abs(y) < -x:
            self.go_left()

        if x > 0 and abs(y) < x:
            self.go_right()

玩家代码

from turtle import Turtle
import turtle
import time

class Player(Turtle):
    def __init__(self, maze_list, start_m, start_n, end_m, end_n):
        # 父类初始化
        Turtle.__init__(self)
        # 初始的横纵坐标
        self.m = start_m
        self.n = start_n
        # 终点的横纵坐标
        self.end_m = end_m
        self.end_n = end_n
        # 迷宫地图
        self.maze_list = maze_list
        self.hideturtle()
        self.speed(0)
        self.penup()
        # 玩家移到对应的位置
        self.goto(self.n * 20 - 120, 120 - self.m * 20)
        # 生成玩家
        self.shape('turtle')
        self.color('yellow')
        # 玩家初始方向
        self.setheading(270)
        self.showturtle()

    # 当抵达时
    def reach_exit(self, m, n):
        if m in self.end_m and n in self.end_n:
            # 走出迷宫,显示'Pass it!'
            text = turtle.Turtle()
            text.hideturtle()
            text.penup()
            text.goto(-125, -10)
            text.color('blue')
            text.write('Pass it!', font=('SimHei', 48, 'bold'))
            time.sleep(2)
            text.clear()

    # 定义玩家可移动的位置,即只允许在迷宫内的通道里移动
    def canmove(self, m, n):
        # 遇到0允许移动
        return self.maze_list[m][n] == 0

    # 玩家移动时位置发生的变化
    def move(self, m, n):

        self.m = m
        self.n = n
        self.goto(self.n * 20 - 120, 120 - self.m * 20)
        self.reach_exit(m, n)

    # 向上移动
    def go_up(self):
        if self.canmove(self.m - 1, self.n):
            self.setheading(90)
            self.move(self.m - 1, self.n)

    # 向下移动
    def go_down(self):
        if self.canmove(self.m + 1, self.n):
            self.setheading(270)
            self.move(self.m + 1, self.n)

    # 向左移动
    def go_left(self):
        if self.canmove(self.m, self.n - 1):
            self.setheading(180)
            self.move(self.m, self.n - 1)

    # 向右移动
    def go_right(self):
        if self.canmove(self.m, self.n + 1):
            self.setheading(0)
            self.move(self.m, self.n + 1)

绘制迷宫

from turtle import Turtle
import turtle

# 设置游戏的窗口大小和背景颜色
turtle.screensize(800, 600, "white")


class Maze(Turtle):
    size = 20  # 迷宫内一格墙的长宽

    def __init__(self, maze_list):
        # 需要先调用父类的初始化方法才能在初始化方法中调用父类的方法
        Turtle.__init__(self)
        self.maze_list = maze_list
        # 为了加快绘图速度隐藏海龟,速度设为最快
        self.hideturtle()
        self.speed(-10)
        self.draw_walls()

    # 绘制迷宫内一格墙的过程
    def draw_wall(self):
        self.pendown()
        self.begin_fill()
        # 绘制墙的颜色
        self.fillcolor('red')
        # 首先画一个距离为20的横线,再向右旋转90度,循环4次形成方形
        for i in range(4):
            self.forward(self.size)
            self.right(90)
        self.end_fill()
        self.penup()

    # 绘制整个迷宫的墙
    def draw_walls(self):
        self.penup()
        # 从 (-130, 130) 开始
        self.goto(-130, 130)
        # 打印墙,横纵循环13次(整个迷宫的长和宽由13格墙组成)
        for row in range(len(self.maze_list)):
            for col in range(len(self.maze_list)):
                # 主函数中的maze_list里面的1则打印出一格墙
                if self.maze_list[row][col] == 1:
                    self.draw_wall()
                # 右移一列
                self.goto(self.size * (col + 1) - 130, 130 - self.size * row)
            # 下移一行
            self.goto(-130, 130 - self.size * (row + 1))


if __name__=="__main__":
    maze_list = [
        [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1],
        [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
        [1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1],
        [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1],
        [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1],
        [1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1],
        [1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1],
        [1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1],
        [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1],
        [1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1],
        [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1],
        [1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1]
    ]

    Maze(maze_list)
    turtle.mainloop()

主控

from Maze import Maze
from Player import Player
from Controller import Controller
import turtle
maze_list = [
  [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1],
  [1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
  [1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1],
  [1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1],
  [1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1],
  [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1],
  [1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1],
  [1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1],
  [1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1],
  [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1],
  [1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1],
  [1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1],
  [1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1]
]


Maze(maze_list)
#0,5表示玩家起始的位置;12,7表示终点的位置
player = Player(maze_list, 0, 5, [12], [7,9])
Controller(player)
turtle.mainloop()

效果

在这里插入图片描述