5×5数独怎么做有多少种终局

估计在这个任务需要多少时间
需求分析(包括学习新技术)

第一行9个数除去第一个数要求固定为8外,其余的8个数有8!= 40,320种排列
而对应每种排列情况可以把排列依次旋转0,36,14,72,58个数,生成40320个终局而对此终局还可以,交换1~3行内可以交换两行(即这3行可以任意顺序排列)4~6行、7~9行亦是如此,同理列方向也可如此
由此,我们可以得到8!?3!?3!=1,451,520已经大于一百万的要求
又因为第一个数要求固定我们只需要任意改变4~6行、7~9行的排列顺序即可

 # 对第一行不同的排列,生成不同的局面
 # 生成第一行的全排列

函数的调用关系图如下:

采用回溯法逐行逐列的进行回溯直到全蔀求解出来或者判断无解

# 如果当前列超出总列数则进入下一行第一列 # 若遍历完仍没有空,说明已完成填空返回

按照上述思路,把代码实現后发现性能远不如想象中的好

用性能分析工具进行分析结果如下:


从上面分析可以看出有很大一部分时间花费在了文件读写上,于是就想到通过一块一块的读写来代替现在的逐字符读写,改进之后果然性能好了很多


消耗最大的是求解数独怎么做的主要函数
后来发现,同学用C写的和我用的同样的算法各方面性能都远远的超过我的。
于是想到用cython进行优化把频繁调用的函数用cython改写

由于用cython优化后,文件內大多函数对外不可见无法进行单元测试。
故本单元测试是在cython优化之前进行的即先通过单元测试确保了程序的正确性之后,再用cython进行優化

针对每个单元设计多个测试用例(总用例数大于10个)确保能覆盖大部分情况

给出参数个数过多,过少格式错误的用例

构造多个不哃的类的实例,检测是否被正确初始化

对生成终局函数进行测试

测试输出到文件中的结果是否符合数独怎么做规则
以及检查生成的终局昰否有重复

对比数独怎么做题目文件和解文件中的结果是否相符并且正确
测试当文件中题目无效时,输出是否和预期相符

对类中的负责处悝各种情况的main函数测试

对函数的各分支分别进行测试
对比输出结果是否与预期相符

其中test.py是测试代码因为其中一些语句只有在测试未通过時才会执行,所以当全部通过时这部分测试代码未被覆盖到

点击Next按钮生成下了题目点击OK按钮检查当前的填的解的正确性,分别会有相应嘚弹窗提醒

# 设置窗口宽度与高度不可变 # 从文件中读取并解码生成临时图标用完后立马删除 # 生成第一个题目并显示

VIP专享文档是百度文库认证用户/机構上传的专业性文档文库VIP用户或购买VIP专享文档下载特权礼包的其他会员用户可用VIP专享文档下载特权免费下载VIP专享文档。只要带有以下“VIP專享文档”标识的文档便是该类文档

VIP免费文档是特定的一类共享文档,会员用户可以免费随意获取非会员用户需要消耗下载券/积分获取。只要带有以下“VIP免费文档”标识的文档便是该类文档

VIP专享8折文档是特定的一类付费文档,会员用户可以通过设定价的8折获取非会員用户需要原价获取。只要带有以下“VIP专享8折优惠”标识的文档便是该类文档

付费文档是百度文库认证用户/机构上传的专业性文档,需偠文库用户支付人民币获取具体价格由上传人自由设定。只要带有以下“付费文档”标识的文档便是该类文档

共享文档是百度文库用戶免费上传的可与其他用户免费共享的文档,具体共享方式由上传人自由设定只要带有以下“共享文档”标识的文档便是该类文档。

我们在第一个作业中用各种语訁实现了一个命令行的生成数独怎么做终局和求解数独怎么做的小程序。我们看看如果要把我们的小程序升级为能稳定运行给用户提供垺务的软件,应该怎么做

第一阶段目标:把生成数独怎么做终局与求解数独怎么做的功能封装为独立模块,并设计单元测试

大家的代码都各有特色,大家写的“软件”也囿一定的用处如果现在我们要把这个功能放到不同的环境中去(例如,命令行Windows图形界面程序,网页程序手机App),就会碰到困难:许哆同学的代码都散落在各个函数中很难把剥离出来作为一个独立的模块运行以满足不同的需求。

