创建随机的9x9数独游戏终盘并打印
创建随机的9x9数独游戏终盘并打印
1. 项目相关要求
1.1 要求
利用程序随机构造出N个已解答的9x9数独棋盘 。
输入
数独棋盘题目个数N(0<N<=1000000)
输出
随机生成N个不重复的已解答完毕的数独棋盘,并输出到sudoku.txt中。
1.2 思路
我是个会数独的人,一看到题目我第一反应是我最喜欢用的数独解法:锁定一种特定数字进行行列摒除。显然这种方法行不通,太麻烦了。
我上网找关于数独终盘的解法,发现一种思路比较满意。先随机生成一行,然后逐个填入行,这样工作9次就可以了。所以我需要一个能够生成随机行的函数。
同时我还发现,虽然摒除很难,但是在电脑上唯余法很容易实现,检查单元所在行、列、宫,这个单元能填什么数字一目了然。写一个唯余法的函数。
理论上只要从上到下、从左到右不断判断+填入就行了。我每行弄一个随机行,排队挨个塞入行中单元。把唯余判断的结果存在一个数组里面,从随机行取数的时候作为参考,只有合法且没用过的数才能放入单元。显然,要是9个数字都放不进去,单元填入就失败了,整行都失败了,要清空重来。
实际实现的时候发现在生成几个终盘之后,程序死循环了。分析发现某些情况下不管一行怎么试,行填入都失败,显然是前面的行生成有问题。并且不仅是最后一行,后面几行都有可能有这个问题。于是我就统计行失败次数,失败次数过多就全盘推翻重来。
2. 遇到的困难及解决方法
2.1 困难描述
我代码基础差,并且很久没有打代码了,所以这个源代码花了我好几个小时的时间。但是我觉得值,因为我能一点一点地推进,每次完成一个小目标,最后终于把整个程序打出来了。那种感觉很爽。
但是单元测试就是搞不定。
2.2 做过哪些尝试
花在单元测试上的时间:173分钟。
找了很多的博客,大多都语焉不详。从来没有一个博客我能够照着每一步做完的。我的最终成果:

我装了JetBrains,但是没有在菜单里面找到测试代码覆盖度的选项,如下图:

能够测试,但是不能使用我打的函数,用了就会提示未声明出错,没有一个博客给出过解释。
2.3 是否解决
未解决。
2.4 有何收获
解决不了的问题不要瞎耗时间,你的时间很宝贵。
不仅要有估计时间,更要有最大时间。最大时间到了就果断放弃,完美主义要不得。后面性能分析的时候我就学聪明了。
时间应该花在刀刃上,陷在“软件使用”这种坑里面很危险,不仅没用,还会令人愤怒焦躁、损害编程创造的兴趣。
3. 代码与设计
3.1 关键代码
/*
* 输入行、列位置,尝试向该单元填入数字。填入成功返回true,否则
* 返回false。
*/
bool filling_unit(int y, int x) {
/*
* 每次填入使用一次removeArray,所以需要初始化。排除完毕后根据
* removeArray顺序拿取randomArray中的数字,找到合适的数字,填
* 入成功;找不到,填入失败。
*/
memset(removeArray, 0, sizeof(removeArray));
remove_impossible_unit(y, x);
for (int i = 0; i < 9; ++i) {
if (randomArray[i] != 0) {
if (removeArray[randomArray[i] - 1] == 0) {
sudoku[y][x] = randomArray[i];
randomArray[i] = 0;
return true;
}
}
}
return false;
}
/*
* 填充数独盘面。
*/
void filling_sudoku() {
int rowDeathCount = 0;
for (int i = 0; i < 9; ++i) {
if (i == 0) {
/*
* 第一行直接填入行首为1的合法随机数组。
*/
generate_random_array_special();
filling_first_row();
}
else {
/*
* 生成合法随机数组,尝试填入行。填入行即为分别填入行内9
* 个单元,其中一个单元填入失败,填入行失败;否则成功。如
* 果填入行失败,重试。
* 在一个数独盘面内,如果填入行失败超过100次,重新执行该函
* 数。
*/
generate_random_array();
for (int j = 0; j < 9; ++j) {
if (!filling_unit(i, j)) {
delete_row(i);
j = -1;
generate_random_array();
rowDeathCount++;
}
if (rowDeathCount == 100) {
memset(sudoku, 0, sizeof(sudoku));
rowDeathCount = 0;
i = -1;
break;
}
}
}
}
}
3.2 设计说明

