自动扫雷 分析
java 扫雷 实验报告
java 扫雷实验报告Java 扫雷实验报告一、引言扫雷是一款经典的单人益智游戏,玩家需要根据数字提示,在雷区中揭开没有地雷的方块,同时避免触雷。
本实验旨在使用Java语言实现一个简单的扫雷游戏,并对实现过程和结果进行分析和总结。
二、实验过程1. 游戏界面设计使用Java的图形用户界面(GUI)工具包Swing,设计了一个扫雷游戏的界面。
界面包括一个方格矩阵,每个方格可以是未揭开、揭开、标记地雷三种状态之一。
同时,界面上显示了剩余地雷数量和游戏时间。
2. 游戏逻辑实现通过编写Java代码,实现了扫雷游戏的逻辑。
主要包括以下几个方面:- 初始化雷区:根据用户输入的难度级别,生成对应大小的雷区,并在其中随机布置地雷。
- 揭开方块:当玩家点击某个方块时,根据该方块周围的地雷数量,显示对应的数字或触雷。
- 标记地雷:当玩家认为某个方块是地雷时,可以标记该方块,以便后续操作时不会误触雷。
- 游戏结束判断:当玩家揭开所有没有地雷的方块时,游戏胜利;当玩家触雷时,游戏失败。
3. 用户交互设计为了提升用户体验,实现了以下交互设计:- 鼠标左键点击方块:揭开方块或触雷。
- 鼠标右键点击方块:标记地雷或取消标记。
- 双击方块:自动揭开周围未标记的方块,如果周围已标记地雷数量与方块上的数字相等。
三、实验结果经过实验,我们成功实现了一个简单的Java扫雷游戏。
游戏界面美观,操作流畅,能够满足基本的游戏需求。
玩家可以根据自己的喜好选择不同的难度级别,挑战不同规模的雷区。
四、实验总结通过这个实验,我们深入理解了Java语言的面向对象特性和图形用户界面的设计思想。
同时,我们学会了如何将一个复杂的问题分解为多个小问题,并通过合理的设计和编码实现整体功能。
在实验过程中,我们也遇到了一些挑战,比如如何处理用户输入、如何判断游戏是否结束等。
通过不断思考和尝试,我们最终找到了解决方案,并取得了满意的结果。
在今后的学习和工作中,我们将继续深入学习Java语言和相关技术,提升自己的编程能力。
java 扫雷 实验报告
java 扫雷实验报告
《Java 扫雷实验报告》
摘要:
本实验利用Java编程语言实现了一个简单的扫雷游戏,并对游戏的性能进行了测试和分析。
通过实验发现,使用Java语言编写的扫雷游戏在性能和用户体验方面表现良好,能够满足一般玩家的需求。
1. 引言
扫雷是一款经典的单人益智游戏,玩家需要根据数字提示来判断雷的位置,然后进行标记或清除。
本实验旨在利用Java编程语言实现一个简单的扫雷游戏,并对其性能进行测试和分析。
2. 实验方法
首先,我们使用Java语言编写了一个扫雷游戏的基本框架,包括游戏界面、游戏逻辑和用户交互等部分。
然后,我们利用性能测试工具对游戏进行了性能测试,包括内存占用、CPU占用和响应速度等指标。
3. 实验结果
通过性能测试,我们发现使用Java编写的扫雷游戏在内存占用方面表现良好,平均占用内存不超过100MB。
在CPU占用方面,游戏在运行时的平均CPU占用率不超过20%,并且响应速度较快,基本没有卡顿现象。
4. 实验讨论
根据实验结果,我们可以得出结论:使用Java编程语言实现的扫雷游戏在性能和用户体验方面表现良好,能够满足一般玩家的需求。
同时,我们也发现一些优化的空间,比如进一步减小内存占用、优化游戏界面等。
5. 结论
本实验利用Java编程语言实现了一个简单的扫雷游戏,并对游戏的性能进行了测试和分析。
通过实验发现,使用Java语言编写的扫雷游戏在性能和用户体验方面表现良好,能够满足一般玩家的需求。
希望本实验能够为Java游戏开发提供一些参考和借鉴。
扫雷游戏需求分析报告
扫雷游戏需求分析报告1. 引言本文档对扫雷游戏的需求进行了分析和整理,旨在明确扫雷游戏的功能和特性,为开发人员提供具体的需求指导,帮助他们设计和开发出一个符合用户期望的扫雷游戏。
2. 项目背景扫雷游戏是一款经典的电脑游戏,旨在通过揭开方块并避免触雷的方式来挑战玩家的智力。
该游戏已经存在许多版本,而我们旨在开发一款简单、易于上手的扫雷游戏,以满足广大用户的需求。
3. 功能需求根据对扫雷游戏的分析和了解,我们整理了如下的功能需求:3.1 游戏规则•游戏开始时,所有方块都是未揭开的状态,其中隐藏了一些地雷。
•玩家需要通过点击方块揭开它们,如果揭开的方块上有地雷,则游戏结束;否则,会显示方块上的数字。
•数字表示周围8个方块中的地雷数量。
•如果揭开的方块上没有地雷并且周围都已揭开,则自动揭开周围的方块。
•玩家可以标记已经确定存在地雷的方块。
•当所有非地雷的方块都被揭开时,游戏胜利。
3.2 游戏界面•游戏界面由一个网格组成,网格上有方块。
每个方块上可以是地雷或者数字。
•玩家可以通过鼠标点击来揭开方块或者进行标记。
•游戏界面上应该有计时器,记录游戏的用时。
•游戏界面上应该显示当前揭开的方块数量,以及游戏剩余的地雷数量。
3.3 游戏设置•游戏应该提供不同的难度级别供用户选择:初级、中级和高级。
不同难度级别的区别在于地雷数量和网格大小。
•用户可以自定义游戏设置,包括地雷数量和网格大小。
4. 非功能需求除了功能需求之外,我们还明确了一些非功能需求,如下所示:4.1 用户界面•游戏界面需要简洁、直观、易于操作,并且能够适配不同分辨率的屏幕。
•游戏需要提供操作指引,帮助用户快速上手。
4.2 性能要求•游戏需要在合理的时间内响应用户的操作,不应该出现明显的卡顿或延迟。
•游戏应该能够快速地进行地雷的生成和分布。
4.3 可扩展性•游戏的代码结构要清晰、模块化,便于后续的功能扩展和维护。
5. 总结本文档对扫雷游戏的需求进行了详细的分析和整理,明确了游戏的功能需求和非功能需求。
第5讲 综合应用-自动扫雷器
12
画图程序在分析自动扫雷器代码中的作用: 扫雷游戏程序和自动扫雷器窗口大小分别是多少个像 素,标题栏和菜单栏高度是多少个像素,边框高度或 宽度是多少个像素,等等。 每个方格16×16区域具体包含了哪些像素。 提取每个方格第8行16个像素的颜色,第8行具体是哪 一行。等等。
13
补充:其他工具软件的应用
数据成员m_nWidth、m_nHeight说明: m_nWidth:扫雷游戏水平方向上有多少个方格。 m_nHeight:扫雷游戏竖直方向上有多少个方格。 数数高级模式水平和竖直方向上分别有多少个方格。
BOOL m_bWin98; CString winMineClassName; HWND hWinMineWnd; CRect rectWinMine; CRect rectMe; BOOL m_bStart; int m_nWidth; int m_nHeight; int m_nMineNum; int m_nMineCurNum; BYTE *m_map; 24 BYTE m_ColorSample[16][8];
屏幕坐标:CPoint类(MFC中的类) 表示屏幕上一个点的坐标。 与Windows中的结构体POINT(即API中的结构体)类似, 增加了很多成员函数。 区域:CRect(MFC中的类) 表示屏幕上一个矩形区域。 与Windows中的结构体RECT(即API中的结构体)类似, 增加了很多成员函数。
扫雷游戏总结
扫雷游戏总结1. 简介扫雷游戏是一款经典的单人推理益智游戏,也是Windows操作系统自带的游戏之一。
游戏的目标是根据隐藏在方块中的数字提示,避开雷区,并成功找出所有不包含雷的方块。
本文将对扫雷游戏进行总结分析。
2. 游戏规则在扫雷游戏中,游戏区域被网格分割为若干个方块。
其中,有些方块下面隐藏着地雷,而其他方块则显示数字,表明相邻方块中地雷的数量。
玩家需要根据这些数字提示,推理出哪些方块是安全的,哪些方块是有地雷的。
玩家可以通过左键点击一个方块来揭开它。
如果揭开的方块是地雷,则游戏结束;如果揭开的方块是数字,则它会显示周围的地雷数量;如果揭开的方块周围没有地雷,则自动揭开相邻的相邻方块,直到揭开的方块周围有数字为止。
玩家可以通过右键点击一个方块来标记它,表示该方块是有地雷的。
游戏胜利的条件是所有没有地雷的方块都被揭开。
3. 游戏策略•规避雷区在扫雷游戏中,首先需要学会规避雷区。
当揭开一个数字方块时,该数字表示其周围格子的地雷数量。
通过观察周围方块的数字,可以推理出哪些方块是地雷,哪些方块是安全的。
•标记地雷在确定一个方块是地雷后,可以通过右键点击该方块来标记它。
这有助于玩家在推理和揭开其他方块时,避免误触地雷。
•利用推理在推理时,可以利用已揭开方块的数字提示,以及已标记的地雷方块,进一步推断其他方块的情况。
通过综合分析,可以确定一些方块是安全的,或者确定一些方块是地雷。
•注意边角在扫雷游戏中,边角的方块与其他方块的不同在于,它们相邻的周围方块较少。
因此,需要更加小心操作边角方块,以避免初步推理时的判断错误。
4. 策略总结通过以上的玩法和策略,可以更好地玩好扫雷游戏。
接下来总结一下玩该游戏的一些有效的策略:1.从数字最小的方块开始推理:通常,数字最小的方块周围的雷最少,因此,从这些方块开始推理,可以更快地找出安全的方块。
2.观察数字方块周围的未揭开方块:数字方块周围的未揭开方块可能是地雷,也可能是安全的方块。
扫雷
进入扫雷界面,会出现一大片方格:先介绍一下操作吧:鼠标左键可以打开方格鼠标右键可以把方格标记为地雷打开的方格里的数字表示本方格周围有几颗地雷。
如果一个方格周围已经标出的地雷数量和方格内数字相同,在方格上同时按左键和右键可以打开其余方格。
如果不幸踩雷,可以按按钮重新来过,不想用鼠标的话可以按键盘上的F2键。
操作介绍完了,现在我们实际演练一盘,就先初级的开始吧:咱先从这个阵学习先从简单学起请看左下角的如果会玩的一看当然就知道左下角的那个不是雷为什么会知道呢?这里有一个规律当方格子里有 1 时就表示它周围的 8 个格子里肯定有一个是雷从这个分析看中间的 1 它周围有 5 个空就表示有 5 个格子不是雷看它左面的和下面的 1 也表示这两个不是雷那么现在咱可以知道中间的 1 周围 8 个格子里有 7 个不是雷下面咱就可以知道左下角的肯定是雷你猜对了咱知道这个了在看最左面中间的那个 1 再看周围 8 个格子里可是他周围不是 8 个所以就考虑剩下的 6 个还继续看那个 1 它周围有一个小红旗表示已经有一个雷了就表示它的周围已经有一个雷了所以剩下的几个格子都不是雷咱就可以得到你已经学会了最简单的部分了下面咱再分析左上的那部分先用我上面给你介绍的那种方法把下面三个 1 上面的两个格子解出来可以得到这时你是不是有点迷惘不知道怎么点了?别着急咱继续分析看到这块右面的下面的 2 了吗?它就表示它的周围有 2 颗雷但咱已经分析出已经有一个是雷了还有它周围还剩下 1 个未知的格子还有6个已知的格子所以咱就可以判断出刚才那个雷的上面还是个雷咱们就可以得到再看左边的那个 2 这时它周围已经有两个雷了所以咱就可以把剩下的三个格点开咱就可以知道这时 2 上面还是 2 并且它周围已经有两颗雷我们就可以把这部分解出来这部分也简单只要你用心去理解就没问题其实总结一条就是:哪个数字就表示它周围的8个格就有几颗雷下面咱就开始分析右面的那部分难的这是常见的1 2 1 格式这个不用思考只要 2 在两个 1 中间那么 2 所对应的就不是雷咱就可以知道这个没什么规律死记就行接着下面的咱可别跑题了坚持住了这时你是不是犯难了呢?不要心急相信自己咱先看 4 周围刚好有4个方格,所以它们全部是雷这个明白了咱就接下面不要走神 !要专心! 学什么都要有个过程的 !咱先从最下面的 2 开始分析运用你前面所学的就可以的得到再看两个 1 还有两个 2 中间的 2 可以看出在 8 个格中它的右上角和右下角有雷 所以你就可以放心点开 咱就可以得到再运用前面所学的 我们就可以得到进一步我们就可以根据 4 下面的 2 把所有的解出来 所以 我们解出来的就是最后咱就可以把整局解开 所以就是3BV: Bechtel's Board Benchmark Value (对3BV文后有详细介绍)每局将所有非雷的方块点开所需最少左键点击数,是目前普遍用来评估局面难易程度的数据。
扫雷的原理
扫雷的原理
扫雷游戏是一款经典的益智游戏,它的原理其实并不复杂。
在这个游戏中,玩家需要根据数字提示来判断哪些方块是地雷,哪些是安全的。
在本文中,我们将深入探讨扫雷游戏的原理,帮助你更好地理解这款游戏。
首先,让我们来了解一下扫雷游戏的基本规则。
在一个由方块组成的网格中,有一些方块下面埋藏着地雷,而其他方块则是安全的。
玩家的任务就是根据周围方块中的数字提示,来推断哪些方块是地雷,哪些是安全的。
当所有的安全方块都被揭开时,玩家就赢得了游戏。
那么,数字提示是如何产生的呢?其实,这些数字是根据周围的地雷数量计算出来的。
当玩家揭开一个方块时,如果这个方块下面是地雷,那么它周围的方块中的数字就会加一。
通过不断地揭开方块,玩家可以逐渐推断出哪些方块是地雷,哪些是安全的。
扫雷游戏的关键在于逻辑推理。
玩家需要根据数字提示,结合已知的信息,来推断出每个方块的状态。
有时候,玩家需要进行一定的猜测,但这种猜测也是建立在逻辑推理的基础上的。
通过不断地分析和推断,玩家可以逐渐揭开更多的方块,直到最终找到所有的安全方块,赢得游戏。
除了逻辑推理,扫雷游戏还需要一定的运气。
有时候,玩家需要根据概率来进行猜测,这就需要一定的运气才能成功。
但是,运气只是辅助因素,真正决定胜负的还是玩家的逻辑推理能力。
总的来说,扫雷游戏的原理并不复杂,但是要想玩得好,需要一定的逻辑推理能力和一些运气。
通过不断的练习和思考,相信每个人都可以成为一名优秀的扫雷玩家。
希望本文对你有所帮助,祝你在扫雷游戏中取得好成绩!。
扫雷可行性报告分析
扫雷可行性报告分析
一、背景介绍
扫雷是一种常见的游戏,玩家需要根据数字提示在地雷中揭露安全区域。
扫雷游戏在计算机上也有很大的应用,但是在实际生活中,扫雷技术是否可行呢?本报告将对扫雷的可行性进行分析。
二、扫雷技术现状
目前,扫雷技术已经相当成熟。
通过计算机算法,可以根据周围的数字提示来确定地雷的位置,从而更快地完成扫雷游戏。
此外,扫雷技术也被应用在一些实际工程中,如军事领域的排雷工作等。
三、扫雷的应用领域
扫雷技术在实际生活中有着广泛的应用领域。
除了游戏和军事领域外,扫雷技术还可以应用于地质勘探、矿产开采等领域。
通过扫雷技术,可以更快速、更安全地完成相关工作。
四、扫雷的优势与挑战
扫雷技术的优势在于可以通过算法迅速准确地确定地雷位置,提高工作效率,降低人员受伤风险。
然而,扫雷技术也面临着一些挑战,如在复杂环境下的准确性、算法的优化等方面需要进一步研究。
五、未来发展趋势
随着人工智能技术的不断发展,扫雷技术也将不断进步。
未来,扫雷技术可能会更加智能化,能够适应更复杂的环境,提高工作效率,降低风险。
六、结论
综上所述,扫雷技术在实际生活中具有一定的可行性,可以在多个领域得到应用。
随着技术的不断发展,扫雷技术也将不断进步,为相关领域的工作提供更好的支持和保障。
扫雷小游戏实验报告(3篇)
第1篇一、实验目的本次实验旨在通过使用C语言编写扫雷小游戏,巩固和加深对C语言编程基础知识的理解,提高编程实践能力。
通过实验,使学生能够熟练运用数组、函数等编程技巧,实现一个具有良好交互性和趣味性的小游戏。
二、实验环境1. 操作系统:Windows 102. 编译器:Visual Studio 20193. 编程语言:C语言三、实验内容1. 游戏设计扫雷小游戏是一款经典的逻辑推理游戏,玩家需要在限定时间内找出棋盘上的所有非雷区域。
游戏规则如下:(1)棋盘大小:9x9(2)地雷数量:10个(3)玩家通过输入坐标排查雷区,若排查到非雷区则显示周围雷的数量,若排查到雷则游戏结束。
(4)玩家的目标是找出所有非雷区,成功排雷后游戏结束。
2. 数据结构设计为了存储雷的位置信息和排查信息,我们需要使用以下数据结构:(1)二维数组:用于存储雷的位置信息,大小为9x9,其中值为-1表示雷,值为0表示非雷。
(2)二维字符数组:用于存储排查结果,大小为9x9,其中字符'0'表示非雷,字符''表示雷。
3. 函数设计(1)初始化函数:用于初始化棋盘、地雷位置和排查结果。
(2)打印棋盘函数:用于显示当前棋盘状态。
(3)布置雷函数:用于随机布置地雷。
(4)排查函数:用于判断玩家输入的坐标是否为雷,并更新排查结果。
(5)游戏主逻辑函数:用于实现游戏的主要逻辑,包括用户交互、游戏结束判断等。
4. 编码实现以下是部分代码实现:```cinclude <stdio.h>include <stdlib.h>include <time.h>define ROW 9define COL 9define MINE_NUM 10// 函数声明void init(char mine[ROW][COL], char show[ROW][COL]);void print(char show[ROW][COL]);void setMines(char mine[ROW][COL]);void check(char mine[ROW][COL], char show[ROW][COL], int x, int y);int isGameOver(char show[ROW][COL]);int main() {char mine[ROW][COL], show[ROW][COL];int x, y;int gameOver = 0;init(mine, show);setMines(mine);while (!gameOver) {print(show);printf("请输入坐标(x y):");scanf("%d %d", &x, &y);if (x < 0 || x >= ROW || y < 0 || y >= COL) { printf("坐标输入错误,请重新输入。
人工智能 扫雷 课程设计报告
人工智能project报告学号:20091000608姓名:王沙沙班级:191091指导老师:赵老师2011年10月25目录1.自动扫雷 (3)需求分析 (3)游戏规则 (3)扫雷游戏设计 (3)自动扫雷设计 (5)用户手册 (5)运行结果 (6)结论 (7)主要算法代码 (7)1 自动扫雷1.问题描述、需求分析扫雷是Windows操作系统自带的桌面小游戏之一,由于其规则简单,长期以来一直受到电脑用户的欢迎。
自动扫雷是开始扫雷后根据扫雷规则利用计算机进行扫雷。
开始棋局,单击第一个按钮,因为执行第一个动作时所有按钮是雷的概率都相等,为了方便起见每次开局后都按下第一个按钮,如果不幸第一个按钮就是雷,那么单击--开始--重新开局。
2.游戏规则游戏界面如下图所示,游戏区域是由M X N个格子组成的“雷区”,左上方的数字显示雷区中未被标出的地雷的个数,右上方的数字显示用户从第一次点击开始所用的时间,单位是秒。
中间的图标指示游戏的状态(完成:笑脸;失败:哭脸)。
用户需要通过鼠标操作来确定雷区中所有地雷的位置:左键单击:尝试某个格子是否有地雷。
如果该格子下有地雷,则游戏失败·如果该格子下没有地雷但其周围八个格子下有地雷,该格子会显示其周围八个格子中地雷的个数;如果该格子下没有地雷且其周围八个格子下也没有地雷,则此处被挖开。
右键单击:改变某个格子是否有雷的标志(工)。
或左右键同时单击:当该格子周围已标地雷的个数与格子中的数字相同时,则挖开周围的其余格子。
当提示该格子周围已标地雷的个数少于格子;3.扫雷游戏设计每个格子有如下几种状态:{MS_NORMAL,MS_OPEN,MS_FLAG,MS_QUEST,MS_EXPLODE} MINESTATUS1)格子类共有变量如下:MINESTATUS m_nStatus;//格子状态int m_nMineNum;//格子周围的雷数,即格子上显示的数字CWnd *m_pParent;//父窗口int m_nX,m_nY; //按下按钮的横纵坐标成员函数SetStatus(MINESTATUS nStatus)//设置状态GetStatus()//获取状态SetMineNum(int nMineNum)//设置雷数GetMineNum() //获取雷数DrawItem(BOOL bFail=TRUE);//绘制格子2)布雷类共有变量如下int m_nRow,m_nCol;//棋盘有多少行多少列int m_nMineNum; //棋盘上的雷数int m_nX,m_nY; //棋盘的位置int m_nOldMine;int m_aMineTest[9];int m_nMineTest;CMineButton *m_aLandMine[10000]; //棋盘CWnd *m_pParent;成员函数Create(int nRow,int nCol,int nMineNum,int nX,int nY,CWnd *pParent);Reset(int nRow,int nCol,int nMineNum);//重新布局ReDraw(BOOL bFail);//刷新棋局LButtonDown(CPoint point);//左键按下BothButtonDown(CPoint point);//左键与右键同时按下RButtonDown(CPoint point);//右键按下MouseMove(CPoint point,int bBothDown);//鼠标移动LButtonUp(CPoint point);//左键弹起BothButtonUp(CPoint point);//左键与右键同时弹起OpenMine(int nCurMine);//开局函数IsSuccess(); //判断是否扫雷成功RndBtShdDn(int nCurMine);GetMineNum()//获取棋盘的雷数GetRight(int nCurMine)//获取四邻域的中心点像素正右方像素点的位置 GetLeft(int nCurMine)//获取四邻域的中心点像素正下左像素点的位置 GetTop(int nCurMine)//获取四邻域的中心点像素正上方像素点的位置GetBot(int nCurMine)//获取四邻域的中心点像素正下方像素点的位置3)布雷算法:首先定义一个n*n的二维数组,该数组的i-1到i+1,j-1到j+1除去i,j本身。
自动扫雷——概率分析之数学实现
⾃动扫雷——概率分析之数学实现前⾯的《》系列博⽂介绍了如何从XP⾃带的扫雷游戏中获取游戏、分析确定情况下的雷块,以及操作⿏标完成游戏。
这篇将介绍如何使⽤数学中的概率知识来玩扫雷游戏,也正是本⼈最想介绍的地⽅,即《》中所说的第四种扫雷模型的分析。
先看游戏界⾯,如下:在游戏开始时,如何出现这样的情况,我们可以认为游戏中未显⽰块按概率相等可分为四个区域,其中a,b,c是其中的三个区域(a区域指上⾯的5个块,b区域指中间的3个块,c区域指下⾯的5个块),再加上不与已揭开块相邻的所有块构成⼀个区域d(d区域含有465块)。
那么这四个区域中哪个区域有雷的概率最⼩呢?这⾥直接说明所使⽤的数学⽅法叫做——条件概率和全概率公式。
条件概率可以说是计算机领域的⼀个功⾂,由其发展⽽来的“统计语⾔模型”实现了机器翻译、语⾳识别、汉字识别等⼀系列的⽤传统⽅法很难解决的问题。
⽽以其为基础的“贝叶斯公式”在图像处理、决策⽀持系统和博弈论中有着⼴泛的应⽤。
维基百科中给的定义是:条件概率就是A在另外⼀个事件B已经发⽣条件下的发⽣。
条件概率表⽰为P(A|B),读作“在B条件下A的概率”。
⽽全概率为:假设{ B n : n = 1, 2, 3, ... } 是⼀个的有限或者可数⽆限的,且每个集合B n是⼀个,则对任意事件A有全概率公式:⼜因为此处Pr(A | B)是B发⽣后A的,所以全概率公式⼜可写作:⽤⾃⼰的话说,条件概率是在某件事发⽣的情况下,另⼀件事的概率;全概率是将所有情况的概率加起来。
⽽在扫雷游戏中有什么“所有情况”呢?看上⾯的游戏场景,a,b,c所占的13个块,如果仅仅根据上⾯所显⽰的"1","2",可以说这13个块中,雷的总数可以有2个,也可以有3个!!并且有2个或者3个的概率分别是1/2。
那么其情况如下:上表说明当雷数为2时,abc有雷的概率分别为0,1/3,1/5;当雷数为3时,abc有雷的概率分别为1/5,0,2/5。
扫雷研究报告
扫雷研究报告
《扫雷研究报告》是一份关于扫雷游戏的研究报告,内容可能包括以下方面:
1. 扫雷游戏的历史和起源:介绍扫雷游戏的起源,以及其在计算机和手机上的发展历程。
2. 游戏规则和玩法:详细解释扫雷游戏的规则和玩法,包括如何点击格子,如何识别地雷和数字提示。
3. 游戏策略和技巧:分享一些在扫雷游戏中取得高分的策略和技巧,如如何分析数字提示,推断地雷的位置等。
4. 扫雷游戏的算法研究:介绍一些用于解决扫雷游戏的算法,例如著名的“连锁反应”算法和“锚点”算法,并探讨它们的优势
和局限性。
5. 扫雷游戏的心理学研究:探讨扫雷游戏对玩家认知能力、逻辑思维和注意力的影响,以及其对玩家心理状态的潜在影响。
6. 扫雷游戏的应用领域:讨论扫雷游戏在其他领域的应用,例如在密码学、数据挖掘和人工智能领域的应用。
7. 扫雷游戏的改进和创新:提出对扫雷游戏的改进和创新建议,以提高游戏体验和挑战性。
8. 扫雷游戏的社交化:探讨扫雷游戏在社交媒体和在线平台上
的社交化趋势,如多人联机对战、排行榜竞争等。
9. 扫雷游戏的教育价值:分析扫雷游戏在教育和学习中的潜在价值,如培养逻辑思维、解决问题的能力等。
10. 扫雷游戏的未来发展趋势:展望扫雷游戏未来的发展趋势,如增加难度级别、加入虚拟现实技术等。
这份报告可以帮助读者更深入了解扫雷游戏的各个方面,并为相关领域的研究者和游戏开发者提供参考和启发。
同时,扫雷游戏也是一种常见的休闲游戏,这份报告也可作为普通玩家了解和提高自己游戏技能的参考资料。
windbg分析win7扫雷
在看雪首发地址:/showthread.php?t=159744查看堆栈0:000> kn# ChildEBP RetAddr00 0024f114 00136fe3 MineSweeper!Board::AttemptReveal 准备翻开一格函数01 0024f130 0013c9c9 MineSweeper!UIBoardCanvas::DoRevealAction+0x2c 翻开动作02 0024f154 0014685d MineSweeper!UITile::HandleEvent+0x4a403 0024f16c 00140494 MineSweeper!NodeBase::HandleEvent+0x2804 0024f18c 0014a40c MineSweeper!UserInterface::ProcessMouseUp+0x325 左键单击消息05 0024f648 75b1c4e7 MineSweeper!GameWindowProc+0x12cb06 0024f674 75b1c5e7 USER32!InternalCallWinProc+0x2307 0024f6ec 75b1cc19 USER32!UserCallWinProcCheckWow+0x14b08 0024f74c 75b1cc70 USER32!DispatchMessageWorker+0x35e09 0024f75c 00145a2a USER32!DispatchMessageW+0xf0a 0024fe14 001352e1 MineSweeper!InitializeEngine+0xcf70b 0024fe50 0013df26 MineSweeper!WinMain+0xb1下断点0:000> bl0 e 00130c50 0001 (0001) 0:**** MineSweeper!Board::AttemptReveal0:000> uf MineSweeper!Board::AttemptRevealMineSweeper!Board::AttemptReveal:00130c50 8bff mov edi,edi00130c52 55 push ebp00130c53 8bec mov ebp,esp00130c55 51 push ecx00130c56 53 push ebx00130c57 8b5d08 mov ebx,dword ptr [ebp+8][ebp+8]为转换为行列后的鼠标位置执行以后(edx为行,ebx为列) 00130c5a 56 push esi00130c5b 8bf1 mov esi,ecx00130c5d 8b4640 mov eax,dword ptr [esi+40h]00130c60 8b400c mov eax,dword ptr [eax+0Ch]00130c63 8b0498 mov eax,dword ptr [eax+ebx*4]00130c66 8b400c mov eax,dword ptr [eax+0Ch]以上5行命令取鼠标点击所在行的9个格子的状态用命令pa 00130c66执行到这里(截图是上次pa的,跟下面寄存器状态不在同一次)00130c66 8b400c mov eax,dword ptr [eax+0Ch] ds:0023:003f91cc=0163e198 eax=0163e198 ebx=00000004 ecx=003f9110 edx=00000008 esi=003f9110 edi=016628f8eip=00130c69 esp=0024f108 ebp=0024f114 iopl=0 nv up ei pl zr na pe nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200246 edx为行,ebx为列下面列出的数据即为第9列的状态0c表示空的格子,02即显示数字2,09表示未翻开,0b为? ,01表示当前正在点击0163e078 0c 00 00 00 0c 00 00 00 0c 00 00 00 02 00 00 00 09 00 ..................0163e08a 00 00 03 00 00 00 01 00 00 00 0c 00 00 00 0c 00 00 00 ..................0163e09c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ..................0163e0ae 00 00 00 00 00 00 00 00 00 00 79 cb f1 67 00 00 00 88 ..........y..g....参看下图鼠标点击在5行9列即(04,08)00130c69 57 push edi00130c6a 8b7d0c mov edi,dword ptr [ebp+0Ch]00130c6d 8b04b8 mov eax,dword ptr [eax+edi*4]以上2行命令取鼠标点击所在(行,列)的格子的状态顺便说一下: [ebp+0Ch]记录的是列号, [ebp+10h]记录的则是行号00130c70 33c9 xor ecx,ecx00130c72 894dfc mov dword ptr [ebp-4],ecx00130c75 83f809 cmp eax,9 是否为未翻开的状态00130c78 741b je MineSweeper!Board::AttemptReveal+0x45 (00130c95) 如果为未翻开,则转移到00130c95处MineSweeper!Board::AttemptReveal+0x2a:00130c7a 83f80b cmp eax,0Bh00130c7d 7416 je MineSweeper!Board::AttemptReveal+0x45 (00130c95)MineSweeper!Board::AttemptReveal+0x2f:00130c7f a1b4681900 mov eax,dword ptr [MineSweeper!Game::G (001968b4)] 00130c84 384818 cmp byte ptr [eax+18h],cl00130c87 745c je MineSweeper!Board::AttemptReveal+0x95 (00130ce5)MineSweeper!Board::AttemptReveal+0x39:00130c89 51 push ecx00130c8a 51 push ecx00130c8b 51 push ecx00130c8c e858f90000 call MineSweeper!GameAudio::PlaySoundProto (001405e9) 00130c91 33c9 xor ecx,ecx00130c93 eb50 jmp MineSweeper!Board::AttemptReveal+0x95 (00130ce5)MineSweeper!Board::AttemptReveal+0x45:00130c95 394e18 cmp dword ptr [esi+18h],ecx [esi+18h]记录点击次数如果还未点击过,则去布雷00130c98 7520 jne MineSweeper!Board::AttemptReveal+0x6a (00130cba)MineSweeper!Board::AttemptReveal+0x4a:00130c9a 57 push edi00130c9b 53 push ebx00130c9c 8bce mov ecx,esi00130c9e e818f4ffff call MineSweeper!Board::placeMines (001300bb)布雷函数,等下再分析00130ca3 6a00 push 000130ca5 57 push edi00130ca6 53 push ebx00130ca7 6a00 push 000130ca9 57 push edi00130caa 53 push ebx00130cab 8bce mov ecx,esi00130cad e890fdffff call MineSweeper!Board::revealAt (00130a42)00130cb2 895e24 mov dword ptr [esi+24h],ebx00130cb5 897e28 mov dword ptr [esi+28h],edi00130cb8 eb23 jmp MineSweeper!Board::AttemptReveal+0x8d (00130cdd)MineSweeper!Board::AttemptReveal+0x6a:00130cba 8b4644 mov eax,dword ptr [esi+44h]00130cbd 8b400c mov eax,dword ptr [eax+0Ch]00130cc0 8b0498 mov eax,dword ptr [eax+ebx*4]00130cc3 8b400c mov eax,dword ptr [eax+0Ch]用命令pa 00130cc6执行到这里00130cc3 8b400c mov eax,dword ptr [eax+0Ch] ds:0023:058e5b54=058e5ae8 eax=058e5ae8 ebx=00000008 ecx=00000000 edx=00000005 esi=01666c50 edi=00000005eip=00130cc6 esp=0024f104 ebp=0024f114 iopl=0 nv up ei pl nz na po nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200202 MineSweeper!Board::AttemptReveal+0x76:00130cc6 380c07 cmp byte ptr [edi+eax],cl ds:0023:058e5aed=00查看058e5ae8处内存,如下(01即表示雷)058e5ae8 00 00 00 00 01 00 00 00 00这是第9列的布雷情况,从上到下与上图完全相符小结: 从上面分析可知,这个函数有2个重要数据, [esi+40h], [esi+44h]从[esi+40h]一直往下,可以找到每列格子的状态从[esi+44h]一直往下,可以找到每列实际的布雷情况00130cc6 380c07 cmp byte ptr [edi+eax],cl 比较是否触雷00130cc9 7405 je MineSweeper!Board::AttemptReveal+0x80 (00130cd0)MineSweeper!Board::AttemptReveal+0x7b: 如果触雷00130ccb 894dfc mov dword ptr [ebp-4],ecx00130cce eb12 jmp MineSweeper!Board::AttemptReveal+0x92 (00130ce2)MineSweeper!Board::AttemptReveal+0x80:00130cd0 51 push ecx00130cd1 57 push edi00130cd2 53 push ebx00130cd3 51 push ecx00130cd4 57 push edi00130cd5 53 push ebx00130cd6 8bce mov ecx,esi00130cd8 e865fdffff call MineSweeper!Board::revealAt (00130a42)不是雷,则翻开格子MineSweeper!Board::AttemptReveal+0x8d:00130cdd 33c9 xor ecx,ecx00130cdf 8945fc mov dword ptr [ebp-4],eaxMineSweeper!Board::AttemptReveal+0x92:00130ce2 ff4618 inc dword ptr [esi+18h] 记录左键单击次数MineSweeper!Board::AttemptReveal+0x95:00130ce5 394e30 cmp dword ptr [esi+30h],ecx00130ce8 5f pop edi00130ce9 5e pop esi00130cea 5b pop ebx00130ceb 770f ja MineSweeper!Board::AttemptReveal+0xac (00130cfc)MineSweeper!Board::AttemptReveal+0x9d:00130ced a1b4681900 mov eax,dword ptr [MineSweeper!Game::G (001968b4)] 00130cf2 8b480c mov ecx,dword ptr [eax+0Ch]00130cf5 6a01 push 100130cf7 e8b86d0000 call MineSweeper!UIBoardCanvas::Refresh (00137ab4)MineSweeper!Board::AttemptReveal+0xac:00130cfc 8b45fc mov eax,dword ptr [ebp-4]00130cff c9 leave00130d00 c20800 ret 80:000> uf MineSweeper!UIBoardCanvas::DoRevealActionMineSweeper!UIBoardCanvas::DoRevealAction:00136fb7 8bff mov edi,edi00136fb9 55 push ebp00136fba 8bec mov ebp,esp00136fbc a1b4681900 mov eax,dword ptr [MineSweeper!Game::G (001968b4)]00136fc1 53 push ebx00136fc2 56 push esi00136fc3 8b7508 mov esi,dword ptr [ebp+8]00136fc6 57 push edi00136fc7 c680c500000001 mov byte ptr [eax+0C5h],100136fce ff761c push dword ptr [esi+1Ch]00136fd1 8bf9 mov edi,ecx00136fd3 ff7618 push dword ptr [esi+18h]00136fd6 8b0db4681900 mov ecx,dword ptr [MineSweeper!Game::G (001968b4)]00136fdc 32db xor bl,bl00136fde e835a4ffff call MineSweeper!Game::AttemptReveal (00131418)00136fe3 85c0 test eax,eax00136fe5 7f0a jg MineSweeper!UIBoardCanvas::DoRevealAction+0x3a (00136ff1)MineSweeper!UIBoardCanvas::DoRevealAction+0x30:00136fe7 89b79c000000 mov dword ptr [edi+9Ch],esi00136fed fec3 inc bl00136fef eb08 jmp MineSweeper!UIBoardCanvas::DoRevealAction+0x42 (00136ff9)MineSweeper!UIBoardCanvas::DoRevealAction+0x3a:00136ff1 50 push eax00136ff2 8bcf mov ecx,edi00136ff4 e8d4fbffff call MineSweeper!UIBoardCanvas::PlayTileRevealSound (00136bcd)MineSweeper!UIBoardCanvas::DoRevealAction+0x42:00136ff9 c687ac00000001 mov byte ptr [edi+0ACh],100137000 5f pop edi00137001 5e pop esi00137002 8ac3 mov al,bl00137004 5b pop ebx00137005 5d pop ebp00137006 c20400 ret 40:000> bl1 e 001300bb 0001 (0001) 0:**** MineSweeper!Board::placeMines0:000> uf MineSweeper!Board::placeMines 布雷函数MineSweeper!Board::placeMines:001300bb 8bff mov edi,edi001300bd 55 push ebp001300be 8bec mov ebp,esp001300c0 51 push ecx001300c1 51 push ecx001300c2 53 push ebx001300c3 56 push esi001300c4 57 push edi001300c5 8bf1 mov esi,ecx001300c7 e84ad70000 call MineSweeper!GetRandomSeed (0013d816)001300cc ff762c push dword ptr [esi+2Ch]001300cf 8945f8 mov dword ptr [ebp-8],eax001300d2 e84ad70000 call MineSweeper!SetRandomSeed (0013d821) 随机种子001300d7 6a10 push 10h001300d9 e8c9db0000 call MineSweeper!operator new (0013dca7) 存放随机种子001300de 59 pop ecx001300df 85c0 test eax,eax001300e1 740e je MineSweeper!Board::placeMines+0x36 (001300f1)MineSweeper!Board::placeMines+0x28:001300e3 6a10 push 10h001300e5 8bc8 mov ecx,eax001300e7 e86df8ffff call MineSweeper!Array<XmlNode const *>::Array<XmlNode const *> (0012f959) 001300ec 8945fc mov dword ptr [ebp-4],eaxpa 001300eceax=0171deb0 ebx=00000000 ecx=00000000 edx=00000010 esi=01666c50 edi=00000008eip=001300ec esp=0024df1c ebp=0024df30 iopl=0 nv up ei pl zr na pe nccs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200246MineSweeper!Board::placeMines+0x31:001300ec 8945fc mov dword ptr [ebp-4],eax ss:0023:0024df2c=01666c5001666c50这个地址是记录各列格子状态地址及游戏设置的难度值09*09 0a表示10个雷01666c50 bc 19 11 00 0a 00 00 00 09 00 00 00 09 00 00 00 00 00001300ef eb04 jmp MineSweeper!Board::placeMines+0x3a (001300f5)MineSweeper!Board::placeMines+0x36:001300f1 8365fc00 and dword ptr [ebp-4],0MineSweeper!Board::placeMines+0x3a:001300f5 8b4608 mov eax,dword ptr [esi+8]001300f8 0faf460c imul eax,dword ptr [esi+0Ch]001300f8 0faf460c imul eax,dword ptr [esi+0Ch] ds:0023:01666c5c=00000009 0:000> teax=00000051 ebx=00000000 ecx=00000000 edx=00000010 esi=01666c50 edi=00000008 eip=001300fc esp=0024df1c ebp=0024df30 iopl=0 nv up ei pl nz na po nc乘完后eax=51H,即表示9*9=81个格子,对应游戏格子如下:00 01 02 03 04 05 06 07 0809 0a 0b 0c 0d 0e 0f 10 1112 13 14 15 16 17 18 19 1a1b 1c 1d 1e 1f 20 21 22 2324 25 26 27 28 29 2a 2b 2c2d 2e 2f 30 31 32 33 34 3536 37 38 39 3a 3b 3c 3d 3e3f 40 41 42 43 44 45 46 4748 49 4a 4b 4c 4d 4e 4f 50001300fc 33ff xor edi,edi001300fe 85c0 test eax,eax00130100 7e49 jle MineSweeper!Board::placeMines+0x90 (0013014b)MineSweeper!Board::placeMines+0x47:00130102 8b4e0c mov ecx,dword ptr [esi+0Ch]00130105 8bc7 mov eax,edi00130107 99 cdq00130108 f7f9 idiv eax,ecx0013010a 33c9 xor ecx,ecx0013010c 2b5508 sub edx,dword ptr [ebp+8] 宽度0013010f 2b450c sub eax,dword ptr [ebp+0Ch] 高度00130112 85d2 test edx,edx00130114 0f9dc1 setge cl00130117 8d4c09ff lea ecx,[ecx+ecx-1]0013011b 0fafca imul ecx,edx0013011e 83f901 cmp ecx,100130121 7f13 jg MineSweeper!Board::placeMines+0x7b (00130136)MineSweeper!Board::placeMines+0x68:00130123 33c9 xor ecx,ecx00130125 85c0 test eax,eax00130127 0f9dc1 setge cl0013012a 8d4c09ff lea ecx,[ecx+ecx-1]0013012e 0fafc8 imul ecx,eax00130131 83f901 cmp ecx,100130134 7e09 jle MineSweeper!Board::placeMines+0x84 (0013013f)MineSweeper!Board::placeMines+0x7b:00130136 8b4dfc mov ecx,dword ptr [ebp-4]00130139 57 push edi0013013a e812590100 call MineSweeper!Array<Material::SavedRender *>::Add (00145a51)eax=00000000 ebx=00000000 ecx=016a4278 edx=00000000 esi=01666c50 edi=00000000eip=0013013f esp=0024df1c ebp=0024df30 iopl=0 nv up ei pl zr na pe ncMineSweeper!Board::placeMines+0x84:0013013f 8b4608 mov eax,dword ptr [esi+8] 设定的宽度00130142 0faf460c imul eax,dword ptr [esi+0Ch] 设定的高度00130146 47 inc edi00130147 3bf8 cmp edi,eax00130149 7cb7 jl MineSweeper!Board::placeMines+0x47 (00130102)循环9*9次pa 步过0013014bMineSweeper!Board::placeMines+0x90:0013014b 6a10 push 10h0013014d e855db0000 call MineSweeper!operator new (0013dca7)eax=0168bd08 ebx=00000000 ecx=00000010 edx=01620048 esi=01666c50 edi=00000051eip=00130152 esp=0024df18 ebp=0024df30 iopl=0 nv up ei pl nz na po nc00130152 59 pop ecx00130153 85c0 test eax,eax00130155 740e je MineSweeper!Board::placeMines+0xaa (00130165)MineSweeper!Board::placeMines+0x9c:00130157 ff7604 push dword ptr [esi+4]0013015a 8bc8 mov ecx,eax0013015c e8f8f7ffff call MineSweeper!Array<XmlNode const *>::Array<XmlNode const *> (0012f959) 00130161 8bf8 mov edi,eax 其实这个edi是个重要的数据00130163 eb31 jmp MineSweeper!Board::placeMines+0xdb (00130196)跳转MineSweeper!Board::placeMines+0xaa:00130165 33ff xor edi,edi00130167 eb2d jmp MineSweeper!Board::placeMines+0xdb (00130196)MineSweeper!Board::placeMines+0xae:00130169 8b45fc mov eax,dword ptr [ebp-4]0013016c 8b00 mov eax,dword ptr [eax]00130169 8b45fc mov eax,dword ptr [ebp-4] ss:0023:0024df2c=0168bc900:000> teax=0168bc90 ebx=00000000 ecx=00000000 edx=0000000a esi=01666c50 edi=0168bd08eip=0013016c esp=0024df1c ebp=0024df30 iopl=0 nv up ei ng nz ac pe cycs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00200297 MineSweeper!Board::placeMines+0xb1:0013016c 8b00 mov eax,dword ptr [eax] ds:0023:0168bc90=0000004d0:000> teax=0000004d ebx=00000000 ecx=00000000 edx=0000000a esi=01666c50 edi=0168bd08eip=0013016e esp=0024df1c ebp=0024df30 iopl=0 nv up ei ng nz ac pe cy上面这2句命令取随机数(这里为4d) 下面的内存是第2 次产生的随机数4c0168bc90 4c 00 00 00 50 00 00 00 10 00 00 00 38 d8 6c 010013016e 85c0 test eax,eax00130170 762b jbe MineSweeper!Board::placeMines+0xe2 (0013019d)MineSweeper!Board::placeMines+0xb7:00130172 48 dec eax00130173 50 push eax00130174 6a00 push 000130176 e878d60000 call MineSweeper!GetRandom (0013d7f3) 产生随机数eax=00000002 ebx=00000000 ecx=0000004d edx=00000002 esi=01666c50 edi=0168bd08eip=0013017b esp=0024df1c ebp=0024df30 iopl=0 nv up ei pl nz na po nccall完后ecx记录随机数edx记录次数0013017b 8bd8 mov ebx,eax0013017d 8b45fc mov eax,dword ptr [ebp-4][ebp-4]为存放随机数的地址mov eax,dword ptr [ebp-4] ss:0023:0024df2c=0168bc900168bc90 4c 00 00 00 50 00 00 00 10 00 00 00 38 d8 6c 0100130180 8b400c mov eax,dword ptr [eax+0Ch] [eax+0Ch] ds:0023:0168bc9c=016cd838 00130183 ff3498 push dword ptr [eax+ebx*4]00130186 8bcf mov ecx,edi 把产生的随机数的个数送到[edi]中eax=016cd838 ebx=00000002 ecx=0168bd08 edx=00000002 esi=01666c50 edi=0168bd08eip=00130188 esp=0024df18 ebp=0024df30 iopl=0 nv up ei pl nz na po nc00130188 e8c4580100 call MineSweeper!Array<Material::SavedRender *>::Add (00145a51)0013018d 8b4dfc mov ecx,dword ptr [ebp-4]00130190 53 push ebx00130191 e808eb0000 call MineSweeper!Array<IEventListener *>::Remove (0013ec9e)MineSweeper!Board::placeMines+0xdb:00130196 8b07 mov eax,dword ptr [edi] ds:0023:0168bd08=000000010168bd08 01 00 00 00 0a 00 00 00 参考上面01是随机数的个数0a是总共数00130198 3b4604 cmp eax,dword ptr [esi+4] [esi+4]就是上面的0a0013019b 75cc jne MineSweeper!Board::placeMines+0xae (00130169)小结:这个循环产生10个随机数,作为雷的位置,比如随机数为08,则在下图08位置放雷(用**代替)00 01 02 03 04 05 06 07 **09 0a 0b 0c 0d 0e 0f 10 1112 13 14 15 16 17 18 19 1a1b 1c 1d 1e 1f 20 21 22 2324 25 26 27 28 29 2a 2b 2c2d 2e 2f 30 31 32 33 34 3536 37 38 39 3a 3b 3c 3d 3e3f 40 41 42 43 44 45 46 4748 49 4a 4b 4c 4d 4e 4f 50用pa 0013019d步过这个循环, 再观察[ebp-4] ss:0023:0024df2c=0168bc900168bc90 43 00 00 00 50 00 00 00 10 00 00 00 38 d8 6c 01 43是最后也就是第10个随机数,那么其他9个跑那去了呢?在前面00130188这个call里,可以找到答案,但是别急,往下看,MineSweeper!Board::placeMines+0xe2:0013019d 33c9 xor ecx,ecx0013019f 390f cmp dword ptr [edi],ecx ecx则清零,前面说过[edi]是0a001301a1 7621 jbe MineSweeper!Board::placeMines+0x109 (001301c4)MineSweeper!Board::placeMines+0xe8:001301a3 8b470c mov eax,dword ptr [edi+0Ch]mov eax,dword ptr [edi+0Ch] ds:0023:0168bd14=058db6b8现在可以发现[edi+0Ch]是不是很重要了,刚产生的10个随机数都存这边了!1 2 3 4 5058db6b8 02 00 00 00 2c 00 00 00 25 00 00 00 2b 00 00 00 44 00 ....,...%...+...D.6 7 8 9058db6ca 00 00 05 00 00 00 4d 00 00 00 4b 00 00 00 00 00 00 00 ......M...K.......10058db6dc 34 00 00 00把上面10个随机数在下图中用**替代** 01 ** 03 04 ** 06 07 0809 0a 0b 0c 0d 0e 0f 10 1112 13 14 15 16 17 18 19 1a1b 1c 1d 1e 1f 20 21 22 2324 ** 26 27 28 29 2a ** **2d 2e 2f 30 31 32 33 ** 3536 37 38 39 3a 3b 3c 3d 3e3f 40 41 42 43 ** 45 46 4748 49 4a ** 4c ** 4e 4f 50对照下图,哈哈革命尚未成功,同志还须努力001301a6 8b0488 mov eax,dword ptr [eax+ecx*4] 这是取第一个随机数02mov eax,dword ptr [eax+ecx*4] ds:0023:058db6b8=00000002001301a9 8b5e0c mov ebx,dword ptr [esi+0Ch] 取总列号001301ac 99 cdq001301ad f7fb idiv eax,ebxeax=00000000 ebx=00000009 ecx=00000000 edx=00000002 esi=01666c50 edi=0168bd08除完eax就是0行edx就是在第3(02h)列的意思001301af 8b5e44 mov ebx,dword ptr [esi+44h]001301b2 8b5b0c mov ebx,dword ptr [ebx+0Ch]001301b5 41 inc ecx001301b6 8b1493 mov edx,dword ptr [ebx+edx*4] edx=02h 即取第3 列格子数据mov edx,dword ptr [ebx+edx*4] ds:0023:0163e038=0171e0c00171e0c0 09 00 00 00 10 00 00 00 10 00 00 00 78 e0 71 01001301b9 8b520c mov edx,dword ptr [edx+0Ch] [edx+0Ch]就是上面的0171e0780171e078 01 00 00 00 001301bc c6041001 mov byte ptr [eax+edx],1 置为1,表示有雷001301c0 3b0f cmp ecx,dword ptr [edi] 循环10次001301c2 72df jb MineSweeper!Board::placeMines+0xe8 (001301a3)pa 001301c4步过上面的循环小结:以上循环关键数据是[esi+44h],这里存放每列实际的布雷情况mov ebx,dword ptr [esi+44h] ds:0023:01666c94=003feb00mov ebx,dword ptr [ebx+0Ch] ds:0023:003feb0c=0163e030mov edx,dword ptr [ebx+edx*4] edx为列在0163e030存放了9个列地址1 2 3 4 50163e030 d0 ea 3f 00 90 e0 71 01 c0 e0 71 01 f0 e0 71 01 20 e1 ..?...q...q...q. .6 7 8 90163e042 71 01 50 e1 71 01 38 e1 71 01 78 bc 68 01 c0 bc 68 01 q.P.q.8.q.x.h...h第1 列刚布完雷还未点击003fead0 09 00 00 00 10 00 00 00 10 00 00 00 18 eb 3f 00 003feb18003feb18 01 00 00 00 00 00 00 00 00第9列0168bcc0 09 00 00 00 10 00 00 00 10 00 00 00 d8 bc 68 010168bcd80168bcd8 00 00 00 00 01 00 00 00 00对照原图,完全正确MineSweeper!Board::placeMines+0x109:001301c4 6a01 push 1001301c6 8bcf mov ecx,edi001301c8 e8c9faffff call MineSweeper!Array<Array<enum ETileStatus> *>::`scalar deleting destructor' (0012fc96)001301cd 8b4dfc mov ecx,dword ptr [ebp-4]001301d0 5f pop edi001301d1 5e pop esi001301d2 5b pop ebx001301d3 85c9 test ecx,ecx001301d5 7407 je MineSweeper!Board::placeMines+0x123 (001301de)MineSweeper!Board::placeMines+0x11c:001301d7 6a01 push 1001301d9 e8b8faffff call MineSweeper!Array<Array<enum ETileStatus> *>::`scalar deleting destructor' (0012fc96)MineSweeper!Board::placeMines+0x123:001301de ff75f8 push dword ptr [ebp-8]001301e1 e83bd60000 call MineSweeper!SetRandomSeed (0013d821)001301e6 c9 leave001301e7 c20800 ret 8关于修改方案1.在布雷函数中,用pa 001301a3步过如下:pa 001301a3MineSweeper!Board::placeMines+0xe8:001301a3 8b470c mov eax,dword ptr [edi+0Ch] ds:0023:0593580c=016b64e0 观察016b64e0(这个数据每次游戏都会变化)016b64e0 02 00 00 00 2c 00 00 00 25 00 00 00 2b 00 00 00 44 00 ....,...%...+...D.016b64f2 00 00 05 00 00 00 4d 00 00 00 4b 00 00 00 00 00 00 00 ......M...K.......把上面的10个随机数改为你想要的,如:016b64e0 00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 04 00 ..................016b64f2 00 00 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 ..................016b6504 09 00 00 00g无敌吧,哈哈年休完,明天又要上班了,源码尚未完成,待续!。
扫雷功能需求分析
扫雷功能需求分析界面是一个窗口,有菜单栏,标题栏和游戏区。
菜单栏里有游戏和帮助两个菜单。
一、游戏菜单里有:开局、初级、中级、高级、自定义、标记、颜色、声音、扫雷英雄榜、退出等10个子菜单;1、在游戏菜单里能够设置游戏的重新开局,也可以使用快捷键F2快速开启,也可以通过游戏区里的笑脸来重新开局;2、设置游戏的级别,分为初中高三个游戏级别,初级是由9*9的方格组成,雷数为10,非雷数71;中级由16*16的方格组成,排有40个雷,非雷数为216;高级是由16*30的方格组成,其中有99个雷,非雷数为381;3、自定义功能能够让玩家重新定义游戏的布局与雷数;颜色功能改变的是游戏区方块的颜色;4、标记功能在排雷的时候来重要作用,通过标记地雷,使客户快速通关,鼠标右键也可标记地雷。
5、声音功能,翻开方块,标记地雷,排雷和踩雷的声音都有不同,让客户玩起来更有意思;6、扫雷英雄榜,记录玩家不同级别的最高得分;7、退出,也可以用界面的关闭键结束游戏。
二、帮助菜单下包含查看帮助、关于扫雷、联机获得更多的游戏等3个子菜单;1、查看帮助,这个菜单主要说明的是游戏规.2、关于扫雷,主要说明扫雷的一些基本信息,版本号,版权号,谁制作等信息。
3、联机获得更多的游戏,能够从网上获得更多的游戏。
三、游戏区域,是由雷数、表情、计时器和方块区组成。
1、关于每个雷数,每个级别对应的雷数都不同,初级、中级、高级分别对应10、40、99个雷。
2、表情,游戏仍然在继续的时候显示微笑的表情,踩中地雷的时候显示悲哀的表情,当你成功排除了所有雷,就会显示酷的表情.3、在你翻开第一个方块起,计算器就开始计时,直到你成功排除所有地雷或者踩中地雷的时候就结束计时。
基于Python实现自动扫雷详解
基于Python实现⾃动扫雷详解⽬录准备实现思路窗体截取雷块分割雷块识别扫雷算法实现⽤Python+OpenCV实现了⾃动扫雷,突破世界记录,我们先来看⼀下效果吧。
中级 - 0.74秒 3BV/S=60.81相信许多⼈很早就知道有扫雷这么⼀款经典的游(显卡测试)戏(软件),更是有不少⼈曾听说过中国雷圣,也是中国扫雷第⼀、世界综合排名第⼆的郭蔚嘉的顶顶⼤名。
扫雷作为⼀款在Windows9x时代就已经诞⽣的经典游戏,从过去到现在依然都有着它独特的魅⼒:快节奏⾼精准的⿏标操作要求、快速的反应能⼒、刷新纪录的快感,这些都是扫雷给雷友们带来的、只属于扫雷的独⼀⽆⼆的兴奋点。
准备准备动⼿制作⼀套扫雷⾃动化软件之前,你需要准备如下⼀些⼯具/软件/环境- 开发环境1. Python3 环境 - 推荐3.6或者以上 [更加推荐Anaconda3,以下很多依赖库⽆需安装]2. numpy依赖库 [如有Anaconda则⽆需安装]3. PIL依赖库 [如有Anaconda则⽆需安装]4. opencv-python5. win32gui、win32api依赖库6. ⽀持Python的IDE [可选,如果你能忍受⽤⽂本编辑器写程序也可以]- 扫雷软件· Minesweeper Arbiter(必须使⽤MS-Arbiter来进⾏扫雷!)好啦,那么我们的准备⼯作已经全部完成了!让我们开始吧~实现思路在去做⼀件事情之前最重要的是什么?是将要做的这件事情在⼼中搭建⼀个步骤框架。
只有这样,才能保证在去做这件事的过程中,尽可能的做到深思熟虑,使得最终有个好的结果。
我们写程序也要尽可能做到在正式开始开发之前,在⼼中有个⼤致的思路。
对于本项⽬⽽⾔,⼤致的开发过程是这样的:完成窗体内容截取部分完成雷块分割部分完成雷块类型识别部分完成扫雷算法好啦,既然我们有了个思路,那就撸起袖⼦⼤⼒⼲!窗体截取其实对于本项⽬⽽⾔,窗体截取是⼀个逻辑上简单,实现起来却相当⿇烦的部分,⽽且还是必不可少的部分。
python实战教程之自动扫雷
python实战教程之⾃动扫雷前⾔⾃动扫雷⼀般分为两种,⼀种是读取内存数据,⽽另⼀种是通过分析图⽚获得数据,并通过模拟⿏标操作,这⾥我⽤的是第⼆种⽅式。
⼀、准备⼯作1.扫雷游戏我是win10,没有默认的扫雷,所以去扫雷⽹下载2.python 3我的版本是 python 3.6.13.python的第三⽅库win32api,win32gui,win32con,Pillow,numpy,opencv可通过 pip install --upgrade SomePackage 来进⾏安装注意:有的版本是下载pywin32,但是有的要把pywin32升级到最⾼并⾃动下载了pypiwin32,具体情况每个python版本可能都略有不同我给出我的第三⽅库和版本仅供参考⼆、关键代码组成1.找到游戏窗⼝与坐标#扫雷游戏窗⼝class_name = "TMain"title_name = "Minesweeper Arbiter "hwnd = win32gui.FindWindow(class_name, title_name)#窗⼝坐标left = 0top = 0right = 0bottom = 0if hwnd:print("找到窗⼝")left, top, right, bottom = win32gui.GetWindowRect(hwnd)#win32gui.SetForegroundWindow(hwnd)print("窗⼝坐标:")print(str(left)+' '+str(right)+' '+str(top)+' '+str(bottom))else:print("未找到窗⼝")2.锁定并抓取雷区图像#锁定雷区坐标#去除周围功能按钮以及多余的界⾯#具体的像素值是通过QQ的截图来判断的left += 15top += 101right -= 15bottom -= 42#抓取雷区图像rect = (left, top, right, bottom)img = ImageGrab.grab().crop(rect)3.各图像的RGBA值#数字1-8 周围雷数#0 未被打开#ed 被打开空⽩#hongqi 红旗#boom 普通雷#boom_red 踩中的雷rgba_ed = [(225, (192, 192, 192)), (31, (128, 128, 128))]rgba_hongqi = [(54, (255, 255, 255)), (17, (255, 0, 0)), (109, (192, 192, 192)), (54, (128, 128, 128)), (22, (0, 0, 0))]rgba_0 = [(54, (255, 255, 255)), (148, (192, 192, 192)), (54, (128, 128, 128))]rgba_1 = [(185, (192, 192, 192)), (31, (128, 128, 128)), (40, (0, 0, 255))]rgba_2 = [(160, (192, 192, 192)), (31, (128, 128, 128)), (65, (0, 128, 0))]rgba_3 = [(62, (255, 0, 0)), (163, (192, 192, 192)), (31, (128, 128, 128))]rgba_4 = [(169, (192, 192, 192)), (31, (128, 128, 128)), (56, (0, 0, 128))]rgba_5 = [(70, (128, 0, 0)), (155, (192, 192, 192)), (31, (128, 128, 128))]rgba_6 = [(153, (192, 192, 192)), (31, (128, 128, 128)), (72, (0, 128, 128))]rgba_8 = [(149, (192, 192, 192)), (107, (128, 128, 128))]rgba_boom = [(4, (255, 255, 255)), (144, (192, 192, 192)), (31, (128, 128, 128)), (77, (0, 0, 0))]rgba_boom_red = [(4, (255, 255, 255)), (144, (255, 0, 0)), (31, (128, 128, 128)), (77, (0, 0, 0))]4.扫描雷区图像保存⾄⼀个⼆维数组map#扫描雷区图像def showmap():img = ImageGrab.grab().crop(rect)for y in range(blocks_y):for x in range(blocks_x):this_image = img.crop((x * block_width, y * block_height, (x + 1) * block_width, (y + 1) * block_height))if this_image.getcolors() == rgba_0:map[y][x] = 0elif this_image.getcolors() == rgba_1:map[y][x] = 1elif this_image.getcolors() == rgba_2:map[y][x] = 2elif this_image.getcolors() == rgba_3:map[y][x] = 3elif this_image.getcolors() == rgba_4:map[y][x] = 4elif this_image.getcolors() == rgba_5:map[y][x] = 5elif this_image.getcolors() == rgba_6:map[y][x] = 6elif this_image.getcolors() == rgba_8:map[y][x] = 8elif this_image.getcolors() == rgba_ed:map[y][x] = -1elif this_image.getcolors() == rgba_hongqi:map[y][x] = -4elif this_image.getcolors() == rgba_boom or this_image.getcolors() == rgba_boom_red:global gameovergameover = 1break#sys.exit(0)else:print("⽆法识别图像")print("坐标")print((y,x))print("颜⾊")print(this_image.getcolors())sys.exit(0)#print(map)5.扫雷算法这⾥我采⽤的最基础的算法1.⾸先点出⼀个点2.扫描所有数字,如果周围空⽩+插旗==数字,则空⽩均有雷,右键点击空⽩插旗3.扫描所有数字,如果周围插旗==数字,则空⽩均没有雷,左键点击空⽩4.循环2、3,如果没有符合条件的,则随机点击⼀个⽩块#插旗def banner():showmap()for y in range(blocks_y):for x in range(blocks_x):if 1 <= map[y][x] and map[y][x] <= 5:boom_number = map[y][x]block_white = 0block_qi = 0for yy in range(y-1,y+2):for xx in range(x-1,x+2):if 0 <= yy and 0 <= xx and yy < blocks_y and xx < blocks_x:if not (yy == y and xx == x):if map[yy][xx] == 0:block_white += 1elif map[yy][xx] == -4:block_qi += 1if boom_number == block_white + block_qi:for yy in range(y - 1, y + 2):for xx in range(x - 1, x + 2):if 0 <= yy and 0 <= xx and yy < blocks_y and xx < blocks_x:if not (yy == y and xx == x):if map[yy][xx] == 0:win32api.SetCursorPos([left+xx*block_width, top+yy*block_height])win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0)win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0)showmap()#点击⽩块def dig():showmap()iscluck = 0for y in range(blocks_y):for x in range(blocks_x):if 1 <= map[y][x] and map[y][x] <= 5:boom_number = map[y][x]block_white = 0block_qi = 0for yy in range(y - 1, y + 2):for xx in range(x - 1, x + 2):if 0 <= yy and 0 <= xx and yy < blocks_y and xx < blocks_x:if not (yy == y and xx == x):if map[yy][xx] == 0:block_white += 1elif map[yy][xx] == -4:block_qi += 1if boom_number == block_qi and block_white > 0:for yy in range(y - 1, y + 2):for xx in range(x - 1, x + 2):if 0 <= yy and 0 <= xx and yy < blocks_y and xx < blocks_x:if not(yy == y and xx == x):if map[yy][xx] == 0:win32api.SetCursorPos([left + xx * block_width, top + yy * block_height])win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)iscluck = 1if iscluck == 0:luck()#随机点击def luck():fl = 1while(fl):random_x = random.randint(0, blocks_x - 1)random_y = random.randint(0, blocks_y - 1)if(map[random_y][random_x] == 0):win32api.SetCursorPos([left + random_x * block_width, top + random_y * block_height])win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0)fl = 0def gogo(): win32api.SetCursorPos([left, top]) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0, 0, 0) showmap() global gameover while(1): if(gameover == 0): banner()这个算法在初级和中级通过率都不错,但是在⾼级成功率惨不忍睹,主要是没有考虑逻辑组合以及⽩块是雷的概率问题,可以对这两个点进⾏改进,提⾼成功率总结以上就是这篇⽂章的全部内容了,希望本⽂的内容对⼤家的学习或者⼯作具有⼀定的参考学习价值,如果有疑问⼤家可以留⾔交流,谢谢⼤家对的⽀持。
扫雷实验报告(一)2024
扫雷实验报告(一)引言概述:本报告旨在总结和分析扫雷实验的结果,探讨扫雷算法的有效性和局限性。
通过对扫雷实验的详细观察和数据分析,以便进一步优化扫雷算法,提高扫雷的准确性和效率。
正文内容:1. 实验目的a. 确定扫雷算法的正确性和有效性。
b. 探索不同扫雷策略的优缺点。
c. 验证扫雷算法对于不同难度的扫雷游戏的适应性。
2. 实验方法a. 设计合适的测试环境和扫雷游戏界面。
b. 提供一系列难度不同的扫雷游戏供算法测试。
c. 运行不同的扫雷算法,并记录扫雷结果和所花时间。
3. 实验结果a. 分析不同难度的扫雷游戏下,扫雷算法的成功率和时间消耗。
i. 记录扫雷算法在简单、中等、困难难度下的扫雷结果。
ii. 统计扫雷算法完成游戏所花费的平均时间。
b. 比较不同扫雷算法之间的差异。
i. 对比不同扫雷算法在各难度下的成功率。
ii. 分析不同算法在扫雷游戏中的优势和劣势。
c. 分析扫雷算法的局限性和改进空间。
i. 总结扫雷算法在难度较高的游戏中的失效原因。
ii. 提出改进扫雷算法的可能方向和策略。
4. 实验讨论a. 探讨扫雷算法的适应性和泛化能力。
b. 分析实验结果对扫雷算法设计的启示和指导意义。
5. 实验结论通过对扫雷实验的分析和讨论,得出以下结论:a. 扫雷算法在简单和中等难度的扫雷游戏中表现良好,成功率较高。
b. 扫雷算法在困难难度下的扫雷游戏中存在一定局限性,需要进一步改进。
c. 提高扫雷算法的泛化能力和适应性是未来的研究方向。
总结:通过本次扫雷实验,我们深入探讨了扫雷算法的有效性和局限性。
在此基础上,我们可以进一步优化扫雷算法,提高扫雷的准确性和效率,并扩展其应用范围。
期待未来能有更多研究对扫雷算法进行改进,使其在各种难度的扫雷游戏中都能取得更好的效果。
扫雷总结报告
扫雷总结报告1. 引言扫雷游戏是一种经典的电脑游戏,从目前流行的Windows操作系统中被广泛采用。
本报告旨在总结扫雷游戏的规则和玩法,并提供一些相关的策略和经验分享。
2. 游戏规则扫雷游戏的目标是在一个方形的区域中,找出所有没有地雷的格子。
游戏开始时,玩家选择难度等级,并根据不同的难度等级在区域中随机生成地雷。
玩家通过逐步揭开不同格子中的数字来推断地雷的位置。
游戏区域中的每个格子可能有以下四种状态:•未揭开的格子:玩家无法得知格子内容,需要点击该格子来揭开。
•数字格子:揭开后会显示周围格子中地雷的数量。
•地雷格子:揭开后游戏失败。
•空白格子:揭开后周围没有地雷,可以一次性揭开相邻的所有空白格子。
通过分析数字格子周围的格子,玩家可以判断格子中是否有地雷。
3. 策略与技巧在扫雷游戏中,对于初学者来说,以下策略和技巧可能会有所帮助:3.1 先揭开空白格子在开始猜测数字格子之前,最好先揭开周围的空白格子。
这样做可以扩大已知信息的范围,有助于更好地推测地雷的位置。
3.2 排除地雷位置当揭开一个数字格子时,根据其显示的数字,可以推测周围格子是否存在地雷。
如果某个数字格子周围已揭开的格子都已经确定没有地雷,那么剩下的未揭开的格子就有可能是地雷。
3.3 注意边缘和角落边缘和角落的格子相对于中间位置的格子来说,周围的格子数量更少。
因此,初始情况下优先揭开这些位置的格子,可以获得更多有用的信息。
3.4 记录已知信息在进行扫雷游戏时,建议记录每次揭开的格子,并将已经确定的地雷格子标记出来。
这样可以避免重复猜测,并利用已知信息推测其他格子的内容。
4. 结论通过本报告的总结,我们了解了扫雷游戏的规则和玩法,并分享了一些策略和技巧。
掌握了这些知识后,希望读者能够在扫雷游戏中取得更好的成绩。
通过不断练习和经验积累,相信大家能够成为扫雷游戏的高手!如果读者有兴趣进一步提高自己的扫雷技巧,可以尝试寻找更多的资源和讨论。
有许多在线论坛和社区专门讨论扫雷游戏的策略和解法,参与其中将有助于开拓思路并加深理解。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一.“影响区域”划定
如上图,假如这个局面摆在我们的面前了。
只有红线圈定的内部区域里面的未被挖开的方块才可能被当前局面直接影响。
只有在红线圈定区域内的方块确定后,其他区域的未被挖开的方块含有的雷数才能由雷的总数做减法求得。
所以我们应该先尽可能的确定红色区域内部雷的分布情况。
顺便写几个有用的提示:红色区域内部的雷数是有多种可能的;红色区域内部每个方块有雷情况,有的可以精确地推出,有的不能精确推出,只能给个概率值了;最后红线外部每个方块有雷的概率是一样的。
二.算式推理技术
对影响区域每一位置都赋予一个符号名,或叫变量名,进行“算式推理”。
对于下图的局面(called by 局面1):
根据每个数字可以列出一个算式,总共得到3个算式:
a+b=1;
e+d=1;
a+b+c+d+e=2; 约束条件是a,b,c,d,e,f取0-1值。
对于下面的这个图(局面2):
根据每个数字可以列出一个算式,总共得到4个算式:
a+b=2;
a+b+c=2;
d+e=2;
b+c+d+e+f=3;约束条件是a,b,c,d,e,f取0-1值。
“算式推理”指得是由原始的算式集合S0(这里是4个算式)尽可能多的推出算式中符号的确定取值。
具体的算法如下:
1.若算式集合S0中含有类似局面2中a+b=2 这样的算式,即符号数目和
等号右边的数字相等,那么可以确定每个符号的值为1,然后把确定的
符号的值给S0中的其他算式中的该符号赋值,如此还可能出现类似c=0
这样的算式(对局面2带入a=1,b=1),即左边一些符号相加后得0,
那么也可以确定此类算式中每个符号取值0。
不断寻找集合S0中的所
有类似上面两种情况的算式,确定一些符号的取值,直到集合S0中没
有类似的算式。
此时得到的算式集合称作S0’。
局面1,S0最后化简得
到的S0’集合为:
a+b=1;
e+d=1;
a+b+c+d+e=2; 约束条件是a,b,c,d,e,f取0-1值。
局面化简后得到的是a=1,b=1,c=0,d=1,e=1,f=0。
这两个例子举得不好,
第一个没有得到化简,第二个全化简完了。
2.对S0’中的每两个式子之间做检测,若其中某个式子左边的符号是另一
个式子左边符号的子集,那么这连个式子相减得到一个新的式子,并
加入S0’。
如,局面1通过这个过程可以得到:
a+b=1;
d+e=1;
a+b+c+d+e=2;
c+d+e=1;
a+b+c=1;
把S0’看做S0,转到第一步继续计算。
直到集合不再能推出符号的确定
值,也不能产生新的算式为止。
这个算法最终得到的是一些符号的确定取值,还有一些不能“消融”的式子集合,把它叫做集合St。
下面给出局面2完整的演算过程:
1.a+b=1;e+d=1;a+b+c+d+e=2;(步骤一结果)
2.a+b=1;d+e=1;a+b+c+d+e=2;c+d+e=1;a+b+c=1;(步骤二结果)
3. a+b=1;d+e=1;a+b+c+d+e=2;c+d+e=1;a+b+c=1;(步骤一结果)
4.a+b=1;d+e=1;a+b+c+d+e=2;c+d+e=1;a+b+c=1;c=0;( 步骤一结果,每次只要两两检测上一轮新产生的算式和原来的算式就可以,而且有重复的话只留一个就可以)
5.a+b=1;d+e=1;a+b+d+e=2;c=0(步骤一结果,同样也要去重)
6.a+b=1;d+e=1;c=0(终止)
算式推理应该是线性代数里面的线性方程的求解或者数论里面的不定方程求解,肯定还有理论和实现上的优化,由于数学基础较差,只能做到这里了。
三,枚举手段
经过“算式推理的过程”,现在我们手头有一些符号确定了,还有一些符号不确定但是他们之间的约束集合St是有的。
接下来对于不确定的符号我们只能算出他们有雷的概率了。
为了编程实现的方便,我们可以采取回溯+枚举这种手段。
假设还有a1,a2,…,an 这些符号还没确定,b1,b2,…,bm这些符号确定了。
我们采用递归实现枚举a1,…,an取0-1的每种可能,中间结合不确定符号的约束关系做剪枝。
最终枚举出来的可能情况假设如下:
1110101011010….101 91
1010100101010….100 98
1111100010100….111 91
…
1000011101010….101 89
前面那个01阵是枚举结果,第i行j列表示第i个枚举中第j个未知符号是否有雷,最后一列是用雷的总数减去红线区域内部的类的数目得到的红线外部的雷的数目。
假设总共k个枚举结果,根据枚举结果我们可以统计出每个符号有雷的概率---用该符号位置是1的枚举结果数目除以总的枚举结果数目。
至于红线外部的方块,他们的有雷的概率都是一样的。
我们只能知道该区域含有雷的数目,至于他们怎么分布那就随便了。
这个概率的计算可以考虑全概率公式。
设枚举结果有100个91,110个90,106个89,105个93,红线外部有M个方块,我认为可以如下计算红线外部每个方块有雷的概率:
100+106+110+105=421
P=(100/421)*(91/M)+(110/421)*(90/M)+(106/421)*(89/M)+(105/421)*(93/M)
经过”影响区域”划定,“算式推理”,枚举手段,我们能够精确确定没挖掘方块中的一些是否有雷,以及不能确定的方块的有雷概率。
我们把确定没雷的都挖开,再使用上面的手段,再挖雷,直到有一个局面我们不能精确确定任何一个方块,只有概率可以参考,那就只能选个概率小的碰运气了。
至于程序实现,目前没时间。
唯一担心的就是那个枚举太耗时间了,然后有些资料上采用了排列组合的方法计算一个局面的每个方块的有雷情况,如《编程之美——4.11 扫雷游戏的概率- fivedoumi的专栏- 博客频道– CSDN》。
但是这种手段只是针对一个很简单的局面在稿纸上做个分析而已。
至于情况变复杂,这么多数字之间肯定是有影响的,还不知道怎么算呢,要是再编程实现就更困难了。
若是这种采用排列组合来算概率的手段得到很好的推到优化,计算速度肯定大幅提升,但是没时间考虑这些呢!
最后我发现扫雷游戏的初始局面要不是你中雷,要么是点中一个8邻域无雷的方块得到如下局面:
要么是你点中一个8邻域内有雷的方块,得到如下局面:
对于第二种情况,我们用宽度优先搜索呈现给玩家出事局面!。