Sudoku 小项目
Sudoku 小项目 - 软工第二次作业
Part 1 · 项目相关
- Github 地址: https://github.com/TheSkyFucker/Sudoku
项目的更多信息以及所有开发文档见 README.md
整体过程,Todolist工具: Teambition

- 部分动态

- 撰写该文时 SourceTree 结构如下:

Part 2 · PSP 表格
| Statu | Stages | 预估耗时 | 实际耗时 |
|---|---|---|---|
| Accept | 【计划】Planning |
60 | 100 |
| Accept | —— 估计时间 Estimate |
60 | 100 |
| Accept | 【开发】Development |
345 | 1550 |
| Accept | —— 需求分析 Analysis |
20 | 15 |
| Accept | —— 设计文档 Design Spec |
60 | 130 |
| Accept | —— 设计复审 Design Review |
15 | 20 |
| Accept | —— 代码规范 Coding Standard |
20 | 25 |
| Accept | —— 具体设计 Design |
30 | 300 |
| Accept | —— 具体编码 Coding |
180 | 1000 |
| Accept | —— 代码复审 Code Review |
20 | 30 |
| Accept | —— 测试 Test |
60 | 30 |
| Accept | 【记录用时】Record Time Spent |
10 | 10 |
| Accept | 【测试报告】Test Report |
40 | 20 |
| Accept | 【算工作量】 Size Measurement |
10 | 10 |
| Accept | 【总结改进】 Postmortem |
60 | 45 |
| Accept | 【合计】Summary |
585 | 1735 |
Part 3 · 解题思路
- 先按做acm题的心态思考了1~2小时,没想到什么比较优秀的做法;
- 然后疯狂搜索,因为一开始打算做附加题所以搜了不少附加题相关的内容。
- 先是搜到了:矩阵交换法的做法,觉得很机智很快,但是因为所有生成矩阵是等价矩阵所以不想采用这个做法
- 然后搜到了搜索法,这个比较直观,除了拉斯维加斯比较有心意,但是普遍效率都不是很好,基本都存在简单回溯的话确实本来随机性的意义。
- 然后搜到了一个不断随机每一行的做法,觉得很棒,博主也测试说很高效,结果实现了一下发现根本做不了,冷静下来分析了一下才发现是个假算法。。浪费了好多时间。
- 最后还是采取了矩阵交换法,虽然也在项目中实现了所有终盘随机质量很好的回溯法,但是没有在指令<-c>中实装,因为测试发现除非只有几k的数据要求量,不然时间要好几十秒乃至若干分钟。
- 当时想做附加题所以继续思考怎么做终盘,搜到的资料多是在挖空的位置上做文章。
Part 4 · 设计实现
(一)类之间的关系:

(二)代码组织
- 类:Sudoku、SudokuGenerator、SudokuChecker 在项目 Sudoku 里
- 类:SudokuTest、SudokuGeneratorTest、SudokuCheckerTest 在单元测试项目 SudokuTest 里
- 类:ParamChecker、CommandWorker 在项目 Command 里
- 类:ParamCheckerTest 在单元测试项目 CommandTest 里
- 主程序 main.cpp 在项目 Main 里
- 项目 Sudoku,Command 均设为静态
Part 5 · 代码说明
(一)内部函数:快速生成
- 主代码
- 主要思路:通过重编码数字、行、列从已有的终盘快速生成其它终盘。
- 注释:逻辑比较简单,就是找下一个行编码,列编码,数字编码,代码中有简单的英文短语注释。

(二)内部函数:高质量生成
- 主代码
- 主要思路:通过深搜,每次随机能当前格子合法的数字集合中随机一个数字放到当前行、列。
- 注释:传统深搜,短语注释了几个逻辑块。

(三)外部框架:指令系统
- 指令系统分为两个类,一个类是封装所有指令的参数校验,另一个类是实现所有指令的功能
- 从而做到能 高效的拓展指令,笔者搭建好框架后在添加指令<-check>以及<-help>途中感觉非常畅通,其它的代码都被隔开,那种仿佛在一张白纸上工作的感觉相当的棒。
- 整个框架:
- 主程序 根据
argv[1]判断指令,调用 主程序中相关指令函数段,并负责整个过程中抛出的 exception

