数独终局生成与求解python实现
Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|
计划 | 30 | 20 |
估计在这个任务需要多少时间 | 10 | 15 |
需求分析(包括学习新技术) | 60 | 120 |
生成设计文档 | 200 | 100 |
设计复审 | ||
代码规范 | 60 | 60 |
具体设计 | 120 | 200 |
具体编码 | 2000 | 2500 |
代码复审 | ||
测试 | 60 | 180 |
报告 | 60 | 100 |
测试报告 | 30 | 20 |
计算工作量 | 30 | 30 |
事后总结 | 30 | 30 |
合计 | 2690 | 3375 |
终局生成
思路
第一行9个数,除去第一个数要求固定为8外,其余的8个数有8!= 40,320种排列
而对应每种排列情况,可以把排列依次旋转0,3,6,1,4,7,2,5,8个数,生成40320个终局,而对此终局还可以,交换1~3行内可以交换两行(即这3行可以任意顺序排列),4~6行、7~9行亦是如此,同理列方向也可如此。
由此,我们可以得到8!・3!・3!=1,451,520已经大于一百万的要求
又因为第一个数要求固定,我们只需要任意改变4~6行、7~9行的排列顺序即可
相关部分代码如下:
# 对第一行不同的排列,生成不同的局面 def create_grid(self, row): grid = [] for slice_x in self.order: grid.append(row[-slice_x:]+row[:-slice_x]) return grid # 生成第一行的全排列 def permutation(self, a_row): if not a_row: self.perm.append(list(self.tmp_row)) return for i in a_row: self.tmp_row[self.cur] = i self.cur += 1 tmp_ls = list(a_row) tmp_ls.remove(i) self.permutation(tmp_ls) self.cur -= 1
函数的调用关系图如下:
解数独
算法的基本思路
采用回溯法,逐行逐列的进行回溯直到全部求解出来或者判断无解
函数的调用关系如下:
相关部分代码如下
def solve(self, row_n, col_n): # 如果当前列超出总列数则进入下一行第一列 if col_n == 9: row_n += 1 col_n = 0 # 直到找到一个空格 while True: # 若遍历完仍没有空,说明已完成填空,返回 if row_n > 8: return True if self.mark[row_n][col_n]: break col_n += 1 if col_n == 9: row_n += 1 col_n = 0 while True: self.a_plz[row_n][col_n] = self.find_next(row_n, col_n, self.a_plz[row_n][col_n] + 1) if self.a_plz[row_n][col_n] == 0: break self.rule(row_n, col_n, False) tmp_flag = self.solve(row_n, col_n+1) if tmp_flag: return True self.rule(row_n, col_n, True) return False
性能分析与改进
按照上述思路,把代码实现后发现性能远不如想象中的好
用性能分析工具进行分析,结果如下:
生成终局的性能分析
从上面分析可以看出有很大一部分时间花费在了文件读写上,于是,就想到通过一块一块的读写来代替现在的逐字符读写,改进之后,果然性能好了很多
解数独的性能分析
消耗最大的是求解数独的主要函数
后来发现,同学用C写的和我用的同样的算法,各方面性能都远远的超过我的。
于是想到用cython进行优化,把频繁调用的函数用cython改写
单元测试
由于用cython优化后,文件内大多函数对外不可见,无法进行单元测试。
故本单元测试是在cython优化之前进行的,即先通过单元测试确保了程序的正确性之后,再用cython进行优化
针对每个单元设计多个测试用例(总用例数大于10个),确保能覆盖大部分情况
对输入进行测试给出参数个数过多,过少,格式错误的用例
对类初构造函数测试构造多个不同的类的实例,检测是否被正确初始化
对生成终局函数进行测试测试输出到文件中的结果是否符合数独规则,
以及检查生成的终局是否有重复
对比数独题目文件和解文件中的结果是否相符并且正确
测试当文件中题目无效时,输出是否和预期相符
对函数的各分支分别进行测试
对比输出结果是否与预期相符
下面是测试代码覆盖率
其中test.py是测试代码,因为其中一些语句只有在测试未通过时才会执行,所以当全部通过时这部分测试代码未被覆盖到
界面
点击Next按钮生成下了题目,点击OK按钮检查当前的填的解的正确性,分别会有相应的弹窗提醒
相关部分代码如下
def gui(self): root = tk.Tk() # 设置窗口宽度与高度不可变 root.resizable(False, False) root.title("Sudoku") # 从文件中读取并解码生成临时图标,用完后立马删除 tmp = open("tmp.ico", "wb+") tmp.write(base64.b64decode(ICO_IMG)) tmp.close() #im = Image.open("tmp.ico") #img = ImageTk.PhotoImage(im) #root.tk.call('wm', 'iconphoto', root._w, img) root.iconbitmap('tmp.ico') os.remove("tmp.ico") tmp = open("tmp.jpg", "wb+") tmp.write(base64.b64decode(JPG_IMG)) tmp.close() tmp_image = Image.open("tmp.jpg") photo = ImageTk.PhotoImage(tmp_image) label = tk.Label(root, image=photo) os.remove("tmp.jpg") # for i in range(11): # root.rowconfigure(i,weight=1) # root.columnconfigure(i,weight=1) # root.rowconfigure(11,weight=1) # 生成空格 for i in range(11): for j in range(11): if i != 3 and i != 7 and j != 3 and j != 7: self.value[i][j] = tk.StringVar() self.ety[i][j] = tk.Entry(root, textvariable=self.value[i][j], width=2, font=90) self.ety[i][j].grid(row=i, column=j, padx=12, pady=12, sticky='NSEW') # 生成第一个题目并显示 self.bind() label.grid(row=0, column=0, rowspan=12, columnspan=11, sticky='NSEW') # 确定按钮 submit_btn = tk.Button(root, text='OK', command=lambda:self.check()) submit_btn.grid(row=11, column=9, pady=10, ipadx=30, columnspan=2) # next按钮 next_btn = tk.Button(root, text='Next>', command=lambda:self.bind()) next_btn.grid(row=11, column=0, pady=10, ipadx=20, columnspan=2) root.mainloop()阅读更多
- 数独终局游戏(数独终局生成,数独问题求解,数独题目生成)
- Python3实现生成随机密码的方法
- python实现二维码的生成
- 个人项目作业-数独生成与求解
- Python3 FreeType库介绍、Python3使用FreeType库生成不定长验证码的实现
- python实现求解列表中元素的排列和组合问题
- 用三种方法实现最大子列和的求解(Python实现)
- python实现自动生成oracle awr报告
- 用Python实现QR二维码的生成
- python——web后台开发实现网址生成二维码
- [置顶] 《统计学习方法》 决策树 CART生成算法 分类树 Python实现
- python调用HTMLTestRunner+unittest实现一次执行多个测试类,并生成与每个测试类对应的测试报告,并不像某些人写的每次只执行一个测试类,具体看代码,附上整个project代码
- NLP----神经网络语言模型(NNLM),词向量生成,词嵌入,python实现
- 使用python实现生成用户信息
- Python实现文章自动生成
- python实现的生成随机迷宫算法核心代码分享(含游戏完整代码)
- Python实现生成简单的Makefile文件代码示例
- python实现求解最长公共子序列LCS问题
- 用深搜加回溯来实现求解数独的所有解
- python实现对文件中图片生成带标签的txt文件