数独(sudoku)是一种填数字的游戏,在一个9*9的九宫格里面推导出剩余的数字,要求每行、每列、每宫(3*3)的数字均包含1~9,且不重复!
另:世界最难数独(题目中的最后一个数独)被江苏扬州一位农民大叔给做出来了,厉害!
从数独的概念我们可以知道,在每次填数字的时候都需要观察行、列、每个宫格的数字不能重复。如果满足这三个条件,那这个数字暂时是正确的,我们接着就填第二个数字,如果出现1-9数字都填完还不正确的话,就只能将上一次的填写删掉,重新来过,这个回溯的过程很像数据库里的事务处理,当失败的时候,就进行回滚(RollBack)

所以从这个回溯的步骤次数来看,扬州那位大叔真的很有耐心,太牛了

class SudoKu():def __init__(self,sudo_ku_data):if not isinstance(sudo_ku_data,list):raise TypeError('sudo_ku_data参数必须是列表,目前输入{}的类型是{}'.format(sudo_ku_data,type(sudo_ku_data)))if len(sudo_ku_data) != 9 or len(sudo_ku_data[0]) != 9:raise TypeError('sudo_ku_data参数必须是9*9的列表,目前输入是{}*{}的列表'.format(len(sudo_ku_data),len(sudo_ku_data[0])))self.sudo_ku = sudo_ku_data# 存放每一行已有的数据【字典】self.every_row_data = {}# 每一列已有的数字self.every_column_data = {}# 每一个3*3有的数字self.every_three_to_three_data = {}# 每一个空缺的位置self.vacant_position = []# 每一个空缺位置尝试了的数字self.every_vacant_position_tried_values = {}# 初始化数据self._init()def _add_row_data(self,row,value):'''每行已有数据初始化到self.every_row_data字典中'''if row not in self.every_row_data:self.every_row_data[row] = set()#如果行索引不存在,就创建一个空集。类似{0: set()} {0: {8, 4}, 1: set()}if value in self.every_row_data[row]:raise TypeError('行存在重复数字!')self.every_row_data[row].add(value)def _add_column_data(self,column,value):'''每列已有数据初始化到self.every_column_data字典中'''if column not in self.every_column_data:self.every_column_data[column] = set()if value in self.every_column_data[column]:raise TypeError('列存在重复数字!')self.every_column_data[column].add(value)def _get_three_to_three_key(self,row,column):'''1~9标识九宫格的每个宫格(3*3)'''if row in [0,1,2]:if column in [0,1,2]:key = 1elif column in [3,4,5]:key = 2else:key = 3elif row in [3,4,5]:if column in [0,1,2]:key = 4elif column in [3,4,5]:key = 5else:key = 6else:if column in [0,1,2]:key = 7elif column in [3,4,5]:key = 8else:key = 9return keydef _add_three_to_three_data(self,row,column,value):'''初始化九宫格的每宫格(3*3)'''key = self._get_three_to_three_key(row,column)if key not in self.every_three_to_three_data:self.every_three_to_three_data[key] = set()self.every_three_to_three_data[key].add(value)def _init(self):for row,row_datas in enumerate(self.sudo_ku):for column,value in enumerate(row_datas):if value == '':self.vacant_position.append((row,column))else:self._add_row_data(row,value)self._add_column_data(column,value)self._add_three_to_three_data(row,column,value)def _judge_value_is_legal(self,row,column,value):'''判断行、列、宫的数据是否合法'''# value是否存在这一行数据中if value in self.every_row_data[row]:return False# value是否存在这一列数据中if value in self.every_column_data[column]:return False# value是否存在这个3*3的宫内key = self._get_three_to_three_key(row,column)#先计算单元格所在的宫格if value in self.every_three_to_three_data[key]:return Falsereturn Truedef _calculate(self, vacant_position):'''计算,开始对数独进行放置值'''# 得到当前位置row,column = vacant_positionvalues = set(range(1,10))#{1, 2, 3, 4, 5, 6, 7, 8, 9}# 对当前位置创建一个唯一key,用来存放当前位置已经尝试了的数据key = str(row) + str(column)# 如果这个key存在,就对values进行取差集,因为两个都是集合(set),直接使用-就行了if key in self.every_vacant_position_tried_values:values = values - self.every_vacant_position_tried_values[key]# 如果这个key不存在,就创建一个空的集合else:self.every_vacant_position_tried_values[key] = set()for value in values:# 对当前数据添加到当前位置尝试过的的数据中self.every_vacant_position_tried_values[key].add(value)# 如果当前value合法,可以放置if self._judge_value_is_legal(row,column,value):# 更新判断数据合法时需要使用到的数据self.every_column_data[column].add(value)self.every_row_data[row].add(value)key = self._get_three_to_three_key(row,column)self.every_three_to_three_data[key].add(value)# 修改这个位置的值为valueself.sudo_ku[row][column] = value# 返回True 和填充的valuereturn True,valuereturn False,Nonedef _backtrack(self,current_vacant_position,previous_vacant_position,previous_value):'''回溯:param current_vacant_position: 当前尝试失败的位置:param previous_vacant_position: 上一次成功的位置:param previous_value:上一次成功的值:return:'''#删除上一次成功的位置的值row,column = previous_vacant_positionself.every_column_data[column].remove(previous_value)self.every_row_data[row].remove(previous_value)key = self._get_three_to_three_key(row,column)self.every_three_to_three_data[key].remove(previous_value)#将上一次成功的位置置空self.sudo_ku[row][column] = ''#删除当前尝试失败的位置current_row,current_column = current_vacant_positionkey = str(current_row) + str(current_column)self.every_vacant_position_tried_values.pop(key)def get_result(self):'''得到计算之后的数独'''# 空缺位置的长度(个数)length = len(self.vacant_position)# 空缺位置的下标index = 0# 存放已经尝试了的数据tried_values = []# 如果index小于length,说明还没有计算完while index < length:# 得到一个空缺位置vacant_position = self.vacant_position[index]# 计入计算函数,返回是否成功,如果成功,value为成功的值,如果失败,value为Noneis_success,value = self._calculate(vacant_position)# 如果成功,将value放在tried_values列表里面,因为列表是有序的.# index+1 对下一个位置进行尝试if is_success:tried_values.append(value)index += 1# 失败,进行回溯,并且index-1,返回上一次的空缺位置,我们需要传入当前失败的位置 和 上一次成功的位置和值else:self._backtrack(vacant_position,self.vacant_position[index-1],tried_values.pop())index -= 1# 如果index<0 了 说明这个数独是无效的if index < 0:raise ValueError('无效数独')# 打印计算之后的数独self.show_sudo_ku()return self.sudo_kudef show_sudo_ku(self):for row in self.sudo_ku:print(row)##################################################
# 用来判断最后计算的数独是否合法,和计算没有关系 #
##################################################def judge_value_is_legal(row,column,value,sudo_ku):# columnfor i in range(0,9):if row == i:continueif value == sudo_ku[i][column]:return False# rowfor i in range(0,9):if column == i:continueif value == sudo_ku[row][i]:return False# three_to_threefor i in range(row//3*3,row//3*3+3):for j in range(column//3*3,column//3*3+3):if i == row and j == column:continueif value == sudo_ku[i][j]:return Falsereturn Truedef judge_sudo_ku_is_legal(sudo_ku):for row,row_values in enumerate(sudo_ku):for column,value in enumerate(row_values):if not judge_value_is_legal(row,column,value,sudo_ku):return Falsereturn Trueif __name__ == '__main__':sudo_ku_data = [[5,3,'','',7,'','','',''],[6,'','',1,9,5,'','',''],['',9,8,'','','','',6,''],[8,'','','',6,'','','',3],[4,'','',8,'',3,'','',1],[7,'','','',2,'','','',6],['',6,'','','','',2,8,''],['','','',4,1,9,'','',5],['','','','',8,'','',7,9],]sudo_ku_data2 = [[3, '', '', '', '', 1, '', '', ''],['', '', 8, 6, '', '', '', 7, ''],['', 4, '', '', '', '', '', 2, ''],[4, '', '', 2, '', '', 7, 5, 1],[9, '', 1, '', 8, '', 2, '', 6],['', '', 7, 5, '', '', '', 3, 9],['', 7, 9, '', '', 3, '', 1, 2],[6, 3, 2, '', 4, 5, 9, 8, 7],[8, 1, 4, '', '', 9, 5, 6, 3],]sudo_ku_data3 = [[8,'','', '', '', '', '', '', 4],['', 2, '', '', '', '', '', 7, ''],['', '', 9, 1, '', 6, 5, '', ''],['', '', 6, 2, '', 8, 9, '', ''],['', 9, '', '', 3, '', '', 4, ''],['', '', 2, 4, '', 7, 8, '', ''],['', '', 7, 9, '', 5, 6, '', ''],['', 8, '', '', '', '', '', 2, ''],[6, '', '', '', '', '', '', '', 9],]sudo_ku_data4 = [[8,'','', '', '', '', '', '', ''],['', '', 3, 6, '', '', '', '', ''],['', 7, '', '', 9, '', 2, '', ''],['', 5, '', '', '', 7, '', '', ''],['', '', '', '', 4, 5, 7, '', ''],['', '', '', 1, '', '', '', 3, ''],['', '', 1, '', '', '', '', 6, 8],['', '', 8, 5, '', '', '', 1, ''],['', 9, '', '', '', '', 4, '', ''],]sudo_ku = SudoKu(sudo_ku_data3).get_result()print(judge_sudo_ku_is_legal(sudo_ku))#sudo_ku2 = SudoKu(sudo_ku_data4).get_result()#print(judge_sudo_ku_is_legal(sudo_ku2))

