数独-GUI开发


GUI界面开发

开发运行环境

??运行环境:JDK1.8

??运行命令:java -jar sudokuGUI.jar

??语言:java

??开发环境:Intellij IDEA 2019.2,JavaFX Scene Builder 8.3.0

项目结构和说明

??为了利用之前的源代码,UI界面采用javafx进行开发,使用MVC框架来设计整个应用,使用了数据绑定,通过构建容器组件,添加menu、监听器等实现图形化界面功能。

软件功能说明

??主要页面如下所示,一打开应用自动进行计时。

??点击菜单中的开始,可以开始新游戏、提交当前页面,查看答案,退出游戏。

??点击提交时,计时器停止,若有空位置没有填,会提示填满再提交,若有错误会弹窗会提示,完全正确时会弹窗恭喜用户。

面向对象分析设计

用例图
类图

总共有五个类
Main用于显示UI界面,界面用xml编写,在sample.xml中。
Controller监听图形页面、鼠标、键盘等。
Solve验证用户提交的数独是否正确。
Generate用于生成终局,对终局随机挖空,形成数独,显示在UI中。
AlterInfo用于弹窗提示。
SudokuCell表示数独中的每一个小块,控制是否可以输入,显示数字等。

状态图

设计思路

??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日 博客优化