- 相关指令函数段:调用 参数校验,接着调用 指令执行。

- 参数校验 框架:

- 指令执行 框架:

(四)程序运行
- 基本上所有的不合法输入都被 单元测试 和 指令系统框架的参数校验代码 ban掉了,所以只展示成功的界面。
<-help> 指令

<-c> 指令:测试100w的数据量,笔者本地运行时间大概 1s,CPU为 I7-4720HQ。

<-check> 指令:检验100w的数据量是否有重复,笔者本地运行时间大概6s,CPU为 I7-4720HQ。
(五)改进性能过程
生成改进一
- 最原本的判法是暴力判合法性,但是效率太低了。
- 编写的复杂的 Sudoku 类是主要为质量最好的 回溯法(SudokuGenerator::BestGenerate) 准备的,内部采用了维护每行、每列、每宫的状态来维护整个棋盘;
- 可以做到动态维护数独棋盘是否合法,每次修改格子都只要花几个常数的时间,O(1)查询当前终盘是否有冲突、是否合法等等。
生成改进二
- 一开始 矩阵转换法 习惯性的用了sudoku 存生成的方案,生成100w数据大概要60秒。
- 性能分析工具分析出Sudoku维护函数调用太多。
- 但是矩阵转换法由于是直接重编码,所以不需要维护合法性,换了一下生成100w大概要10秒,提速6倍左右。
生成改进三
- 输出一开始采取一个个输出,效率太低。
- 后面把每个棋盘弄成一个字符串然后puts输出,改进完后生成100w数据大概在 1 秒左右。
校验改进一
- 把每个棋盘压成一个string,然后扔进set来判重复。
- 改进后判定100w个棋盘速度大概在 6s左右。
(六)性能分析图
- 由于设计时就不打算提供非命令行运行,所以性能分析时采用输入信息嵌入主代码的方式。
- 性能分析图

- 分析数据量 1w,测试结果较理想。
- 按调用数排序,核心函数 std::next_permutation 调用次数 1w 多次,理论上生成1w的数据调用次数无法低于 1w

- 次数最高的函数为系统函数,其次是输出函数,函数如下:

