《编程之美》读书笔记(七):数独游戏解析
前言:说实话,所有游戏都是有一定规律可循的,只要掌握游戏规则通关就会变得容易,所以像九连环和魔方这样的游戏会产生看一眼之后就闭着眼睛完成的高手出现。但是数独游戏有所不同,如果其初始状态的生成过程充分随机且空白比较多的话就不那么容易解决,所以数独矩阵的生成就是本题的关键。以往我的关注点主要在补充书中算法的遗漏或不足上面,但是由于感觉这个游戏确实挺好玩,而且作者也没把他的源码公布出来,所以我就利用书中的算法和自己想的算法作了一个数独生成器出来,大家有兴趣的话可以留言管我要,不过要回答本文最后提出的问题才可以J。
1 问题的描述与讨论
本文所说的数独是指:一个由9个3*3的子矩阵组成的9*9矩阵,其中每个3*3矩阵都由1-9这9个数字组成,且数独矩阵中每行每列都没有重复数字。在游戏的初始状态,数独矩阵是残缺不全的,玩家在填入数据时要保证数独的定义规则不被破坏。显然,残缺的数字越多,游戏就越困难。但是,如果被用户看出了数字的生成规律(如书中解法二介绍的行列变换生成法),填数就变成很简单的事情了。
于是我们的关注点就很明显了,就是要研究如何生成一个数独,但在此之前我们考虑一下问题:
1.有多少个数独(符合规则的9*9的矩阵)存在?
2.为什么行列变换生成法可以生成有效的数独?
3.如何使得生成的数独更具随机性?
1.1 关于独立有效的数独数量的讨论
这个问题书中第4.9节给出了一个求解数独数量的估计方法和一个与精确结果相差很小的估计值。大体的思路是,将3个在一行的3*3矩阵视为一个行向量,每个行向量内部仍然保证数独定义的约束,求出所有不同的行向量的数量(M1)3;同理也可以求出所有不同的列向量的数量(M2)3,并假设二者相互独立(事实上不完全独立),得到的估计值为6.657*1021,而精确值为6.671*1021。虽然书中并未给出精确值的求解方法,但是给出了参考文献,有兴趣的话可以去看一下。但是有些令我不解的是,在直观上,假设行列向量相互独立的情况下得出的数独数量应该多于不完全独立情况下的数量,毕竟在完全独立的情况下得到的一些矩阵可能会与数独的“每行每列数字不同”的约束相冲突而不能作为有效的数独。所以按照书中的估计方法,估计值应该大于精确值才对。所以应该用所有“块行解”的值乘2作为估计值,这个值虽然要比精确值大很多,但是觉得似乎更说得通。当然,也可能是我理解有误,有不同意见的朋友可以留言。
1.2 数独生成算法的分析
1.2.1. 方法一:回溯法
书中给出了两种方法,第一种方法还是使用回溯法,原理是构建一棵搜索树(深度为9*9),然后对每一个格子用不同的数字进行尝试,如果不与数独构造法则冲突则继续搜索,否则返回到上一个节点换个数继续搜索。这个方法的缺点很明显,在搜索过程中,对于每一个数都要考察其是否满足数独规则,即是否与所在小矩阵中的数字重复和是否存在行列重复。此外如果运气不好的话搜索过程可能会很漫长。好处是生成的数独足够“随机”,除了数独规则外没有什么规律可循,所以如果游戏的留白比较多的话将是一个很考验智商的题目。同时我们似乎可以用这种方法来得到所有合法数独的精确值(只是不知道我家的老爷机多长时间才能搞定J)。
1.2.2. 方法二:矩阵变换法
相比较第一种而言,书中给出的方法二是简洁高效得过了头。方法是以中间的矩阵为中心,利用列变换生成2号和8号矩阵(我们将所有子矩阵按照行优先的顺序从1-9进行编号),再使用行变换生成4号和6号矩阵,最后分别用4号和6号矩阵利用列变换生成1号、7号矩阵和3号9号矩阵。这样就最重形成了一个合法的数独。这种方法的具体实现过程在下一节会有详细说明。该方法唯一的好处就是简单,但是太过简单的生成方式很容易让玩家找到规律,降低了难度。
我在这里简单说明一下为什么这样做能够产生合法的数独。首先我们知道利用行列变换生成的2、4、5、6、8号矩阵是满足数独规则的,下面就只需要证明1、2、3号矩阵满足“每行都没有重复数字”且1、4、7号矩阵满足“每列都没有重复数字”。首先,4,5,6号矩阵所组成的向量中的每一行都没有重复数字,所以在这4号和5号矩阵内部进行任意的列变换都不会在行上产生重复数字。同时2号矩阵又是5号矩阵通过列变换得到的,所以1,2,3号矩阵在行上不会产生重复数字。而1和7号都是4号矩阵经过列变换的到,所以他们在列上不会有重复数字。证毕!
1.2.3. 方法三:其他方法
既然第二种方法太容易被识破,那么我们似乎应该开发一些复杂度低于第一种方法但是随机性比第二种方法好一些的生成算法来。我简单的想了一个,生成过程如下图所示:
首先随机生成对角线上的3个矩阵,然后按照后两图的方式采用方法一生成最终的数独。我想这样做即增加了随机性,也不会使太过于缓慢。不过这只是抛出去的“砖”而已,希望有兴趣的朋友能够提供一些更好的方法,有“玉”的朋友请不吝留言J。
1.3 数独游戏的实现
由于MSRA的网站上并没给出源码,我就自己用Java写了一个。下图是利用方法二制作数独的过程,有兴趣的朋友可以继续开发新的算法,让这个游戏更加丰满起来,在学到知识的同时还能娱乐自己。
2 后记
本节是我到目前为止看到错误最少的一节,几乎没有什么错误。关于我写的数独代码,自然是希望提供给有兴趣的朋友去研究新的生成算法,免去写界面的麻烦。但是有小小的要求:
1.点击左侧广告一次J
2.假设现要构造的是一个9*9的数独方阵,用Cell[9][9]保存,每个子方阵是3*3,每个子方阵的按照行优先进行编号,其编号分别为1,2,….,9。现给出方阵的编号,如何获取该方阵内的所有格子的坐标。例如,2号子阵中所包含的9个格子的坐标分别为:{{[0][3],[0][4],[0][5]},{[1][3],[1][4],[1][5]},{[2][3],[2][4],[2][5]}};假设现在给出第i号子阵,你能给出取得其中包含的格子坐标的计算公式吗。很简单吧?
3.请回答问题2的答案在程序写程序的时候哪里会用到(写出一个用途即可)。
请在下面用留言方式给出答案和邮箱地址,我会把源码发给回答正确的朋友。回答不正确的朋友也没关系,因为你将获得本游戏的界面源码(算法就靠你自己写了J)
分享到:
相关推荐
数独是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复。 ...
数独小游戏,可以用于微信小程序课程设计,有分数统计、排行、设置和主游戏界面
微信小程序源码:数独小游戏
java课程设计作业——基于java+swing构建的数独小游戏(源码+资源文件) 编程语言:java 界面绘制:swing IDE:MyEclipse,IDEA java课程设计作业——基于java+swing构建的数独小游戏(源码+资源文件) 编程语言...
数独:数独游戏
几何数独游戏,微博[@屠龙的胭脂](https://weibo.com/1852299857?refer_flag=1001030103_)所介绍[几何数独游戏视频介绍](https://video.weibo.com/show?fid=1034:4737961351381034)同款。源码在:[蛇蛇数独游戏源...
Sudoku1.5(Android游戏开发:数独(附源码).zip
秘籍(2):数独.doc
微信小程序 小游戏类 数独小游戏 (源代码+截图)微信小程序 小游戏类 数独小游戏 (源代码+截图)微信小程序 小游戏类 数独小游戏 (源代码+截图)微信小程序 小游戏类 数独小游戏 (源代码+截图)微信小程序 小...
用c++编程实现数独游戏,九宫格,其中主要运用一些常用的算法
winform数独C#的数独游戏 本程序基于.netframework使用C#语言开发,实现功能: 1、各个难度随机出题(New); 2、数独解题提示(Compute); 3、输入的合法性校验; 思路分享 说一下开发步骤及思路: 1、验证合法性...
请设计一个数独游戏,要求包括: 1, 基本要求:能按照不同难度级别设置随机的初始数独,允许用户在空格处填入数字完成数独游戏;在用户输入数字时,判断冲突,给出错误提示;计时,记录用户完成数独所用时间。 2, ...
(c++编程)高手数独游戏,详细设计步骤及注释!
基于 MFC 编写的一个数独小游戏源码。支持简单、普通、困难三种难度;支持读档、存档;支持自动计算数独结果。 预置20个游戏文件,使用快速载入游戏可随机载入这些游戏,可使用创建新游戏来产生新的游戏及游戏文件...
Android 功能完善的数独游戏源代码,关于这个游戏的玩法,这里不再赘述了,游戏编写上的特点,简要说明下: 这个游戏在界面上可支持更换三种游戏主题(草地绿、天空蓝、深沉黑)。同时游戏中还涉及到了许多的...
Python数独游戏源代码、源程序共包括两个程序文件:main.py及build.py
数独游戏的求解 第一步:确定数独中可以唯一确定的空位的值 第二步:用递归的方式确定剩余空位的值 (内含源程序和程序说明书)
内容概要:这个程序主要是用的搜索与回溯算法,最终得出数独的答案。 适合人群:有C++算法基础、热爱数独却不知道该怎么解答的人。 能学到什么:可以学到搜索与回溯算法的基本框架及应用范围,还可以尝试自己用这个...
JAVA的数独游戏代码,随机生成数独,如果有三个难度可选
数独 游戏解决方案 C 语言 结果存入文件 “厨师数据”中