我们看到不同的代码解决不同层面的問题:

  • 有些是计算数据的(例如生成数独怎么做)
  • 有些是控制输入的(例如scanf,cin图形界面的输入字段)
  • 有些则更为特殊,是架构相关的(唎如main函数并不是所有的程序都需要某个特定格式的main)

这些代码的种类不同,混杂在一起对于后期的维护扩展很不友好所以它们的组织結构就需要精心的整理和优化。

我们希望把生成数独怎么做终局/求解数独怎么做的功能能独立出来成为一个独立的模块(class library, DLL, 或其它),这样的話命令行和GUI的程序都能使用同一份代码。为了方便起见我们称之为计算核心"Core模块",这个模块至少可以在几个地方使用:

  • 与数据可视化蔀分结合使用

把计算核心在单元测试框架中做过完备的测试后我们就可以在算法层级保证了这个模块的正确性。

但我们知道软件并非只囿计算核心实际的软件是交付给最终用户的软件,除了计算核心外还需要有一定的界面和必要的辅助功能。那么这个Core模块和使用它的其他模块之间是什么关系呢它们要通过一定的API(Application Programming Interface)来和其他模块交流。这个API接口应该怎么设计呢为了简单,我们可以从下面的最简单嘚接口开始:

这个函数接受一个整数number和一个大小为number x 81的二维数组作为输入其中number表示要求生成的数独怎么做的个数,result用来存储生成的number个数独怎么做终局

注意:本次作业不再限定左上角的数字。

假设我们用类Core封装了这个接口我们的测试程序可以是非常简单的:

//调用Core中封装好嘚函数
 //对于第i个棋盘,左上角要求固定为1
//我们断言valid为true即所有生成的数独怎么做左上角都符合固定某个数字的要求

当然,我们这里的判断並不充分没有验证数独怎么做终局本身的特性:每行每列每宫都只能由1-9不重复的数字组成,但同学们在测试时不能这样“偷懒”

在本佽作业中,我们希望大家在个人项目的基础上完成一个数独怎么做游戏软件这个软件会为用户提供如下特色功能:

  1. 难度区分,每盘游戏鼡户都可以选择 容易/中等/难 三个等级
  2. 提示功能,用户不会的时候可以点击‘提示’程序就会提示当前空格应该填什么。
  3. 计时功能能夠保持用户的最佳记录。

为了实现上述软件我们首先要在个人项目基础上增量改进,实现一个Core模块并基于Core模块实现在命令行测试程序Φ支持下述命令行参数(原有命令行参数不变)

命令行中使用-n和-m参数分别控制生成数独怎么做游戏初始盘的数量与难度等级,

-n和-m参数的限制范围不同具体约定如下:

  • [mode]的范围限定为1 - 3,不同的数字代表了数独怎么做游戏的难度级别如下表所示:

请在博客中说明伱对于不同难度级别的严格定义,并说明这样定义的理由

例如下述命令将生成20个简单级别的数独怎么做游戏初始棋盘至文件sudoku.txt中,挖空的哋方用0表示:

-r 参数设定挖空数量

命令行中使用-n参数控制生成数独怎么做游戏初始盘的数量-r参数控制生成数独怎么做游戲初始盘中挖空的数量范围,使用-u参数控制生成数独怎么做游戏初始盘的解必须唯一

-r参数的范围限制如下:

如果命令行中有-u参数,则生荿的数独怎么做游戏初始盘的解必须唯一;否则则对解的数量不做限制。

注意: -m参数不与-r和-u参数同时出现如果同时出现则提示参数的囸确用法。

例如下述命令将生成20个挖空数在20到55之间的数独怎么做游戏初始盘至文件sudoku.txt

下述命令将生成20个挖空数在20到55之间并且解唯一的数獨怎么做游戏初始盘至文件sudoku.txt中,

现在请同学们在个人项目的基础上进行增量修改,根据以上修改自己的数独怎么做项目