Python来处理数独游戏(含世界最难数独示例)相关推荐

  1. 数独游戏-蓝桥杯-C语言,数独游戏_java_深搜+回溯

    问题描述 你一定听说过"数独"游戏. 如[图1.png],玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行.每一列.每一个同色九宫内的数字均含1-9,不重 ...

  2. python 玩公众号游戏_Python入门太难?不如从玩塔防小游戏开始,玩通关就能学会编程...

    我一直认为,在python入门阶段学习基础理论,太枯燥.所以我们整理了很多有关python的项目案例,有详细教程还有源码,希望能帮助更多对python感兴趣的人. 这是其中一个适合入门的Python项 ...

  3. python可以数独游戏吗_Python小实验——数独游戏

    1)简化迭代模型-->填充数字 引入itertools.product()函数能够把之前需要两层以上迭代才能完成的工作用一层迭代就完成>>> print list(produc ...

  4. Windows Mobile 数独游戏及全部源码

    去年写的一个Windows Mobile 数独游戏,可以安装到手机里面在闲暇时玩数独,开发工具C#,Visual Studio 2008. 主要功能包括:1)自动生成数独游戏:2)手工录入数独游戏:3 ...

  5. 软件工程基础-个人项目-数独游戏

    软件工程基础-个人项目-数独游戏 ----------------------------------------------------------------------------------- ...

  6. 数独问题流程图_数独游戏的难度等级分析及求解算法研究

    2 数独难度等级 数独游戏发展至今, 在数独爱好者的积极探索下, 求解数独的算法众多, 有 矩形顶点删减法.关键数删减法等 [7] .解答一道数独问题是一种或多种方法相互 结合, 为了使玩家能循环渐进 ...

  7. python实现2048小游戏_python—手把手教你实现2048小游戏

    相信2048这个游戏对大家来说一定不陌生,下面这篇文章就主要给大家介绍了怎么用Python实现2048小游戏,文中通过注释与示例代码介绍的很详细,相信对大家的理解和学习具有一定的参考借鉴价值,有需要的 ...

  8. 数独游戏(Sudoku Game)

    不知道数独游戏在国内是什么时候流行起来的,原来在tompda看到有人在讨论,没有引起我的兴趣.前几天在北京图书大厦居然看到了关于数独的书,随手翻了翻,发觉这个东西在空闲时可以尝试一下. No one ...

  9. 抄的第一个项目数独游戏

    学习完,java基础,android基础   开始跟随视频做一个实战训练,第一个:数独游戏 ****************************************************** ...

最新文章

  1. mysql workbench ssh_通过MySQL Workbench进行SSH隧道
  2. SAP UI5 应用开发教程之十七 - 聚合绑定在 UI5 复合控件中的使用
  3. 如何查找Power BI本地报表服务器产品密钥
  4. B. The Cake Is a Lie
  5. 【Qt调试技巧】Profile配置使用及一些坑
  6. 非常好的C语言章节习题集带答案,非常好的C语言章节习题集带答案选编.doc
  7. Mock Server利器 - Moco
  8. CF1110F Nearest Leaf
  9. harbor搭建与使用
  10. php file_get_contents()请求某个链接
  11. 台式计算机怎么把声音输出,台式电脑音频管理器的设置教程 台式电脑音响没声音怎么弄...
  12. 趣谈充电IC的电源路径管理功能
  13. 关于邮箱显示已经回复,但是已发送邮件里面没有
  14. 特殊节日网站全体变成黑灰色
  15. xy苹果助手未受信任_【安全问题】关于苹果信任问题
  16. npm,vue简易安装教程
  17. Elastic 7.5 安装和升级指南(官方翻译)
  18. php微擎万能门店小程序_【微擎微赞模块】万能门店小程序6.8.73+小程序前端+后端...
  19. 游戏项目的技术开发成本
  20. JSP实战————留言版实现

热门文章

  1. 【网络基础】【TCP/IP】私有IP地址段
  2. django Rest Framework----认证/访问权限控制/访问频率限制 执行流程 Authentication/Permissions/Throttling 源码分析...
  3. Re-Order Buffer
  4. ajax提交时“加载中”提示的处理方法
  5. 基于webpack模块加载,ts里对系统对象prototype的扩展
  6. 【转载】用平常语言介绍神经网络
  7. JQuery操作总结
  8. checkboxlist详细用法、checkboxlist用法、checkboxlist
  9. C++中 类与类之间的关系
  10. AndroidStudio_Gradle命令行的使用_使用gradle命令编译出apk_以及依赖管理---Android原生开发工作笔记77