# 基于JavaScript实现的数独游戏
# 一、问题描述
设计并实现一个基本的数独游戏。功能包括根据用户选择的级别给出初始盘面数字(级别越低,数字越多),并且能够实时监测并提示冲突;当用户完成后,保存最近十次的成绩(完成一次所需时间)以及最好成绩。
# 二、问题分析
数独是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3\*3)内的数字均含1-9,不重复。
因此,核心问题就是我们需要得到一个含有一定数目空格的九宫格,并且一定存在一种填写方式使得九宫格满足数独的要求。
我们可以先得到一个完整的,满足每一行、每一列、每一个粗线宫(3\*3)内的数字均含1-9,不重复的数独表。然后随机得到数独表中空格的位置,在通过可视化生成游戏界面,实现交互功能。
在用户与界面交互过程中,实时监测冲突是否产生,检验提交的答案是否正确,保存最近十次成绩和最好的一次成绩。
# 三、算法设计
本游戏为使用JavaScript开发的网页数独游戏,因此以下算法实现为JavaScript实现。
经问题分析可得我们需要解决的几个核心子问题,并设计算法如下:
## 3.1 传统回溯法生成数独表
网上提供的数独算法多种多样,但绝大部分的核心思想依然是传统回溯法:
通过一个9\*9的二维数组sudu表示一个数独九宫格。
首先初始化该数组,值都为0,然后将该九宫格的第一行依次随机填入1-9中的一个数字。接下来,从第二行开始,遍历该数组剩下的元素。
每遍历到一个位置,随机填入1-9中的一个数字,然后判断这个九宫格目前的所有数字是否满足每一行、每一列、每一个粗线宫(3\*3)内的数字均含1-9,不重复的要求。如果满足,继续向下一个位置遍历;如果不满足,则重新随机填写该位置。当重复填写了十次之后依然不满足要求,则回溯到上一个位置,重新填写该位置。
直到遍历完所有数组后,我们也就得到了一个完整的数独表。用sudu表示。
Math.floor(Math.random() \* 9 + 1)可得到1-9范围内的随机整数。
## 3.2 随机生成难度级别不同的数独
由3.1得,sudu数组保存着完整的数独表,那么游戏中的有空格的数独表可以用9\*9的二维数组curSudu表示,其中空格位置的数字设为0。如果填入了数字,则实时修改curSudu中该位置的值。
通过空格个数的不同来区分数独难度级别,空格个数越多,难度级别越高。设计该游戏难度级别有三个,分别为,初级:15个空格;中级:30个空格;高级:45个空格。
欲实现该需求,则先根据难度随机生成对应数目的空格的位置坐标(i,j),用数组表示为:blanks=[{row: i, column: j},……]。其中0 <= i <= 8, 0 <= j <= 8。通过Math.floor(Math.random() \* 9)即可生成需要的i,j。curSudu一开始等于sudu,得到blanks后将curSudu对应空格的值设为0。
## 3.3 用户填写数独时实时判断是否产生冲突
用户每填写完一个数字,都会触发判断冲突事件。由于之前填过的数字都被判断过,所以只需要判断刚刚填入的数字所在的行,列,粗线宫内是否满足条件。
首先保存刚刚填入的数字num,然后对所在的行,列,(3\*3)区域,分别进行遍历,假如遍历到的数字等于刚刚填入的数字并且所在的位置不同,则该填入数字在九宫格内产生了冲突;否则没有冲突。
## 3.4 保存最近十次成绩和最好成绩
设计成绩的数据结构为:
```c
let user = {
username: username,
time: time
}
```
时间表示成绩高低,时间越短,成绩越好。
每当游戏开始时,将当前时刻距 1970 年 1 月 1 日之间的毫秒数保存在全局变量time中。当提交答案,游戏结束时,time = ((new Date().getTime() - time) / 1000 / 60).toFixed(2),得到从开始到结束的时间,以分钟为单位,保留两位小数。
每次提交成绩时,将用户名和成绩保存在user中。然后从数据中通过getRank()得到最近的十次成绩(用长度为10的一维数组ranks表示),通过getMaxGrade()得到最好的一次成绩maxGrade。
将user.time与maxGrade.time进行比较,如果user.time比maxGrade.time更小,则maxGrade=user;然后将user插入ranks的最前面,去掉ranks最后一个元素,将ranks的长度保持在十。然后存入数据中。
# 四、软件架构
该软件是由JavaScript,HTML,CSS编写的的网页游戏,其中主要逻辑算法由JavaScript完成。而其软件架构为MVC模式
## 4.1 控制层(Controller)
JavaScript是一门事件驱动型的语言,通过在网页的特定DOM中绑定相应的事件监听,当用户在界面上特定的DOM元素上进行特定操作时就会触发对应的事件监听函数时,对逻辑进行处理。
## 4.2 视图(View)
该软件的界面由HTML和CSS决定,文件夹中的index.html和style.css会在浏览器的运行下生成对应的DOM树与样式,并在浏览器上渲染出界面。Js可以修改DOM树和样式,从而改变视图。
## 4.3 模型(Model)
sudu.js和index.js文件中保存着实现处理事件的对应代码。而数据保存在浏览器的localstorage中。因为由于规定对浏览器的限制,浏览器只能读取本地文件,却不能修改本地文件,所以在不使用服务器的情况下,本软件通过浏览器的localstorage来保存修改成绩。
# 五、实现与测试
## 5.1 软件实现
生成数独表和判断是否冲突的函数
在sudu.js中定义Sudu函数,返回函数:
回溯法生成数独表:gennerateShudu(), 判断填入元素所在的行,列,(3\*3)是否冲突:checkRow(), checkColumn(), checkNine()。
## 5.2 软件测试
**游戏初始界面**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/0d69f3d5998126b5644d3cf38dbe4b4a.writebug)
**选择难度为“初级”后点击‘开始游戏’按钮后游戏开始界面**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/1845c72136e5ced6c7653bfa06c5cd34.writebug)
**在第1行第2列填入5,产生冲突后右边文本框中提示冲突,空格颜色变红**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/994b054deee1004df48122ed8576f2be.writebug)
**在修改数字为9之后,冲突消失界面**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/ca443191fe5ad39711772568442c7f57.writebug)
**填满数字提交答案之前的界面**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/7e92a9a22d34ae24ca949c015ab76e11.writebug)
**点击‘提交结果’按钮后游戏界面,显示用时3.71min,要求输入用户名**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/2f8f219fdae17355f5b4eda185f4c2a3.writebug)
**填入用户名**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/a85e43d88be09b4e2954f62252fb1013.writebug)
**点击‘提交’按钮,成绩保存后的界面**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/049b74ddff4fe0c7cdd30f476770916a.writebug)
**点击‘排行榜’按钮,打开成绩榜单,显示最好的一次成绩与最近十次成绩,其中最近一次成绩yolanda:3.71min 保存在最前面**
![](http://www.writebug.com/myres/static/uploads/2021/10/19/f78cfcb7b0009185e9ee061aadd2c68a.writebug)
# 六、性能评价
传统的回溯法的性能较好,通过这种算法可以较快地得到满足数独要求的二维数组。但仍然存在可以优化的余地,不断的回溯的时间复杂度仍然较高,但在游戏中,并不碍事