第二次作业——数独终盘
1.github链接:
https://github.com/MeKChen/Software-Engineering/tree/master/SudokuProject
2.PSP表格:
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟)
----|------|----
Planning | 计划 | |
· Estimate | · 估计这个任务需要多少时间 | 30 |
Development | 开发 | |
· Analysis | · 需求分析 (包括学习新技术) | 120 |
· Design Spec | · 生成设计文档 | 30 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 15 |
· Design | · 具体设计 | 120 |
· Coding | · 具体编码 | 1300 |
· Code Review | · 代码复审 | 30 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 |
Reporting | 报告 | |
· Test Report | 报告 | 60 |
· Size Measurement | · 计算工作量 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 60 |
合计 | | 1885 |
3.解题思路:
拿到这个题目后,第一时间我想到的是要用到随机数和二维数组,因为要随机生成不同的数独终盘,那随机数和二维数组是需要用到的,根据数独的定义,行,列,九宫格都必须是1-9不同的数,我的第一种想法是,先生成一行包含1-9的随机数列,接在生成第二行完整的随机数列,再将这第二行放入二维数组,通过循环和判断语句来辨别这行每个数所在的列与九宫格是否符合数独定义,符合的话,再生成第三行,以此类推。虽然这种方法先用随机数将生成的每一行都确保符合数独定义,但是这种方法所需要的时间太多,实现起来比较难,比如第二行第一个数其实就已经出错了,但使用这种方法就必需完整的生成一行,后面生成的其实是毫无用处的。此时在查阅了资料后,我改变了思路,每生成一个数,就对其进行判断,这个数符合条件,继续下一个数的判断,我想到了递归。想到这一步时,我大致确定了一下整个程序需要的函数,main函数,judge(int x,int y,int q)函数(用来判断位置为(x,y)的数q与其所在行,列,九宫格的数是否重复),fill(int i,intj)函数(用来对位置(i,j)进行填数),judge函数在填数的时候就调用。想到这里整体的思路就比较完整了,开始动手试着写。
4.设计实现:
代码有main函数,judge函数,fill函数,rd函数。fill函数需要用到递归,并在fill的内部进行judge函数的调用,实现填一个数判断一个数;rd函数用来随机生成第一行的数。
5.代码说明:
①judge函数:判断位置(x,y)的数q与其所在的行,列,九宫格的数是否重复。在行中,判断当前位置左边的数与当前位置的数是否有重复;在列中就是判断当前位置上面的数与当前位置的数是否有重复。这两个的判断容易。在九宫格中,将其转换为数学问题,从当前位置(x,y)来得出需要进行判断的次数count,再通过每个数在九宫格的相对位置得到九宫格每个格子相对于整个数独棋盘的位置。代码如下:
bool judge(int x, int y, int q)
{
int i, j;
//判断行
for (i = x, j = 0; j < y; j++)
{
if (q == data[i][j])
return false;
}
//判断列
for (i = 0, j = y; i < x; i++)
{
if (q == data[i][j])
return false;
}
//判断九宫格
int count = y % 3 + x % 3 * 3;
while (count--)
{
if (q == data[ x / 3 * 3 + count / 3][ j / 3 * 3 + count % 3])
return false;
}
return true;
}
②fill函数:从第二行第一格开始填数,填数采用随机,每填一个数,调用judge函数判断,可行的话将当前位置后移一位,并进行fill的递归,直到整个棋盘可行。
bool fill(int i, int j)
{
int s,k,p;
if (i > 8)
return true;
s = 1 + rand() % 9; //使其填数不唯一
for ( k = 9; k > 0; k--)
{
p = (s + k) % 9 + 1;
if (judge(i, j, p))
{
data[i][j] = p;
if (j == 8)
{
i++;
j = 0;
}
else
{
j++;
}
if (fill(i, j))
return true;
}
}
return false;
}
③rd函数:使棋盘的第一行随机生成1-9的九个数,由于直接用随机数的话,会生成重复的数字,所以先将1-9存入一个数组,然后对数组下标进行随机,从第一个数开始,随机到哪个数,就把第一个数与此下标的数调换位置,再到第二个数,以此类推。打乱数的排列顺序达到随机的目的。
void rd(int a[])
{
int temp, random;
for (int i = 0; i <= 8; i++)
{
random = rand() % 9;
temp = a[random];
a[random] = a[i];
a[i] = temp;
}
}
6.测试运行:
当输入数字时,输出数独棋盘,当输入非数字时提示输入错误:
7.性能分析:
8.PSP表格:
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
· Estimate | · 估计这个任务需要多少时间 | 30 | 15 |
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 120 | 360 |
· Design Spec | · 生成设计文档 | 30 | 40 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 10 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 15 | 10 |
· Design | · 具体设计 | 120 | 40 |
· Coding | · 具体编码 | 1300 | 960 |
· Code Review | · 代码复审 | 30 | 100 |
· Test | · 测试(自我测试,修改代码,提交修改) | 60 | 110 |
Reporting | 报告 | ||
· Test Report | 报告 | 60 | 190 |
· Size Measurement | · 计算工作量 | 30 | 30 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 60 | 50 |
合计 | 1885 | 1915 |
9.总结:
第一次作业得分只有3.48分。拿到这个分数我并不觉得有什么不满。毕竟相对于其他人的博客,我写的确实是不用心,我也确实不喜欢计算机。在不喜欢计算机的前提下,第一次的博文也就草草了事。看到自己分数后,我也进行了反思,虽然不喜欢计算机,但是对于作业,对于这门课程,亦或是其他课程,要做的任何事,都要抱着积极、认真的态度去完成,这一点上,我要进行改正。
执行力代表的是办事能力。比如,一个团队一般有一名指挥,当指挥下达命令后,整个团队能迅速制定出对此任务的计划以及能迅速、高质量地完成此计划,这就是执行力;
泛泛而谈指肤浅地提出看法,不深入研究。一个人其实知道很多知识缺故意敷衍,这能称作泛泛而谈;或是一个人知道的知识不多,所以无法深入谈论,只能泛泛而谈。
这次作业碰到的困难和学习的新知识不少,例如通过利用打乱数字的排列顺序来生成一行不重复的1-9的随机数,对递归的应用,回溯法,从命令行输入,以及性能分析。代码复审的时候,在命令行输入这块上发现了问题,通过查阅资料和修改使其能正常运行。性能分析这块没有能很好的理解,目前还在学习中。