方框为函数,箭头为调用关系,绿色部分为main。不包括测试函数。
3.3 测试运行












3.4 性能分析
使用CPU采样-以项目为目标进行分析,出错:

使用CPU采样-以可执行文件为目标进行分析:

使用检测分析方法:

很奇怪,没有达到预期的效果。无法分析性能,但是我使用命令行运行exe,生成10000数独终盘大概花了7s时间。
4. PSP
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 10 | 6 |
| · Estimate | · 估计这个任务需要多少时间 | 10 | 6 |
| Development | 开发 | 450 | 908 |
| · Analysis | · 需求分析 (包括学习新技术) | 240 | 263 |
| · Design Spec | · 生成设计文档 | 20 | 40 |
| · Design Review | · 设计复审 (和同事审核设计文档) | 3 | 49 |
| · Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 7 | 5 |
| · Design | · 具体设计 | 30 | 53 |
| · Coding | · 具体编码 | 60 | 175 |
| · Code Review | · 代码复审 | 30 | 15 |
| · Test | · 测试(自我测试,修改代码,提交修改) | 60 | 308 |
| Reporting | 报告 | 50 | 144 |
| · Test Report | · 测试报告 | 20 | 18 |
| · Size Measurement | · 计算工作量 | 10 | 0 |
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 20 | 126 |
| 合计 | 510 | 1058 |
“单元测试”算在“测试”里面。
5. 记录自己的学习进度条(每周追加)
| 第N周 | 新增代码(行) | 累计代码(行) | 本周学习耗时(小时) | 累计学习耗时(小时) | 重要成长 |
|---|---|---|---|---|---|
| 0 | 415 | 415 | 19 | 19 | 学会使用VS2017、PSP流程 |
…
创建随机的9x9数独游戏终盘并打印的更多相关文章
- 使用Xamarin开发移动应用示例——数独游戏(一)项目的创建与调试
最近项目中需要移动客户端,由于团队基本上使用.Net产品线,所以决定使用Xmarin进行开发,这样技术路线统一,便于后期维护.官网上是这样介绍的" Xamarin 允许你使用 .NET 代码 ...
- 用 JS 做一个数独游戏(二)
用 JS 做一个数独游戏(二) 在 上一篇博客 中,我们通过 Node 运行了我们的 JavaScript 代码,在控制台中打印出来生成好的数独终盘.为了让我们的数独游戏能有良好的体验,这篇博客将会为 ...
- 用 JS 做一个数独游戏(一)
用 JS 做一个数独游戏(一) 数独的棋盘由 9x9 的方格组成,每一行的数字包含 1 ~ 9 九个数字,并且每一列包含 1 ~ 9 这 9 个不重复的数字,另外,整个棋盘分为 9 个 3x3 的块, ...
- 使用Xamarin开发移动应用示例——数独游戏(六)使用数据库
项目代码可以从Github下载:https://github.com/zhenl/ZL.Shudu .代码随项目进度更新. 现在我们希望为应用增加更多的功能,比如记录每个完成的游戏,可以让用户自己添加 ...
- C语言学习 数独游戏
摘要:花了1周多时间学习了C语言,开始练手写解数独游戏的程序. C语言学习 数独游戏 作者:乌龙哈里 时间:2015-11-22 平台:Window7 64bit,TCC 0.9.26(x86-64 ...
- 经典数独游戏+数独求解器—纯C语言实现
"心常乐数独小游戏"(下面简称"本软件")是一款windows平台下的数独游戏软件. 本软件是开源.免费软件. 本软件使用纯C语言编写,MinGW编译,NSIS ...
- Swift数独游戏优化——C++与OC混编、plist自动生成
一.为什么要C++与OC混编? 在我之前的数独游戏中涉及到的数独游戏生成算法是参考的网上其他人的算法,是利用C++来实现的. 但是在我的例子中我发现这样存在一定的局限性: 1.我是利用Termin ...
- iOS开发 Swift开发数独游戏(四) 游戏界面的界面与逻辑
一.游戏界面涉及到的功能点 1)数独格子的建模 (1)绘制数独格子要考虑到标记功能 所以要在每个格子内预先塞入9个标记数字,仅数独格子算下来就有9*9*9=729个格子且存在大量嵌套(这导致我在操作S ...
- 150+行Python代码实现带界面的数独游戏
150行代码实现图形化数独游戏 Github地址,欢迎各位大佬们fork.star啥的,感谢: 今天闲着没事干,以前做过html+js版的数独,这次做个python版本的,界面由pygame完成,数独 ...
随机推荐
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十二):解决跨域问题
什么是跨域? 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源. 同源策略是浏览器安全的基石. 如果一个请求地址里面的协议.域名和端口号都相同,就属于同源. ...
- nginx介绍(五) - 高可用
前言 即便想 nginx 这么牛B的服务器, 也不能保证他不挂啊, 就算不是机器出故障, 比如, 停电了, 那么机器挂了, 很正常啊. 这时候, 没有分发服务器, 网站就不能正常访问了, 咋搞? 网站 ...
- springboot json返回null问题处理
在开发过程中,我们需要统一返回前端json格式的数据,但有些接口的返回值存在 null或者""这种没有意义的字段.以上不仅影响理解,还浪费带宽,这时我们可以统一做一下处理:不返回空 ...
- kubernetes1.13之后的kubeadm init config
1.kubernetes1.13之后kubeadm开始GA,由于1.13的kube-proxy有bug,删除ipvs的地方总是导致kube-proxy挂掉,所以建议直接用1.13.2,这个版本解决了b ...
- 将代码从 spark 1.x 移植到 spark 2.x
1. SparkSession sparkSession可以视为sqlContext和hiveContext以及StreamingContext的结合体,这些Context的API都可以通过spark ...
- ios --键盘监听JYKeyBoardListener
没有前言,就是一个简单的键盘监听,自动调整输入框的位置不被键盘遮挡 .h // // JYKeyBoardListener.h // // Created by JianF.Sun on 17/9/2 ...
- 数据结构(java版)学习笔记(四)——线性表之循环链表
单向循环链表 PS:有阴影的结点是头结点 概念: 最后一个结点的链域值不为NULL,而是指向头结点 特点: 从表中的任意结点出发,都可以找到表中其他结点 循环条件 p==h 双向链表 概念 链表中的每 ...
- 给OkHttp Client添加socks代理
Okhttp的使用没有httpClient广泛,网上关于Okhttp设置代理的方法很少,这篇文章完整介绍了需要注意的方方面面. 上一篇博客中介绍了socks代理的入口是创建java.net.Socke ...
- Ansible安装 入门教程
learn一门新技术咯: ansible是新出现的自动化运维工具,基于Python开发,集合了众多运维工具(puppet.cfengine.chef.func.fabric)的优点,实现了批量系统配置 ...
- mysql中数据类型后面的数字到底是什么?
1.在mysql新建数据表的时候我们在数据类型后面经常会见到,或者添加数据,那么数据类型后面的数字到底是什么呢?之前以为int(3) 就代表最长数据就是3个字节,其实不是!! 我向num字段中插入: ...