扫雷游戏算法的研究


前一阵子参加了公司组织了一个编程比赛,要求在一个C-S架构的网页端扫雷游戏上,比拼谁的扫雷成功率高。很遗憾并没有得到名次。不过整个过程中的自己的收获还是很大的,在这里做一个小结。

首先,终于了解了如何使用代码跟网页进行交互。在参加这个小比赛之前写过一些网页自动化操作的小脚本,但是都是一些简单的网页操作,复杂点的涉及到需要前后端频繁交互的网页应用,就不太会用代码模拟了,而且优点纠结于怎么使用脚本模拟javasript这样的问题。这次经过同事的指点,终于知道完全不用管前端的javascript怎么执行,只要关注并模拟前后端交互的内容就行了。

其次,使用python来实现这个小程序,终于稍微熟悉了python这个语言,以前自学的时候看过python的书,也实现过一些简单的python脚本,但是始终没有什么正儿八经的小项目实操,这次的小比赛,麻雀虽小,但是五脏俱全,像我这样好多年都没怎么正经碰过代码的人来说,收益着实也不小。

再其次,麻雀虽小,五脏俱全,通过这个小程序,实际上一个人做了系统分析,代码实现,程序测试这整个过程的多次迭代,也收获了软件开发流程中各个阶段的好多的best practice。

上面的这几点,这次不打算展开记述了,这次主要想描述一下在写代码过程中对扫雷算法的不断理解和优化思索历程。事实上,我觉得这个过程也是一个很让人兴奋的过程。

扫雷游戏应该是所有人都不陌生的一个游戏,每个人或多或少都玩过这个游戏。如果把这个扫雷游戏当作一个题来解,我们尝试的就是力图给出一个完美的答案,那么我们首先要了解一下这个题的题面是什么,给了我们哪些条件,然后需要我们给出什么样的答案。

虽然这个游戏的规则非常的简洁和直接,绝大多数人都知道怎么玩,为了明确起见,还是稍稍总结一下游戏的规则:

  • 使用鼠标左键点翻开隐藏的格子,使用鼠标右键标记格子为雷。
  • 点开格子k,如果k是雷,那么游戏gameover。
  • 点开格子k,如果k不是雷,则显示数字,数字的含义为与k接壤的所有格子中雷的总数N,N取值最大可能情况为0~8。
  • 如果N为0,不显示0,而是与其接壤的格子全部显示数字,数字的含义依然是各自接壤格子雷的总数。注意这是一个递归的过程,这表明,如果某个与k接壤的格子假设为m,与m接壤的格子的雷的总数也是0的话,那么m接壤的所有的格子也会一起被显示,以此类推。
  • 直到如果所有的非雷的格子都被打开了,游戏胜利。
  • 游戏还有一个隐藏的规则,第一次点击时,会保证永远不会碰到雷。

同时在本次的比赛中的雷区,是长下面这样的:

  • 雷区是一个长方形,长为30个格子,高为16个格子,总格子数 30×16=480个。
  • 整个雷区的雷的总数为99个。

好,上面列出的就是题面给出的所有的条件了,需要求解的是,基于上面给出的条件,进行扫雷游戏,最终统计成功率,要求尽可能高的提高游戏的成功率。

那么代码的算法应该怎么设计呢?最容易想到的一个思路就是看看,我们自己人在玩这个游戏的时候是怎么一步一步往下玩的,看看能不能提炼出一些规律,总结出来,固化成算法体现在代码中。

在找规律之前,我么首先得要确认一个信念,那就是,并不存在一个完美的算法,或者说规律,能够让我们一步一步确定的找出所有雷的位置。一个最简单和直接的例子就是像下面的这样的情况:

XXXXXXXXX(第一次点击之后发现数字是1的情况)

上面的这种情况下,基于这样的条件没法判断出哪一个方块不是累,想要继续游戏时,没办法,只能要靠猜测了。

所以寻找扫雷算法的时候,必然会有两种方向,一类算法是基于盘面上的所有条件,尽量多的判断出哪些格子是雷,标记它们,哪些格子非雷,点开它们,这类算法可以叫做确定性算法。还有一类算法是,如果穷经了盘面上的所有条件,都不能再找出任何的是雷的格子和非雷的格子,那么我们要找出那些是雷的概率最小的格子,点击它们尝试继续游戏,这类算法可以叫做尝试算法。

确定性算法:

确定性算法显然是所有人喜欢的,毕竟尝试算法是有可能失败的。那么怎么来寻找确定性的算法呢?我们可以回忆一下我们自己是怎么来玩这个游戏的,尝试从里面来总结出规律。

最简单,其实也是最容易碰见的是下面的这样的盘面:

XXXXXX(数字和周围的雷个数是一样的)

很明显我们能够确定数字周围的格子都是雷,逻辑是如此的简单和直接。因为数字和周围的没有点开的格子数量是相等的,所以数字周边所有的格子都是雷!不妨从这个例子里面尝试提取一下背后的通用的规则。

  • 数字N周边3×3范围内,如果剩余未打开的格子数等于N的话,则所有的格子都是雷。

同时稍微思索一下就能够总结出来,还有一个跟上面规律相对等的规则:

  • 数字N周边3×3范围内,如果已经标记为雷的格子数等于N的话,那么剩余的所有未打开的格子都不是雷。

这两个规则非常的简单,看起来似乎并不能起很大的作用,但是实际上,仅仅依靠这两个简单的规则,就已经有能力顺利的挖出所有的雷了,只是相对来说,成功率并没有那么高,因为毕竟这两种规律描述的是相当巧合的场景,每次点开一个数字都能碰到的话,那确实是太幸运了。


Leave a Reply

Your email address will not be published. Required fields are marked *