数独sudoku(九)GUI游戏实现分析
Github完整项目地址:https://github.com/surpasss/software-engineering
大家好,上一期博客介绍了游戏说明,这一期从实现的角度分析几个关键过程,分成两部分,题目要求和完善性维护。
题目要求
1. GUI页面
对于页面生成,我借鉴了其他学长的代码,9×9棋盘是由81个textBox控件拼成的,每个控件是70×70像素大小,而5个按钮则分别对应5个Button控件。为每个控件设置字体格式、位置、大小、背景颜色等属性,用了1500多行代码,我觉得或许有其他统一设置属性的写法。
2. 残局来源
由于对c#语法比较陌生,我是通过调用事先准备好的、用C语言生成的sudoku.exe应用程序生成残局文件checkboard.txt和解决方案文件answer.txt。方法是:调用之前的生成终局函数生成1000个终局,保存在answer.txt中,然后对每个终局按照题目要求挖空一部分数字,最终把挖空的残局写入checkboard.txt中。
题目要求99棋盘上挖空不少于30个,不多于60个,每个33的小棋盘中挖空不少于2个。我的挖空方法是:首先对于9个33小棋盘,挖去随机数n(2≦n≦6)个数字,这样既可保证每个33小棋盘中的挖空数量不少于2个,又可保证总的挖空数量不多于60个。因为2×9=18 < 30,所以对于之前挖空数量小于30个的棋盘,继续在整个99大棋盘上随机挖空,直到总的挖空数量达到30个。实现的C语言完整代码如下:
#include "define.h"
int node[9] = { 0, 3, 6, 27, 30, 33, 54, 57, 60 };//每个3*3方块中左上角方格的序号
int bias[9] = { 0, 1, 2, 9, 10, 11, 18, 19, 20 };//3*3方块中的9个方格相比于左上角方格的序号偏置
void CreateCheckboard(int n)//需生成的终局个数
{
CreateSudoku(n);//生成n个终局
ifstream in("answer.txt");
if (!in)
{
cout << "Open File Failed!" << endl;
return;
}
stringstream buf;
buf << in.rdbuf();//一次性读取
in.clear();
in.close();
string s = buf.str();
srand((unsigned)time(NULL));
for (int index = 0; index < s.length(); index += 163)//循环每个终局
{
int num = 0;//该终局已挖空的方格数量
for (int i = 0; i < 9; i++)//循环9个3*3方块
{
int a = index + node[i] * 2;//该3*3方块左上角方格的下标
int n = rand() % 5 + 2;//随机生成该3*3方块需要挖空的方格数量,2<=n<=6
//printf("n: %d\n", n);
for (int j = 0; j < n; )//循环挖空,直到挖空n个方格退出循环
{
int m = rand() % 9;
if (s.at(a + bias[m] * 2) != '0')
{
s.at(a + bias[m] * 2) = '0';
j++;
}
}
num += n;
}
//printf("num: %d\n\n", num);
while (num < 30)//继续挖空,直到达到30个
{
int x = rand() % 80;
if (s.at(index + x * 2) != '0')
{
s.at(index + x * 2) = '0';
num++;
}
}
}
ofstream out("checkboard.txt");//将所有棋盘写入checkboard.txt文件
out << s;
out.clear();
out.close();
}
3.加载残局
设置一个全局变量num,程序启动时初始化为0,每点击一次“开始游戏”按钮,从checkboard.txt的对应位置读取残局,遍历每个数字,根据该数字是0还是非0设置棋盘中对应方格的背景颜色和字体颜色,之后num加1。
4. 判断对错
我使用的是之前在对生成终局进行正确性测试的方法,即:判断棋盘的每一行、每一列、每个3×3方块是否包含1~9。判断的方法很简单,用一个数组judge[10]保存涵盖情况,judge[i] == 0表示数字i不存在,judge[i] == 1表示数字i存在。judge数组每次初始化为0后,遍历该行或者该列或者该3×3方块的9个小方格,把小方格中数字对应的judge[i]置为1。遍历完9个小方格后,判断judge[i](1≦i≦9)是否都为1,如果不是,则说明求解错误;遍历完所有行、列、方块后说明求解正确。
完善性维护
完善性维护也称改善性维护,是为了满足用户在软件使用过程中提出的新的功能或性能要求。题目的要求很简单,但是从用户体验、异常处理和功能补充的角度,我做了多处改进。
1.用户体验
对于用户来说,软件的操作简单方便非常重要,甚至比功能和性能更重要。为了利于用户答题,我设置了上下左右键、WASD键、Tab键移动光标,而不是仅仅通过鼠标点击,因为鼠标频繁地在小范围区域内点击很影响用户体验。这里说明一点,我电脑的上下键不能移动光标,左右键可以,通过弹窗得知程序可以捕捉到上下键的按压,但是却不能调用聚焦函数,很奇怪。种种尝试未果后,我增加了WASD键,作为补充。而Tab键是在总共86个控件中快速顺序地移动光标。
2.异常处理
用户可能在可填写控件中填写任意类型、任意长度的数据,也可能在任意时刻操作任意控件,因此需要考虑种种情况,做出预防处理,防止出现异常情况。对于第一种情况,我设置了每个方格的最大填写长度为1、只接收对上述功能键的按压。对于第二种情况,我设置了没开始游戏就点击后三个按钮弹出相应提示、没开始游戏不能在任意方格中填写数据、开始游戏后不能修改方格的原始数据等。
3.功能补充
为了让用户体验到完成题目的快乐,我增加了提示和查看答案两个功能。每点击一次提示按钮,从第一个方格依次检查到最后一个方格,如果该方格尚未填写,则显示answer.txt中对应该残局、该方格的答案,并退出循环。用户点击查看答案按钮,显示answer.txt中对应该残局的答案。

浙公网安备 33010602011771号