实验准备(超级玛丽闯迷宫)

  经过了前面两个项目的实践,我对python和pyqt5已经有了一定的了解,除了能够把实验要求全部完成,还加入了自己的一些想法在游戏里,让游戏更加有趣。

  第三个项目主要的需求是能随机生成一个迷宫,并且能够自动寻路来破解迷宫。迷宫的随机生成主要采用Prim算法来生成迷宫,一方面是因为Prim算法生成的迷宫比较自然,另一方面是之前了解过Kurskal最小生成树的思想,二者有共通性,故选用此算法。自动寻路则使用实验要求里的A*算法来实现,它相比广度优先搜索的效率更高,因为它有启发函数,能够在边权为1的图里面提供额外的启发信息,能够更快的收敛,搜索到目标结点。

目录

  • 实验准备(超级玛丽闯迷宫)
    • 一、迷宫定义(Map类)
      • 1. 成员变量
      • 2. 成员方法
    • 二、随机生成迷宫(Prim算法)
      • 1. 最小生成树
      • 2. Prim算法流程
      • 3. prim算法和迷宫生成的关系
      • 4. prim算法生成迷宫流程
    • 三、迷宫自动寻路(A*算法)
      • 1. 算法简介
      • 2. 路径选择
      • 3. 定义结点
      • 4. 子方法
      • 5. 算法流程
    • 四、游戏界面(PyQt5)
      • 1. 成员变量
      • 2. 构造函数
      • 3. 子方法

一、迷宫定义(Map类)

  要实现随机生成迷宫第一步当然是定义迷宫,定义迷宫的大小以及对迷宫进行获取、设置、重置、判断、打印等操作的方法。

1. 成员变量

(1)width,height:定义迷宫的行数和列数。

(2)map:二维列表用来存放迷宫地图,坐标定义与数组索引相似,x为纵向,y为横向(与一般坐标系不同)。

二维列表中每一个元素的值代表不同的含义,分别如下:

① map[i][j] == 0:当前格为空格。

② map[i][j] == 1:当前格为墙壁。

③ map[i][j] == 2:当前格为起点。

④ map[i][j] == 3:当前格为终点。

⑤ map[i][j] == 4:当前格为自动寻路路径上的结点。

2. 成员方法

(1)getMap(self):返回当前对象的map[n][m]二位迷宫列表。

(2)resetNode(self, value):设置map[n][m]二位迷宫列表的每一个元素为value值。

(3)setNode(self, x, y, value):设置map[x][y] = value。

(4)isWall(self, x, y):判断map[x][y] = 1 ?也就是判断是否是墙壁。

(5)showMap(self):打印map[n][m]整个迷宫。

二、随机生成迷宫(Prim算法)

  定义了迷宫后我们来实现Prim算法,用它来实现迷宫的随机生成,Prim算法可在加权连通图里搜索最小生成树,那么首先我们来了解什么是最小生成树。

1. 最小生成树

  百度百科给出的定义是:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。

  我的理解是:在一个带权图中,有n个结点,用n-1条边使得这n个点相互之间可达,这也就是生成树,所谓最小即为这n-1条边的权值之和是最小的。所以最小生成树其实就是在n个顶点的图中选n-1条边使得这个图为联通图(强连通图)并且这n-1条边的权值之和最小。

  如下是我用3D画图画的无向赋权图

无向赋权图

它的生成树:

生成树1,边权之和 = 13

生成树2,边权之和 = 13 即使生成树不同,边权可以相同。

最小生成树:

生成树2,边权之和 = 8 最小生成树的边权之和最小且为联通图。

2. Prim算法流程

(1) 输入:一个加权连通图,其中顶点集合为V,边集合为E;

(2) 初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;

(3) 重复下列操作,直到Vnew = V:

  ① 在集合E中选取权值最小的边<u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);

  ②将v加入集合Vnew中,将<u, v>边加入集合Enew中;

(4) 输出:使用集合Vnew和Enew来描述所得到的最小生成树。

3. prim算法和迷宫生成的关系

  假设迷宫为7×7的正方形,9个白格子为初始空结点,黑色格子为墙壁。

  接着我们把整个迷宫看成一张无向图,白色的格子看成结点,部分黑格子看成边,如下图:

图中1~9标号代表结点,红色的线代表边。

   接下来用Prim算法即可生成这个图的一个最小生成树,这个最小生成树就是迷宫的连通的部分,也就是玩家可以走的部分。并且因为每一个边权都是1,所以只要边权之和一定是n-1也就是 9-1 = 8 。

图中1~9标号代表结点,红色的线代表边。

   最后生成如上图,也就是我们所需要的迷宫,途中一共有8条边,边权之和也就是 8*1 = 8。

4. prim算法生成迷宫流程

预处理部分:

(1)定义一个检查列表checklist存放为划分顶点集。
(2)把初始起点加入checklist列表中。

主循环部分:

