软件工程实践2019第三次作业
- Github项目地址
https://github.com/33lc/031702211
- PSP表格
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
Estimate | 估计这个任务需要多少时间 | 15 | 15 |
Development | 开发 | ||
Analysis | 需求分析 (包括学习新技术) | 120 | 180 |
Design Spec | 生成设计文档 | 60 | 90 |
Design Review | 设计复审 | 30 | 40 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 60 | 45 |
Design | 具体设计 | 60 | 60 |
Coding | 具体编码 | 240 | 180 |
Code Review | 代码复审 | 60 | 60 |
Test | 测试(自我测试,修改代码,提交修改) | 120 | 150 |
Reporting | 报告 | ||
Test Repor | 测试报告 | 150 | 180 |
Size Measurement | 计算工作量 | 40 | 30 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 60 | 100 |
合计 | 1015 | 1130 |
- 计算模块接口的设计与实现过程
void clear(int m);
void input(int m);
void output(int m);
int check(int step,int i,int j,int x);
int build(int step,int i,int j);
int search0(int step);
1. clear函数
由于存在多个盘面需要求解,故在每次解之前需将程序中原数组进行清零,clear函数便用于执行清零操作。
void clear(int step) //step为阶数
{
int i, j;
for (i = 0; i < step; i++)
for (j = 0; j < step; j++)
sd[i][j] = 0;
}
2. input函数
用于从文件输入需要解的盘面。
void input(int step) //step为阶数
{
int i, j;
for (i = 0; i < step; i++)
for (j = 0; j < step; j++)
cin >> sd[i][j]; //从文件输入sd[i][j]
}
3. output函数
用于向文件输出解出的盘面答案。
void output(int step) //step为阶数
{
int i, j;
for (i = 0; i < step; i++)
{
for (j = 0; j < step; j++)
{
cout << sd[i][j]; //向文件输出盘面,
if (j < step - 1)
cout << " ";
}
cout << endl;
}
cout << endl;
}
4. check函数
先检测横纵方向是否存在与即将输入的数相同的数,而后检查每一宫内是否存在与即将输入的数相同的数,若存在相同的数则返回,反之返回1。
int check(int step, int i, int j, int x) //阶数=step,待填的数横坐标=i,纵坐标=j,待填的数=x
{
int k, r, c, l;
for (k = 0; k < step; k++) //判断横纵是否存在相同的数
{
if (sd[i][k] == x || sd[k][j] == x)
return 0; //存在则返回0
}
if (step == 4) //判断四宫格内2*2小方格是否存在相同的数
{
r = i / 2;
c = j / 2;
for (k = r * 2; k < r * 2 + 2; k++)
{
for (l = c * 2; l < c * 2 + 2; l++)
if (sd[k][l] == x)
return 0;
}
}
else if (step == 9) //判断九宫格内3*3小方格是否存在相同的数
{
r = i / 3;
c = j / 3;
for (k = r * 3; k < r * 3 + 3; k++)
{
for (l = c * 3; l < c * 3 + 3; l++)
if (sd[k][l] == x)
return 0;
}
}
else if (step == 6) //判断六宫格内3*2小方格是否存在相同的数
{
r = i / 2;
c = j / 3;
for (k = r * 2; k < r * 2 + 2; k++)
{
for (l = c * 3; l < c * 3 + 3; l++)
if (sd[k][l] == x)
return 0;
}
}
else if (step == 8) //判断八宫格内2*4小方格是否存在相同的数
{
r = i / 4;
c = j / 2;
for (k = r * 4; k < r * 4 + 4; k++)
{
for (l = c * 2; l < c * 2 + 2; l++)
if (sd[k][l] == x)
return 0;
}
}
return 1; //若均不存在则返回1
}
5.build函数
看到题目的第一反应是回溯,但是由于不太熟练就不太想打...打了一个暴力版的三宫格,讨论了几种错误情况,逐渐麻烦...然后回来乖乖打回溯。
首先寻找需要填的空位,若该位置已存在数字,继续向下搜索。发现空位后,调用check函数检验1~9中那个数字填入是合法的,若存在合法的数填充后继续向下搜索填充,反之不存在合法的数则将该位置清零,并回溯。填充完毕时标志位op置1并退出。
int build(int step, int i, int j)
{
int x;
if (i > step - 1) //已填充完毕
{
op = 1; //标志位置1
return 0;
}
else if (sd[i][j] > 0) //该位置已存在数字,填充下一个
{
if (j < step - 1) //未填充到改行末,继续该行填充
build(step, i, j + 1);
else //已填充到行末,开始填充下一行
build(step, i + 1, 0);
}
else
{
for (x = 1; x <= step; x++) //尝试填入
{
if (check(step, i, j, x) == 1)
{
sd[i][j] = x; //该数字x未冲突,可以填入
if (j < step - 1) //未填充到改行末,继续该行填充
build(step, i, j + 1);
else //已填充到行末,开始填充下一行
build(step, i + 1, 0);
if (op == 1) //标志位已置1,结束
return 0;
sd[i][j] = 0; //出现冲突,清零
}
}
}
return 0;
}
6. search0函数
经过build和check函数运行后,若盘面仍有部分格子未被填充,说明题目本身是无解的,将通过search0函数进行查找并报错。
int search0(int step)
{
int i, j;
for (i = 0; i < step; i++)
{
for (j = 0; j < step; j++)
if (sd[i][j] == 0)
return -1;
}
return 0;
}
7.主函数
int sd[10][10],op=0; //全局变量
int main(int argc, char *argv[])
{
int step = atoi(argv[2]), repeat = atoi(argv[4]);
FILE *stream1, *stream2;
freopen_s(&stream1,argv[6], "r", stdin); //输入重定向
freopen_s(&stream2,argv[8], "w", stdout); //输出重定向
while (repeat--)
{
op = 0;
clear(step); //清零
input(step); //从文件输入
build(step, 0, 0); //回缩填充
if (search0(step) == -1) //无解题判断
cout << "error:no answer" << endl << endl;
else
output(step);
}
fclose(stdin); //关闭输入文件
fclose(stdout); //关闭输出文件
return 0;
}
- 计算模块接口部分的性能
主要的消耗还是在check和build函数,但是还没想到怎么优化...
- 单元测试
- 3阶,5阶,7阶
- 4阶,6阶,8阶
- 9阶
- 异常处理
做了一个无解的异常处理...
无解的情况下,build函数调用完毕后,宫图仍保持输入时有空位的情况,调用search0函数进行判断。
- 心得体会
数独从小就在玩,甚至现在手机里还有app(虽然因为有段时间没开它不兼容了...),但从未站在另一个角度去思考在解数独时会遇到什么?无解?多解?计算机应该怎么去处理这些情况?以后看问题也可以尝试从程序设计的角度去思考,或许会有不一样的发现。
这次实验一开始蛮迷茫的,int main(int argc,char *argv[])、文件输入输出,这些看着熟悉但是并没有用过的东西...文件输入输出本是c语言的内容,但当时这一章被跳过,自己也没有继续去学习。在这次实验中才开始学习,开始尝试寻找适合这次题目的输入方式。
在翻看《构建之法》时看到“这些同学是真的懂软件工程,是一个合格的软件工程师吗?”是啊,我也常常想过去的两年时光究竟学了什么,看似学了很多,却又像什么都不会...许多人都在追求完美,但完美真的存在吗?存在的只有相应时间空间下的“足够好”罢了。