数独-GUI开发
GUI界面开发
开发运行环境
运行环境:JDK1.8
运行命令:java -jar sudokuGUI.jar
语言:java
开发环境:Intellij IDEA 2019.2,JavaFX Scene Builder 8.3.0
项目结构和说明
为了利用之前的源代码,UI界面采用javafx进行开发,使用MVC框架来设计整个应用,使用了数据绑定,通过构建容器组件,添加menu、监听器等实现图形化界面功能。
软件功能说明
主要页面如下所示,一打开应用自动进行计时。
![U](https://img2018.cnblogs.com/blog/1903333/202001/1903333-20200119124601131-590726771.png)
点击菜单中的开始,可以开始新游戏、提交当前页面,查看答案,退出游戏。
![U](https://img2018.cnblogs.com/blog/1903333/202001/1903333-20200119124639004-296391543.png)
点击提交时,计时器停止,若有空位置没有填,会提示填满再提交,若有错误会弹窗会提示,完全正确时会弹窗恭喜用户。
![没写](https://img2018.cnblogs.com/blog/1903333/202001/1903333-20200119124752195-2047818938.png)
![错误](https://img2018.cnblogs.com/blog/1903333/202001/1903333-20200119124811129-885269380.png)
![正](https://img2018.cnblogs.com/blog/1903333/202001/1903333-20200119124830750-558085829.png)
面向对象分析设计
用例图
![](https://img2018.cnblogs.com/blog/1903333/202001/1903333-20200119140443881-1142892102.png)
类图
总共有五个类
Main
用于显示UI界面,界面用xml编写,在sample.xml中。
Controller
监听图形页面、鼠标、键盘等。
Solve
验证用户提交的数独是否正确。
Generate
用于生成终局,对终局随机挖空,形成数独,显示在UI中。
AlterInfo
用于弹窗提示。
SudokuCell
表示数独中的每一个小块,控制是否可以输入,显示数字等。
![](https://img2018.cnblogs.com/blog/1903333/202001/1903333-20200119124744434-460687448.png)
状态图
![](https://img2018.cnblogs.com/blog/1903333/202001/1903333-20200119141712080-60409868.png)
设计思路
GUI中的主体代码和命令行部分几乎一致,最开始选择生成数独的回溯算法。最初实现UI界面,用了优化以后利用排列组合快速生成终局的算法,但因为终局是由变换第一宫形成的,所以存在规律性,降低数独的可玩性。所以采用了最初生成终局的回溯算法。
实现思路是先通过回溯算法生成一个终局,因为要求最少挖30个空,最多挖60个空,每个宫中最少有两个。当每个最少挖4个,4×9=36符合要求,每个宫最多挖6个,6×9=54个符合要求。所以循环九个宫,每个宫产生一个随机数n(4<=n<=6),然后在1-9中生成n个不同的随机数,在该宫中将n个随机数所在的位置挖掉,便生成了一个数独。
在编写代码的过程中,卡壳了很久一直在思考如何保证数独解的唯一性,但因为自己对这部分算法的理解并不是很深入,所以放弃了保证了数独解的唯一性。用户提交数独时,不与最初生成的终局比较,而是利用循环检查用户提交的答案中是否有错误,没有错误即为正确答案。若用户选择查看答案,则提供最初的终局。
自定义了一个数据类型SudokuCell,来存放数独中的每一个小块,其中设置一个属性write
保证可以多次修改答案,若数独中该位置需要填写,则将write设置为true,若不需要则设置为false,并且可以对每一个SudokuCelle用css进行美化,使数独的外观更加美观。
具体代码实现
对用户提交数独进行检查,正确时返回true,错误时返回false,这个方法在命令行中用于测试,检查对txt数独中求解时,是否有错误。
/**
* @Title: checkSolution
* @Description: 检查结果
* @param data
* @return boolean
* @throws
*/
boolean checkSolution(int[] data)
{
int index=0;
int[] criterion=new int[27];
Solve s=new Solve();
for (int j = 0; j < 27; j++) {
criterion[j] = 511;
}
s.setCriterion(criterion);
if(!checkSudoku(data,index,s))
return false;
return true;
}
/**
* @Title: checkSudoku
* @Description: 检查数独答案是否正确
* @param data
* @param index
* @param s
* @return boolean
* @throws
*/
private boolean checkSudoku(int[] data,int index,Solve s) {
for (int j = 0; j < 9; j++) {
for (int k = 0; k < 9; k++) {
while (data[index]>9 || data[index]<1)
{
index++;
}
int temp = data[index++];
if (!s.fill(j, k, temp)) {
Logger logger=Logger.getLogger("SolveTest");
logger.setLevel(Level.SEVERE);
String msg="row:"+(j+1)+"clo:"+(k+1)+"value:"+temp;
logger.severe(msg);
return false;
}else{
s.usedNum(j,k,temp);
}
}
}
return true;
}
测试
因为GUI项目中,除了UI部分代码,都是在命令行中经过测试的代码,所以只进行简单的系统测试,检测页面的响应、监听等是否正常。
编号 | 操作 | 预期结果 | 实际结果 | 状态 |
---|---|---|---|---|
1 | 页面有空位,点击提交 | 未完成弹窗 | 未完成弹窗 | 通过 |
2 | 页面没有空位,存在错误,点击提交 | 错误弹窗 | 错误弹窗 | 通过 |
3 | 正确完成数独,点击提交 | 正确弹窗 计时停止 |
正确弹窗 计时停止 |
通过 |
4 | 点击查看答案 | 显示答案 计时停止 |
显示答案 计时停止 |
通过 |
5 | 点击退出 | 退出程序 | 退出程序 | 通过 |
6 | 点击新游戏 | 开始新游戏 | 开始新游戏 | 通过 |
7 | 在空位输入非数字字符 | 输不进去 | 输不进去 | 通过 |
8 | 在空位输入数字字符 | 空位显示该数字 | 空位显示该数字 | 通过 |
9 | 点击查看答案以后,点击提交 | 正确弹窗 | 正确弹窗 | 通过 |
10 | 点击关于 | 信息弹窗 | 信息弹窗 | 通过 |
11 | 点击帮助 | 帮助弹窗 | 帮助弹窗 | 通过 |
简要开发过程
时间 | 内容 |
---|---|
2019年12月19日 - 2019年12月20日 | 需求分析、概要设计 |
2019年12月26日 - 2020年1月1日 | 基本完成命令行功能 |
2019年12月26日 - 2020年1月1日 | 开始单元测试 |
2020年1月2日 - 2020年1月3日 | 修改算法、对代码结构进行优化,完成测试 |
2020年1月4日 - 2020年1月16日 | 代码质量检测、UI编写 |
2020年1月17日 - 2020年1月18日 | 博客优化 |