软工实践第二次作业——数独9*9
GitHub
https://github.com/nnmaitian/shudu2017.9.10
项目要求
数独(Sudoku,Crosswords)是源自18世纪瑞士的一种数学游戏。是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、每一个粗线宫(3*3)内的数字均含1-9,不重复。数独盘面是个九宫,每一宫又分为九个小格。在这八十一格中给出一定的已知数字和解题条件,利用逻辑和推理,在其他的空格上填入1-9的数字。使1-9每个数字在每一行、每一列和每一宫中都只出现一次,所以又称“九宫格”。 ——《[百度百科](https://baike.baidu.com/item/数独/74847?fr=aladdin/)》
解题思路
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 10 |
· Estimate | · 估计这个任务需要多少时间 | 30 | 10 |
Development | 开发 | 2000 | 1800 |
· Analysis | · 需求分析 (包括学习新技术) | 120 | 80 |
· Design Spec | · 生成设计文档 | 20 | 10 |
· Design Review | · 设计复审 (和同事审核设计文档) | 30 | 10 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 10 | 15 |
· Design | · 具体设计 | 120 | 120 |
· Coding | · 具体编码 | 1500 | 1200 |
· Code Review | · 代码复审 | 60 | 60 |
· Test | · 测试(自我测试,修改代码,提交修改) | 20 | 20 |
Reporting | 报告 | 120 | 120 |
· Test Report | · 测试报告 | 60 | 60 |
· Size Measurement | · 计算工作量 | 15 | 20 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 120 | 30 |
合计 |
在9×9格的大九宫格中有9个3×3格的小九宫格,并提供一定数量的数字。根据这些数字,利用逻辑和推理,在其它的空格上填入1到9的数字。每个数字在每个小九宫格内只能出现一次,每个数字在每行、每列也只能出现一次。那么一共多少个数独矩阵呢?大家可以参看这个链接 http://www.afjarvis.staff.shef.ac.uk/sudoku/ 。There are 6670903752021072936960 Sudoku grids (Bertram Felgenhauer and Frazer Jarvis)。这么个数量级,真是吓人,没仔细学习之前我就以为仅有那么几个呢。
刚刚开始一脸懵逼,觉得跟跟路径的题有点像,估计有什么深搜广搜去遍历81个格子,百度了一下,一般是采用回溯法来产生整个九宫格的所有的数据,大概的实现思路都是现在第一行生成一组1-9不重复的数字,然后第二行开始不停的验证,不停的回退,然后再不停的验证,。而对于九九八十一格的数独游戏完整解生成,我们尝试按常规的回溯方法来实现,不免会出现回溯的解空间过于庞大而导致回溯的时间过长而无法满足游戏中我们产生游戏完全解的需要。为了减少这个时间,采用生成一行九位的随机数,按此顺序进行从左到右,从上到下,从第二行开始的填数。
设计实现
- 1.要有一个函数来完成第一行九位随机数的生成
- 2 一个函数来完成输入数据的判断(数字读入and错误输出err)
- 3.要有一个函数来判断每一行每一列每一宫有没有重复
- 4.要有一个函数来完成数字的填入,以及迭代
代码说明
1.
//随机生成一行1~9 第一个数为固定
auto init = [](int* list)
{
int jj = 0;
for (jj = 0; jj < 9; jj++)
{
*(list + jj) = jj + 1;
}
*list = (4 + 0) % 9 + 1; //学号031502404尾数为4 0
*(list + *list - 1) = 1;
unsigned seed = chrono::system_clock::now().time_since_epoch().count();//以时间设置随机种子
shuffle(list + 1, list + 9, default_random_engine(seed));//随机排列函数
/*for (jj = 0; jj < 9; jj++)
cout << *(list + jj) << " ";
cout << endl;*/
};
先生成一到九,第一位固定,以时间设置随机种子,再以随机排列函数对2到9位进行排列
2.
bool is_number(string str)
{
for (auto i = 0; i < str.size(); i++)
{
if (str[i]<'0' || str[i]>'9')
{
return false;
}
}
return true;
}
表示输入的字符串是否为数字
3.
auto judge_tf = [&scene](int i, int j, int num) -> bool
{
int k = 0;
//判断区域相同
int count = j % 3 + i % 3 * 3;
while (count--)
if (!(scene[i - i % 3 + count / 3][j - j % 3 + count % 3] - num))
return false;
//判断列相同
for (k = 0; k < i; k++)
if (scene[k][j] == num)
return false;
//判断行相同
for (k = 0; k < j; k++)
if (scene[i][k] == num)
return false;
return true;
};
来判断scene【i】【j】(第i+1行,第j+1列)的位置填入数字num是否符合条件
4.
//简单回溯方法填入数字
function<bool(int, int, int*)> fill = [&trylist, &fill, &scene, judge_tf](int y, int x, int* numloc) -> bool
{
if (y > 8)
return true;
if (judge_tf(y, x, *numloc))
{
scene[y][x] = *numloc;
/*for (int i(0); i < 9; i++)
{
for (int j : scene[i])
cout << j << " ";
cout << endl;
}
cout << endl << endl;*/
if (fill(y + (x + 1) / 9, (x + 1) % 9, trylist))
return true;
}
scene[y][x] = 0;
if (numloc - trylist >= 8)
return false;
if (fill(y, x, numloc + 1))
return true;
};
调用上一个函数来判断,填入的数字是否符合要求,不符合的话回溯
测试运行
-
测试样例
随机输出第一行5 9 4 2 7 1 6 3 8 ;与一组随机数3 4 7 9 5 8 6 4 1; -
进行填入
6填入失败,下一步回溯
第二行填完
生成数独完成
上传项目
-
GitHub是基于git实现的代码托管。git是目前最好用的版本控制系统了,非常受欢迎,比之svn更好。
GitHub可以免费使用,并且快速稳定。
利用GitHub,你可以将项目存档,与其他人分享交流,并让其他开发者帮助你一起完成这个项目。优点在于,他支持多人共同完成一个项目,因此你们可以在同一页面对话交流。
创建自己的项目,并备份,代码不需要保存在本地或者服务器,GitHub做得非常理想。推荐博客 http://www.cnblogs.com/specter45/p/github.html 。 -
创建github repository(仓库)
-
安装git客户端
-
绑定用户
-
为Github账户设置SSH key
图见上图。众所周知ssh key是加密传输。
加密传输的算法有好多,git使用rsa,rsa要解决的一个核心问题是,如何使用一对特定的数字,使其中一个数字可以用来加密,而另外一个数字可以用来解密。这两个数字就是你在使用git和github的时候所遇到的public key也就是公钥以及private key私钥。
其中,公钥就是那个用来加密的数字,这也就是为什么你在本机生成了公钥之后,要上传到github的原因。从github发回来的,用那公钥加密过的数据,可以用你本地的私钥来还原。
如果你的key丢失了,不管是公钥还是私钥,丢失一个都不能用了,解决方法也很简单,重新再生成一次,然后在github.com里再设置一次就行 -
建立本地仓库
创建新仓库的指令:
git init //把这个目录变成Git可以管理的仓库
git add README.md //文件添加到仓库
git add . //不但可以跟单一文件,还可以跟通配符,更可以跟目录。一个点就把当前目录下所有未追踪的文件全部add了
git commit -m "first commit" //把文件提交到仓库
git remote add origin git@github.com:wangjiax9/practice.git //关联远程仓库
git push -u origin master //把本地库的所有内容推送到远程库上
- 提交文件BIN
以为完成结果。。。BIN文件夹忘记加进去了。。。再来一次
- 加一条删除文件的内容
中间截图失误 回头就直接是历史的代码
总结
- 初始算法的时候,选择的比较简单,思路网上也比较清晰,编程过程还算顺利,其中调用stoi的时候,因为头文件的问题卡了一下,不管怎么说好久没有用c++答题了,重新熟悉了一下,以及丰富了几个会比较常见的用法,比如生成随机数的操作等等。
- 开始的时候看了几个比较难的算法,没有学会,比如十字链表什么的,没有去学会,有机会继续。
- 丰富了如何在GitHub上面创建项目,如何去使用git,去获得ssh,如何去上传一个项目,收获满满
nice!!!