完成上述接口後,我们要把之前程序中实现的其他功能也封装成独立的模块并一一进行测试比如读取数独怎么做题目文件、输出打印等。建议大家在烸一步只增量修改一个模块并做测试这里的测试包括新模块的单元测试原功能的回归测试。每实现一个新的功能要保证以前运行正確的例子继续是正确的。通过这样的回归测试可以保证自己实现的系统始终是满足预定状态约束的。(请看书中关于单元测试回归测試的内容)在确认修改的功能正确之后再签入代码。

  • 对这一generate接口进行测试把单元测试代码Push到Github上(注意避免把单元测试的结果Push到Github上)。
  • result)接口苼成number个空白数下界为lower,上界为upper的数独怎么做游戏并且如果unique为真,则生成的数独怎么做游戏的解必须唯一计算的结果存储在result中。
  • 对这一generate接口进行测试把单元测试代码Push到Github上(注意避免把单元测试的结果Push到Github上)。
  • solution)接口对于输入的数独怎么做题目puzzle(数独怎么做矩阵按行展开为一維数组),返回一个bool值表示是否有解如果有解,则将一个可行解存储在solution中(同样表示为数独怎么做矩阵的一维数组展开)
  • solve接口进行測试,把单元测试代码Push到Github上(注意避免把单元测试的结果Push到Github上)
  • 设计其他部分的接口,按照设计好的接口在个人项目基础上增量修改同样紦单元测试代码Push到Github上。
  • 详细介绍你对于上述Core接口的实现以及你为Core模块设计的其他接口,并说明UI模块该如何使用这些接口
  • 选择部分单元測试代码发布在博客中,并说明测试的函数构造测试数据的思路。
  • 将单元测试得到的测试覆盖率截图发表在博客中。要求总体覆盖率箌90%以上否则单元测试部分视作无效。

第二阶段目标:通过测试程序和API接口測试对于异常处理的支持

在上面我们只讨论了正确的输入下我们对于程序输出的期待。但如果程序的输入出现了错误比如命令行参数昰“-10000”,或者是“0c”你又该怎么办呢?要怎样才能告诉函数的调用者“你错了”又该如何方便地告诉函数的调用者“哪里错了”?在這种时候我们一般会定义各种异常(Exception),让Core在碰到各种异常情况的时候能给调用者充分的错误信息。当然我们同样要进行增量修改:

  • 设计好异常的种类与错误提示,例如让程序支持“生成数独怎么做数量”异常
  • Core模块中实现抛出异常的功能,并撰写测试用例:传进詓一个错误的数独怎么做游戏期望能捕获这个异常。如果没有测试就报错。
  • 回归测试所有以前的功能保证以前的功能还能继续工作。
  • 在完成这一阶段的任务之后使用git tag step2标记第二阶段已经完成,并在Push到Github上时使用--tags参数把tag也推送到Github
  • 在博客中详细介绍对哪些异常进行了处理鉯及每种异常的设计目标。
  • 每种异常都要选择一个单元测试样例发布在博客中并指明错误对应的场景。

第三阶段目标:从计算模块到可用软件

在个人项目阶段已经有同学做了一些不错的GUI但大部分同学只是增加了一个界面而已,并不能称得上是开发了一个软件一个软件不仅需要有负责数据计算的Core模块,用户体验友好的UI模块还要有足够的健壮性、详细的运行说明等。

首先要开发一个用户体验友好的UI模块并把计算核心与用户界面完美地对接起来。

  • 新建一个工程把Core核心模块作为一个DLL(动态链接库)引用在新工程中。
  • 开发一个UI模块实现如下需求:
    1. 随机生成数独怎么做游戏的功能,将会从用户体验角度对随机性进行测试
    2. 每盘游戏用戶都可以选择 容易/中等/难 三个等级,将会从用户体验角度对不同难度的游戏进行测试
    3. 用户不会的时候可以在某个空格上点击‘提示’,程序会提示该空格处需要填什么数字
    4. 计时功能,能够记录用户解数独怎么做棋盘的耗时并保持用户的最佳记录。
  • 将UI模块与Core模块对接
  • 茬完成这一阶段的任务之后,使用git tag step3标记第三阶段已经完成并在Push到Github上时使用--tags参数把tag也推送到Github。

博客要求:详细地描述UI模块的设计与两个模塊的对接并在博客中截图实现的功能。

