(1)https://github.com/Agazelle98/MY_SUDOKU
(2)PSP表格(估计时间,见文章末尾)
(3)解题思路描述
数独生成
在拿到题目的之后,先了解了数独的游戏规则和求解数独的各种方法,发现只要第一行给出了确定的数字序列,那么其他八行能够通过第一行的变换得到一个完整的数独,首先将整个大九宫格分为九个3*3的小九宫格,然后再每个小九宫格中填入数字,检查数字并进行回溯,这里我选用了随机数生成法。
需求分析:
命令行格式:sudoku.exe -c N
1<=N<=1000000
数独不重复
数独左上角首数字固定。
可行性分析:我的首数字为(9+0)%9+1=1,只需要随机生成其他八个数字即可,这样有8!=40320种情况,经过回溯变换再生成其他八行,完全可以生成超过1e6个不重复的数独。
求解数独
在数独生成的基础上加上判断,按顺序把数字填入小九宫格,如果该数字没有合适的位置,则将上一个填入的数字进行替换,直到找到一个能够完全填满的方式。
需求分析:
命令行格式:sudoku.exe -s absolute_path_of_puzzlefile
0代表空,每个题目只要输出一个可行解即可
(4)设计实现过程
首个版本由于一开始没有找到解题简便方法,在生成数独的过程中是完全随机的,也就是说,在回溯的思路下,希望能够给出数独终局更多的随机性,但是没有考虑给出随机数字之后的检验问题,事实很快就告诉我这种方法不行,于是第一个版本被pass掉了。
之后通过上网查找方法和其他同学给的建议,放弃了完全随机的思想,而是小范围随机生成数字,通过规律变换生成最终数独,这是一个讨巧的办法,回溯的具体过程用到row,column, square三个9 * 9的数组做标记,记为1,记录每一行、列、九宫格中已使用的数字在初始数组中的index。一个循环结束后回退时把标记抹去。在求解数独时也是用了相同的方法。
下面是函数关系图,由vs企业版自动生成:
(5)程序改进及分析
改进的话在设计实现过程中提及过,主要是将完全随机改为首行随机加回溯变换。
数独生成改进:
左上角为1,先将9个1放入合法位置中,然后随机产生初始行,求解数独,然后由初始数独映射,每个初始数独能够生成8!个数独终局,由于9个1的位置不同,所以产生的初始数独不同。
文件输入输出改进:
将所有终局数独存在一个长字符串中一次性输出。
用ifstream,stringstream,string一次将文件内容读入。
下面是性能分析图
(6)代码说明
int **CreateArray();.....................................................................................................创建数独棋盘
int *CreateSet();..................................................................................................创建数组并初始化
void DeleteArray();..............................................................................................................删除数组
int FindSudokus();........................................................................................生成左上角第一格数独
int GenerateSudokus();...........................................................................................对数独进行变换
int* InitSet();...............................................................................................................生成数独首行
int SolvePuzzles();...............................................................................................................标记行列
void SudokuOutput();.............................................................................将结果存入outputStr数组
int PuzzleInput();..................................................................................................-s情况下棋盘输入
void print();.........................................................................................................................打印棋盘
int Transfer();.......................................................................................................将字符转换为数字
(7)PSP表格(实际时间,见文章末尾)
(8)总结
本次项目从清明节假期开始做,所以起点比别的同学稍晚了一些。vs2017、GitHub都是第一次使用,在学习软件运用的过程中花费了好多的时间,之前的编程课都是用的dev-cpp或codeblocks,所以在第一次使用vs时连创建项目都需要摸索,向同学请教后逐渐熟悉了vs的使用方法。在进行主项目编码的过程中,参考了网上给出的生成数独的方法,和一些其他同学的建议,使用的是随机数生成法,然后通过回溯变换生成数独终局,由于能力有限,优化也只做了文件的输出部分和数组优化。通过这次的个人项目经历,真正发现了自己与其他同学的差距,也是对自己学习能力和文档能力的一个提升,希望能为以后的项目做一个铺垫。
附录:PSP表格PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 60 |
·Estimate | ·估计这个任务需要多少时间 | 30 | 60 |
Development | 开发 | 2070 | 2730 |
·Analysis | ·需求分析(包括学习新技术) | 180 | 360 |
·Design Spec | ·生成设计文档 | 60 | 90 |
·Design Review | ·设计复审(和同事审核设计文档) | 60 | 60 |
·Coding Standard | ·代码规范(为目前的开发制定合适的规范) | 30 | 30 |
·Design | ·具体设计 | 120 | 120 |
·Coding | ·具体编码 | 1080 | 1440 |
·Code Review | ·代码复审 | 360 | 360 |
·Test | ·测试(自我测试,修改代码,提交修改) | 180 | 270 |
Reporting | 报告 | 300 | 300 |
·Test Report | ·测试报告 | 180 | 180 |
·Size Measurement | ·计算工作量 | 60 | 60 |
·Postmortem&Process Improvement Plan | ·事后总结,并提出过程改进计划 | 60 | 60 |
合计 | 2400 | 3090 |