(3)重复下面几个步骤直到检查列表checklist为空:

  ① 随机取出checklist列表中的一个结点node1。

  ② 检查这个结点node1周围有没有墙wall。
    ③ 有墙:从这个结点node1周围的墙中随机选一个,假设是wall_left,把这个墙置为空;并且把这个墙与node1之间的结点也置为空;最后把这个墙的位置坐标加入checklist中。
    ④ 无墙:把node1从checklist中删除。

(4)通过上述步骤后,迷宫即可随机生成。

三、迷宫自动寻路(A*算法)

1. 算法简介

   A* 算法是一种静态路网中求解最短路径最有效的直接搜索方法,我认为A*算法与BFS广度优先搜索算法有很多相似之处,不过它相比广度优先搜索的效率更高,因为它有启发函数,能够在边权为1的图里面提供额外的启发信息,能够更快的收敛,搜索到目标结点。

2. 路径选择

   那么我们如何在若干条路径中选出最优的一条呢?

这就需要定义路径代价:F

它衡量了当前路径的优劣程度,对是否继续采用改路径具有决定作用。

同时它满足下列等式:

                F = G + H

G是移动代价,即从起点沿当前路径到当前结点的路径的长度。

H是估算代价,我们这里使用曼哈顿距离,即当前结点到目标结点的最短路径长度(忽略地形)。

3. 定义结点

  为什么要定义结点:因为最后输出路径的时候需要从最后一个目标结点不断访问父节点来进行路径追溯,最后才能输出从源节点到目标结点的一条完整路径。
主要变量有:

  • x、y坐标
  • 沿当前路径到map[x][y]的路径长度(G值)
  • 当前路径的F值(F = G + H)
  • 父节点(用于路径回溯)

4. 子方法

(1)pathEvaluate(val, fx, fy, ex, ey) :

  计算当前路径代价(F = G + H)。

(2)findMin(open) :

  返回open表中代价最小的结点。

(3)find_node(node, list):

  判断某个结点在不在某个表中。

(4)AStar(map, row, col, sx, sy, ex, ey)方法:

  完成A* 算法的主逻辑,执行过程中调用前面三个子方法。

5. 算法流程

定义与预处理部分:

(1)定义一个open开放列表,这里面的结点可能更新可能移除。
(2)定义一个close封闭列表 ,这里面的结点不需要处理。
(3)往open表中加入起点。

主循环部分:

(4)重复下面几个步骤直到检查列表checklist为空:

  ① 找到open表中代价最小的结点,把它从open表中取出并放入close表中。

  ② 判断这个结点是否是目标结点

      ③ 是:通过这个结点不断回溯到源节点生成一条路径,返回这个路径并退出整个AStar函数。

      ④ 否:往相邻结点nx拓展搜索。

          ⑤ 如果相邻结点nx:1.在close表里。2.是墙壁。3. 超出地图边界。就跳过这个相邻结点nx,直到这个结点的4个相邻结(n1、n2、n3、n4)点都判断过。

          ⑥ 如果相邻结点nx在open表中(注意只要 (x,y) 坐标相同就算相同),比较相邻结点nx和open表中结点的G移动代价,如果相邻结点n的G值比open表中相同结点的G值小,则更新open表中的相同结点的G值和F值,并且把open表中的相同结点的父节点设置为当前结点。

          ⑦ 如果相邻结点nx不在open表中,直接把相邻结点nx加入open表中。

(4)通过上述步骤后,从源结点到目标结点的路径就生成了。

四、游戏界面(PyQt5)

1. 成员变量

  ① 窗口变量:设置窗口大小
  ② 地图变量:设置地图行列数、起点、终点、地图列表
  ③ 玩家变量:定义玩家坐标
  ④ 游戏标志:定义各种游戏标志,如到第几关、是否通关、人物左右。
  ⑤ 音乐播放器:音乐播放器的初始化以及音乐的导入。

2. 构造函数

  1. 设置窗口标题
  2. 设置图标
  3. 设定游戏背景颜色
  4. 游戏窗口大小
  5. 让游戏窗口大小固定
  6. 初始化游戏

3. 子方法

  1. init(self): 初始化游戏
  2. update_bgm(self): 更新背景音乐
  3. update_level(self): 更新游戏关卡
  4. showMap(self): 打印地图
  5. paintEvent(self, event): 绘图事件
  6. sound(self): 播放音效
  7. checkPass(self): 判断通关
  8. findpath(self): 自动寻路
  9. keyPressEvent(self, event): 键盘事件

  这次迷宫游戏学习了Prim算法以及A*算法收获了很多,同时发掘经过前两个项目的实践,这次游戏编写及调试的速度有了提升,整个游戏2天完成,第3天写博客收尾。

———2020.12.21(1:25)(罗涵)

THE END