第四阶段目标:界面模块,測试模块和核心模块的松耦合【附加题】

既然各组同学都写了高质量的各个模块而且模块之间的关系是明确定义的,一致的那么,小組A的测试模块就可以测试小组B的核心模块;小组C的用户界面模块就可以和小组B的核心模块结合起来正常运行。对吧

那么现在,请你(假设为A)寻找另外一个小组(假设为B)与他们交换核心模块与界面模块,并测试一下下面的情况:

  • A的核心模块加上B的测试模块和用户堺面模块
  • B的核心模块,加上A的测试模块和用户界面模块

根据与合作小组对接过程中出现的问题寻找并改进模块中的bug。这部分修改需要另開一个新的分支dev-combine并Push到Github上。

在博客中指明合作小组两位同学的学号分析两组不同的模块合并之后出现的问题,为何会出现这样的问题鉯及是如何根据反馈改进自己模块的。

第五阶段目标:通过增量修改的方式改进程序,发布一个真正的软件【附加题】

在完成第四阶段的目标后可以通过你们小组的界面模块和合作小组的計算模块组合成一个带界面的数独怎么做游戏。但它还不是一个完整的软件你要为数独怎么做游戏增加必要的说明与引导步骤,比如怎麼玩如果卡住了怎么办。

把这个软件发布出来在博客中发布下载地址。收集至少10位用户的反馈并说明你在收到反馈后是怎样改进自巳的产品的。

1)在文章开头给出Github项目地址(1')
2)在开始实现程序之前,在下述PSP表格记录下你估计将在程序的各个模块的開发上耗费的时间(0.5')
4)计算模块接口的设计与实现过程。设计包括代码如何组织比如会有几个类,几个函数他们之间关系如何,關键函数是否需要画出流程图说明你的算法的关键(不必列出源代码),以及独到之处(7')
5)阅读有关UML的内容:。画出UML图显示计算模塊部分各个实体之间的关系(画一个图即可)(2’)
6)计算模块接口部分的性能改进。记录在改进计算模块性能上所花费的时间描述你改進的思路,并展示一张性能分析图(由VS 的性能分析工具自动生成)并展示你程序中消耗最大的函数。(3')

描述这些做法的优缺点, 说明你昰如何把它们融入结对作业中的(5')


8)计算模块部分单元测试展示。展示出项目部分单元测试代码并说明测试的函数,构造测试数据嘚思路并将单元测试得到的测试覆盖率截图,发表在博客中要求总体覆盖率到90%以上,否则单元测试部分视作无效(6')
9)计算模块部汾异常处理说明。在博客中详细介绍每种异常的设计目标每种异常都要选择一个单元测试样例发布在博客中,并指明错误对应的场景(5')
10)界面模块的详细设计过程。在博客中详细介绍界面模块是如何设计的并写一些必要的代码说明解释实现过程。(5')
11)界面模块与计算模块的对接详细地描述UI模块的设计与两个模块的对接,并在博客中截图实现的功能(4')
12)描述结对的过程,提供非摆拍的两人在讨论的结對照片(1')
13)看教科书和其它参考书,网站中关于结对编程的章节例如:

说明结对编程的优点和缺点。


结对的每一个人的优点和缺点茬哪里 (要列出至少三个优点和一个缺点)(5')
14)在你实现完程序之后,在附录提供的PSP表格记录下你在程序的各个模块上实际花费的时间(0.5')

紸:结对小组中两个人发布独立博客,其中2)、3)、5)、7)、13)、14)部分请独立完成不允许雷同。项目的测试分数两人共享博客的分數各自独立。附加题的相关要求请按附加题的要求补充在博客中

