软件工程实践2019第三次作业
GitHub项目地址:
我的github项目链接:https://github.com/54zhazhahui/131700114
需求
实现一个命令行程序,不妨称之为Sudoku。
百度百科简介:
数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。
具体任务:
现在我们想一步一步来,完成从三宫格到九宫格的进阶;完成三宫格和其他博客任务,就算过了初级考核,其他的算升级。具体各阶规则如下:
三宫格:盘面是33。使1-3每个数字在每一行、每一列中都只出现一次,不考虑宫;
四宫格:盘面是22四个宫,每一宫又分为22四个小格。使1-4每个数字在每一行、每一列和每一宫中都只出现一次;
五宫格:盘面是55。使1-5每个数字在每一行、每一列中都只出现一次,不考虑宫;
六宫格:盘面是23六个宫,每一宫又分为32六个小格。使1-6每个数字在每一行、每一列和每一宫中都只出现一次;
七宫格:盘面是77。使1-7每个数字在每一行、每一列中都只出现一次,不考虑宫;
八宫格:盘面是42八个宫,每一宫又分为24八个小格。使1-8每个数字在每一行、每一列和每一宫中都只出现一次;
九宫格:盘面是33九个宫,每一宫又分为3*3九个小格。使1-9每个数字在每一行、每一列和每一宫中都只出现一次;
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 10分钟 | 5分钟 |
Estimate | 估计这个任务需要多少时间 | 36小时 | 48小时 |
Development | 开发 | 4小时 | 6小时 |
Analysis | 需求分析 (包括学习新技术) | 2小时 | 6小时 |
Design Spec | 生成设计文档 | 2小时 | 4小时 |
Design Review | 设计复审 | 2小时 | 1小时 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 1小时 | 4小时 |
Design | 具体设计 | 1小时 | 1小时 |
Coding | 具体编码 | 2小时 | 1小时 |
Code Review | 代码复审 | 2小时 | 30分钟 |
Test | 测试(自我测试,修改代码,提交修改) | 2小时 | 8小时 |
Reporting | 报告 | 1小时 | 1小时 |
Test Repor | 测试报告 | 30分钟 | 10分钟 |
Size Measurement | 计算工作量 | 10分钟 | 20分钟 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30分钟 | 45分钟 |
合计 | 19.2小时 | 33.2小时 |
for (i = 0; i < m; i++)//输出解出的数独
{
for (j = 0; j < m; j++)
{
if (j < (m - 1))
ofp << a[i][j].num << " ";
else
ofp << a[i][j].num;
}
ofp << endl;
}
ofp << endl;
n--;
}
return 0;
}
**结构体定义数据**
struct number //每个数的结构体 sa
{
int sign;//定义一个标记,表示这个数还有几种可能的取值
int maybe[9] = { 1,2,3,4,5,6,7,8,9 };//定义num的可能取值
int num;//定义num的确定值
}a[9][9];
### 核心代码
核心代码是两个函数,一个**唯一值函数**,一个**排查函数**。
**唯一值函数**
void onlyone(int i, int j)//这个函数是把唯一解求出来;
{
for (int k = 0; k < line; k++) //唯一解在maybe里面
{
if (a[i][j].maybe[k] != 0)
{
a[i][j].num = a[i][j].maybe[k];
a[i][j].maybe[k] = 0;
a[i][j].sign = 0;
del(i, j);
break;
}
}
}
**排查函数**
void deletehl(int i, int j)
{
for (int k = 0; k < line; k++)//把同一行的sign减一,把maybe的可能取值变零
{
if (a[i][k].maybe[a[i][j].num - 1] != 0)//如果不等0,说明还没去掉这个可能;
//等0的话,说明前面已经去掉了,sign不用再减一了;
{
a[i][k].maybe[a[i][j].num - 1] = 0;
a[i][k].sign--;
if (a[i][k].sign == 1)
{
onlyone(i, k);
}
}//把同一行的相同可能值删掉
if (a[k][j].maybe[a[i][j].num - 1] != 0)
{
a[k][j].maybe[a[i][j].num - 1] = 0;
a[k][j].sign--;
if (a[k][j].sign == 1)
{
onlyone(k, j);
}
}//把同一列的相同可能值删掉
}
}
void deletegong(int i, int j)
{
//宫的首地址计算 //x,y;这个宫的首个数的地址为a[x][y] ;
int x, y;
x = (i / gongrow) * gongrow;
y = (j / gongline) * gongline;
for (int gi = 0; gi < gongrow; gi++)
for (int gj = 0; gj < gongline; gj++)//把同一宫的sign减一,把maybe【num】的取值变零
{
if (a[gi + x][gj + y].maybe[a[i][j].num - 1] != 0)
{
a[gi + x][gj + y].maybe[a[i][j].num - 1] = 0;
a[gi + x][gj + y].sign--;
if (a[gi + x][gj + y].sign == 1)
{
onlyone(gi + x, gj + y);
}
}
}
}
唯一值函数就是当一个空的可能性只有一种的时候,就可以填入了。
排查函数就是把同一列或同一行或同一宫的,已存在的值的可能性排除掉。
### 数据测试
下面是5和6宫格的数据测试结果
![](https://img2018.cnblogs.com/blog/1797348/201909/1797348-20190925220600589-545168212.png)
![](https://img2018.cnblogs.com/blog/1797348/201909/1797348-20190925220640289-1100503425.png)
### 性能分析
![](https://img2018.cnblogs.com/blog/1797348/201909/1797348-20190925223552849-1785591570.png)
![](https://img2018.cnblogs.com/blog/1797348/201909/1797348-20190925223640034-1913736679.png)
![](https://img2018.cnblogs.com/blog/1797348/201909/1797348-20190925223659569-995779287.png)
###总结
这次作业花了我很长的时间,但是也是收获满满。比如说学会了在github上传代码,还有vs2017的使用,还有文件输入输出!!!在写作业的过程中遇到了很多困难,很多bug,很多意想不到的问题,当是通过自己的努力,一步步攻克过来,最后成功解决。我觉得这个过程才是最重要的,也是我这次最大的收获。