计算机软件实习项目三 —— 超级玛丽闯迷宫 (实验准备) 12-19(12-21更新)相关推荐

  1. 计算机软件实习项目三 —— 超级玛丽闯迷宫(游戏介绍 游戏视屏 游戏下载)12-21

    超级玛丽闯迷宫(游戏介绍 & 游戏视屏 & 游戏下载)   经过了几天的开发,超级玛丽床迷宫游戏总算是出炉了.这次开发比前两个项目快了许多,迷宫的定义及随机生成花费一天完成,迷宫自动寻 ...

  2. 计算机软件实习项目三 —— 超级玛丽闯迷宫 (代码实现) 12-21

    代码实现(超级玛丽闯迷宫)   上一篇博客对这个游戏的整体框架以及算法的流程进行了比较详细的设计及分析:对必要的类和类的成员变量.类的方法进行了声明以及声明.这一篇博客主要来呈现相关代码. 目录 代码 ...

  3. 计算机软件实习项目二 —— 贪吃蛇游戏 (实验准备)

    目录 一.实验目的 二.编程语言和平台 三.实验难点: 四.参考资料 一.实验目的 1.实现贪吃蛇游戏基本功能,屏幕上随机出现一个"食物",称为豆子 2.上下左右控制"蛇 ...

  4. 项目三 Java开发迷宫游戏

    一.项目预习: 思考过程: 迷宫由一个一个格子组成,要求从入口到出口只有一条路径. 通过树实现是比较容易的,从根节点到每一个子节点都只有一条路径.假设入口是根节点,出口是树中某个子节点,那么,从根节点 ...

  5. 软件技术实习项目三 迷宫

    1.实习内容 1) 迷宫游戏是非常经典的游戏,在该题中要求随机生成一个迷宫,并求解迷宫: 2) 要求查找并理解迷宫生成的算法,并尝试用两种不同的算法来生成随机的迷宫. 3) 要求迷宫游戏支持玩家走迷宫 ...

  6. 计算机软件实习——项目一

    项目一需要我们做出一个基础的计算器,要包含加减乘除.验算式子等功能,均由Java编写. 首先考虑UI制作,Java自带的Java GUI即Java的图形用户界面,包含了AWT,Swing,javaFX ...

  7. 计算机软件实习项目二 —— 贪吃蛇游戏 (代码实现) 12-16

    代码实现   不得不说python真是太香了,我感觉写起来比C++快,而且代码量更少,还有非常多十分方便的方法可以使用.在pycharm里有非常多的快捷键十分的方便,相较项目使用的visual stu ...

  8. 计算机软件实习项目一 简单计算器 (Qt实现计算器界面) 12-5

    UI用户界面 使用Qt Designer对计算器的界面进行制作 目录 UI用户界面 界面设计 功能描述 界面浏览 新功能 1.小数点前后自动补0 2.加减乘除自动切换 3.不允许的操作按了不会生效 4 ...

  9. 计算机软件实习(一)简单计算机

    计算机软件实习(一)简单计算机 实验内容: (1) 学习图形界面的设计,利用 MFC 应用程序(Java swing 或 QT 框架,或 C#)创 建基于对话框的应用程序,添加按钮.编辑框等控件: ( ...

最新文章

  1. hp-ux 集群,内存 小记
  2. 客户端如何连接 DataSnap Server 调用服务的方法
  3. 【2013年11月12号】日记
  4. Metasploit Framework 简介与使用
  5. 最好用的koa2+mysql的RESTful API脚手架,mvc架构,支持node调试,pm2部署。
  6. 从CLR GC到CoreCLR GC看.NET Core为云而生
  7. 切换分支 如何判断 是否完成_如何判断展览公司是否专业?
  8. DNS高可用设计--软件高可用
  9. Swagger2的使用
  10. 一杯水怎么测试_每滴都是“芯”鲜好水,碧然德新款净水器实测
  11. 软件定义重划边界——IT就是把复杂东西简单化
  12. mysql备份单实例(一)shell
  13. linux中nohup命令_Linux中的Nohup命令
  14. linux c语言ide,linux下用过的c++IDE
  15. 博士劝退文,写的真好!
  16. 应用/游戏在三星Galaxy S8及S8+上的适配办法
  17. 「小白学Python」Windows安装Python
  18. html5图片2d转换器,webp2jpg - 图片格式转换工具
  19. 小爱同学+8266的小爱语音台灯,基于Blinker库
  20. 安装scrapy报错failed with error code 1 in C:\Users\ADMINI~\AppData\Local\Temp\pip-install-4447ozxq\Twist

热门文章

  1. 运营小白“染指”ASO手游联运的正确姿势
  2. Android 重新编译资源文件(touch)
  3. 用小牛翻译API让ChatGPT给我做个在线翻译网站
  4. 软件工程复试——十三、软件项目管理
  5. springboot +mybatisPlu控制台打印sql
  6. 销售和程序员哪个好_适合服装店的服装销售管理软件哪个好?
  7. influxdb常见操作
  8. 全球及中国热电离质谱仪行业投资风险预测及发展规划建议报告2022-2028年
  9. SQL必知必会-笔记(完善版):第1课
  10. 走近BI:揭开管理驾驶舱的神秘面纱