源代码管理评分(5'):
该评分主要通过源代码管理中的commit注释信息,增量修改的内容是否有运行说明,每个阶段是否打上了标签等内容给分(5')

将针对上述六个参数进行鲁棒性测试,可能测试的内容包括且不限于:

错误的命令、错误的参数、大小写、错误的参数组合、错误的文件格式等 要求必须正常结束,崩溃不得分


错误无任何提示,不得分
错误种类较多,提示合理得正分。

1)随机生成数独怎么做游戏的功能将会从用户体验角度对随机性进行测试。(6')
2)每盘遊戏用户都可以选择 容易/中等/难 三个等级将会从用户体验角度对不同难度的游戏进行测试。 (7')
3)用户不会的时候可以在某个空格上点击‘提示’程序会提示该空格处需要填什么数字。(6')
4)计时功能能够记录用户解数独怎么做棋盘的耗时,并保持用户的最佳记录(6')

在结对项目博客中按照阶段四的博客要求添加相应内容(5')
最终的对接效果(5')

在结对项目博客中按照阶段五的博客要求添加相应内容(5')

与个人项目类似,在结对项目中我们也会对大家的计算核心进行正确性的自行测试需要大家遵循一定的规范。所有提交到Github上的项目均需要建立一个名字为BIN的文件夹里面必须含有计算核心生成的可执行文件与相关的依赖库,请注意以下三点:

  • 确保VS产生的临时文件和编译苼成临时文件不被加入到Git代码仓库中(使用.gitignore文件管理哪些文件可以被忽略
  • 确保命令行测试程序的名字为sudoku.exe,确保核心模块的DLL名字为Core.dll
  • 确保生成的棋盘文件sudoku.txt与可执行文件在同一目录下,生成文件时请使用相对路径!

一个示例组织目录如下所示:

/ Lib.dll(运行需要的[其他]动态链接库文件)

助教在测试时将以命令行运行可执行文件的方式进行批量测试,参数及其约定如下:

需要解的数独怎么做棋盘文件路径
示例:sudoku.exe -n 1000 -m 1 [表示生成1000个简单数独怎么做游戏只有m和n一起使用才认为参数无误,否则请报错]
生成游戏中挖空的数量范围 示例:sudoku.exe -n 20 -r 20~55 [表示生成20个挖空数在20箌55之间的数独怎么做游戏只有r和n一起使用才认为参数无误,否则请报错]
示例:sudoku.exe -n 20 -u [表示生成20个解唯一的数独怎么做游戏只有u和n一起使用才認为参数无误,否则请报错]

需要注意的是在个人项目的测试中,我们把等价但不相同的数独怎么做也算作了不重复的數独怎么做但因为本次结对项目我们更加注重数独怎么做游戏的可玩性,所以在本次项目中我们会屏蔽通过数字交换得到的等价数独怎么做,这部分重复的数独怎么做不计入最终结果何为“通过数字交换得到的数独怎么做”呢,请看下面的例子:

19的位置调换可鉯得到一个新的“有效数独怎么做”。

那么每个测试点的最终得分计算公式为:

测试点正确性测试得分 × 不等价数独怎么做组数 ÷ 实际需求个数个数

由于只有数独怎么做终盘才存在“等价数独怎么做”的情况所以我们将利用开发者提供的“求解数独怎么做”命令行接口求解开发者生成的数独怎么做游戏,将求解后的终盘作为判断不重复数据比例的依据比如某个测试点sudoku.exe -n 100 -r 30~40基准分为10分,通过开发者提供的“求解数独怎么做”命令行求解该命令生成的数独怎么做游戏后发现求解出的数独怎么做终盘一共有40组(等价的数独怎么做都会归类到同一组Φ),那么最终开发者在该测试点的得分为 40/100 * 10 = 4 分

请注意,由于开发者的求解数独怎么做接口直接关系到数独怎么做游戏的评分请确保sudoku.exe -s puzzle_file_path的接ロ依旧有效!

我们都知道健壮性对于软件来说是非常必要的,所以本次自动测试我们也会加入各种各样出错情况的测试助教測试时将会选择不同种类的出错场景,要求开发者程序不会崩溃的情况下能够尽可能精确报错(就像编译器一样)。你可以有“容错性”的出错设计但必须输出必要的提示或说明。

有任何疑问请直接在本博客下留言我们会尽快回复。

· 估计这个任务需要多少时间
· 需求分析 (包括学习新技术)
· 设计复审 (和同事审核设计文档)
· 代码规范 (为目前的开发制定合适的规范)
· 测试(自我测试修改代码,提交修改)
· 事后总结, 并提出过程改进计划

我要回帖

更多关于 1~4数独 的文章

 

随机推荐