(六)总结
- 偏工程方面的总结在 README.md 的文档里。
- 感觉几天内学到了好多东西吧,搜了不少东西,从一开始的把自己弄得手忙脚乱,commit的时候一堆东西揉在一起,代码习惯性的会往打acm题目的风格靠,git里还有100m+的输出文件就commit最后push崩溃才察觉到这个问题,设计了改改了再设计,时常写不出单元测试偷偷先去写主代码最后砸了自己的脚。
- 到后来慢慢熟悉了整个过程,回档fix bug,先写单元测试再写代码,检验文件无异常再commit和merge,每个功能新开一条git 分支编写然后merge回dev分支,VS又报错了也淡定了,exe崩溃了也知道自己可能有野指针或者内存泄漏,慢慢感觉到了一丝丝的秩序,虽然这一切还是按照自己临时搜的一堆资料构建出来的自以为的软件开发应有的流程Orz..但还是觉得学到了很多吧,也研究了一下怎么处理异常好一点,最后学了下try throw的那一套逻辑,但是可能姿势不太对还是搜的信息还不够所以也是按照自己的理解构建了目前项目的整个异常系统,函数声明也会留意要不要const 和throw等等。
- 然后突然发现不会打题了。
End。
Sudoku 小项目的更多相关文章
- 用struts2标签如何从数据库获取数据并在查询页面显示。最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变量。
最近做一个小项目,需要用到struts2标签从数据库查询数据,并且用迭代器iterator标签在查询页面显示,可是一开始,怎么也获取不到数据,想了许久,最后发现,是自己少定义了一个变量,也就是var变 ...
- IOS-小项目(饿了么 网络部分 简单实现)
在介绍小项目之前,在此说明一下此代码并非本人所写,我只是随笔的整理者. 在介绍之前先展现一下效果图. 看过效果图大家应该很熟悉了,就是饿了么的一个界面而已,值得注意的是,实现时并没有采用本地连接,而是 ...
- Andriod小项目——在线音乐播放器
转载自: http://blog.csdn.net/sunkes/article/details/51189189 Andriod小项目——在线音乐播放器 Android在线音乐播放器 从大一开始就已 ...
- 模拟XShell的小项目
不知道大家有没有用过XShell这款工具,这款工具通过windows可以远程操作处于开机状态的linux操作系统,也就是说把你的电脑和一台服务器连入网络,你通过输入服务器所在的IP地址建立一个会话就可 ...
- 小项目特供 贪吃蛇游戏(基于C语言)
C语言写贪吃蛇本来是打算去年暑假写的,结果因为ACM集训给耽搁了,因此借寒假的两天功夫写了这个贪吃蛇小项目,顺带把C语言重温了一次. 是发表博客的前一天开始写的,一共写了三个版本,第一天写了第一版,第 ...
- 【PHP小项目使用MVC架构】
小项目名称是雇员管理系统. mvc是一种项目的开发模式,中文名称为模式视图控制器,是强制程序员将数据的输入.处理.输出分开的一种开发模式. 在这个小项目中,控制器使用service作为后缀名. 项目u ...
- MOGRE学习笔记(3)--MOGRE小项目练习
学习OGRE有一段时间了,领导为了检测学习效果,根据已有C++项目,弄一个类似的用c#语言编写的小项目. 配置:win7,DirectX2009,vs2010. 项目要求: 1.有Ogre窗口(尺寸1 ...
- Web前端开发:SQL Jsp小项目(一)
Jsp的学习算是告一段落,针对这段时间的学习,写了一个Jsp小项目来巩固学到的知识. 框架示意图 User list process UserAdd process 需要的界面效果: 需要工具:Ecl ...
- Ado.Net小练习02(小项目CUID
前台界面: 后台代码: namespace ado.net小项目cuid { public partial class Form1 : Form { //连接字符串 ...
随机推荐
- asp .net core Get raw request.
小弟初来乍到,分享一些工作学习中遇到的问题和解决方式,如有不准确或是有错误的地方,希望不吝赐教,谢过了. --Dogtwo 背景: 一个代理服务器BK,接收前端A发送的请求,记录log,并转发给 ...
- EF 延时加载与死锁
第一种 #region 第一种延迟加载 用到的时候就会去查询数据. //用到的时候就会去查询数据. //IQueryable<UserInfo> temp = from u in dbCo ...
- mysql+mycat实现读写分离
centos7 master slave mycat1.6 client 192.168.41.10 192.168.41.11 192.168.41.12 192.168.41.13 实 ...
- c# dllimport 调用函数,参数乱码
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] [return: MarshalA ...
- 【Java每日一题】20170321
20170320问题解析请点击今日问题下方的“[Java每日一题]20170321”查看(问题解析在公众号首发,公众号ID:weknow619) package Mar2017; public cla ...
- Laravel 系列入门教程(四)【最适合中国人的 Laravel 教程】
本篇文章中,我将跟大家一起实现 Article 的新增.编辑和删除功能,仔细解读每一段代码,相信本篇文章看完,你就能够 get Laravel 使用之道. RESTful 资源控制器 资源控制器是 L ...
- module.js:549 throw err;
解决方法: 1.有可能是拼写错误 2.未明原因. (1)删除 node_modules 文件夹 (2)cnpm cache clean,不过提示错误就用 cnpm cache clean --forc ...
- jQuery效果之jQuery Color animation 色彩动画扩展
jQuery 的动画方法(animate)支持各种属性的过渡,但是默认并不支持色彩的过渡,该插件正是来补足这一点! PS: 该插件支持 RGBA 颜色的过渡,但是请注意,IE8以下的版本不支持 RGB ...
- Tars http服务
http服务 发布到平台后可以直接使用 http 请求来调用,注意发布服务时选择 非 tars 协议! 1,创建一个 springboot 项目,并在启动类添加 @EnableTarsServer 注 ...
- 开发Spring过程中几个常见异常(一)
异常一:java.lang.NoClassDefFoundError: org/apache/commons/logging/LogFactory 原因:未导入有关日志管理的jar包或者未添加到路径. ...
