当前位置: 首页 > 后端技术 > Python

你知道数独吗?你知道怎么用python秒解数独吗?

时间:2023-03-26 13:40:21 Python

前几天和隔壁邻居玩游戏被抓,卡被没收了。我不能再打游戏了,但我还是想和我的邻居一起玩。如果还想打游戏,戳:老王不在的时候,找隔壁邻居打游戏。Bibi的思考终于让我想到了一个游戏,数独!什么是数独?数独是一款可以让我在老王不在的时候和隔壁邻居一起玩的游戏!数独规则1.数字1-9在每一行中只能出现一次。2.数字1-9在每一列中只能出现一次。3.数字1-9在每个3x3的房子里只能出现一次。3x3的宫位是A1-C3,A4-C6,A7-C9,D1-F3,D4-F6,D7-F9...数独题例大体思路1.我们用一个二维列表来存储数独,有no值的位置我们使用''空字符来改变占位符。(二维数组)2、获取每个3*3宫中每行每列已有的数据,然后存储。3.获取所有空位,然后遍历空位,尝试放置数据,然后进行判断,如果满足条件,继续放置下一个。以此类推,如果途中有条件不满足,则进行回溯,回到上次满足的条件,再进行一次尝试。演示环境操作系统:windows10python版本:python3.7代码编辑:pycharm2018.2具体代码1、首先我们创建一个类SudoKu。编写构造函数。classSudoKu():def__init__(self,sudo_ku_data):#判断传入的数独是否满足格式ifnotisinstance(sudo_ku_data,list):raiseTypeError(f'sudo_ku_dataparamsmustalist,but{sudo_ku_data}isa{type(sudo_ku_data)}')iflen(sudo_ku_data)!=9orlen(sudo_ku_data[0])!=9:raiseTypeError(f'sudo_ku_dataparamsmusta9*9list,but{sudo_ku_data}isa{len(sudo_ku_data)}*{len(sudo_ku_data[0])}list')self.sudo_ku=sudo_ku_data#存储每行中的现有数据self.every_row_data={}#每列中的现有数字self.every_column_data={}#每个Anumberself.every_three_to_three_data={}#每个空位self.vacant_position=[]#每个空位试过numberself.every_vacant_position_tried_values={}2.写加每行,每列,每宫法,方便供我们调用def_add_row_data(self,row,value):'''向self.every_row_data添加数据,即添加每一行已有的数据:paramrow::paramvalue::return:'''#如果当前行不存在,则使用当前行键,初始化值为set()(emptycollection)ifrownotinself.every_row_data:self.every_row_data[row]=set()#如果这个值已经出现在这一行中,说明输入的数独不是正确的ifvalueinself.every_row_data[row]:raiseTypeError(f'params{self.sudo_ku}isaninvalidSudoKu')self.every_row_data[row].add(value)def_add_column_data(self,column,value):'''添加数据到Inself.every_column_data,上面函数的思路是一样的:paramcolumn::paramvalue::return:'''ifcolumnnotinself.every_column_data:self.every_column_data[column]=set()ifvalueinself.every_column_data[column]:raiseTypeError(f'params{self.sudo_ku}isaninvalidSudoKu')self.every_column_data[column].add(value)def_get_three_to_three_key(self,row,column):'''获取哪一个位置在3*3的宫位:paramrow::paramcolumn::return:'''ifrowin[0,1,2]:ifcolumnin[0,1,2]:key=1elifcolumnin[3,4,5]:key=2else:key=3elifrowin[3,4,5]:ifcolumnin[0,1,2]:key=4elifcolumnin[3,4,5]:key=5else:key=6else:ifcolumnin[0,1,2]:key=7elifcolumnin[3,4,5]:key=8else:key=9returnkeydef_add_three_to_three_data(self,row,column,value):'''添加数据到self.every_three_to_three_data:paramrow::paramcolumn::paramvalue::return:'''#首先获取哪个3*3宫内键=self._get_three_to_three_key(row,column)#如果键不在self.every_three_to_three_data:self.every_three_to_three_data[key]=set()ifvalueinself.every_three_to_three_data[key]:raiseTypeError(f'params{self.sudo_ku}isaninvalidSudoKu')self.every_three_to_three_data[key].值)3。遍历数独并初始化每个数据def_init(self):'''根据传入的数独初始化数据:return:'''forrow,row_datasinenumerate(self.sudo_ku):forcolumn,valueinenumerate(row_datas):ifvalue=='':#添加空位self.vacant_position.append((row,column))else:#添加行数据self._add_row_data(row,value)#添加列数据self...''判断方放置的数据是否合法:paramrow::paramcolumn::paramvalue::return:'''#value是否存在于这一行数据中ifvalueinself.every_row_data[row]:returnFalse#该列是否存在该值Ifvalueinself.every_column_data[column]:returnFalse#该3*3宫内是否存在该值key=self._get_three_to_three_key(row,column)ifvalueinself.every_three_to_three_data[key]:returnFalsereturnTrue5、写一个计算函数,循环当前位置可以使用的数据量,并阻止我的这个值是否可以放置def_calculate(self,vacant_position):'''计算,开始放置数独值:paramvacant_position::return:'''#获取当前位置row,column=vacant_positionvalues=set(range(1,10))#为当前创建唯一键position,用来存放当前位置已经尝试过的数据key=str(row)+str(column)#如果这个key存在,就取值的差值,因为都是集合(sets),就用-ifkeyinself.every_vacant_position_tried_values:values=values-self.every_vacant_position_tried_values[key]#如果这个key不存在,创建一个空集合else:self.every_vacant_position_tried_values[key]=set()forvalueinvalues:#是将当前数据添加到当前位置的已试数据self.every_vacant_position_tried_values[key].add(value)#如果当前值合法,则可以放置ifself._judge_value_is_legal(row,column,value):print(f'set{vacant_position}valueis{value}')#更新判断da时需要用到的数据ta是合法的_three_data[key].add(value)#修改这个位置的值为valueself.sudo_ku[row][column]=value#returnTrue和填充值returnTrue,value返回False,None6,如果没有当前位置可以放值,然后回溯,回到上次成功的位置,重新取值,所以我们写一个回溯函数def_backtrack(self,current_vacant_position,previous_vacant_position,previous_value):'''backtrack:paramcurrent_vacant_position:当前尝试失败的位置:paramprevious_vacant_position:最后一个成功的位置:paramprevious_value:最后一个成功的值:return:'''print(f"runbacktracking...valueis{previous_value},空位为{previous_vacant_position}")row,column=previous_vacant_position#对于最后一个成功的值,移除self.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]=''#删除当前尝试失败的位置和城市失败的值,因为回溯,所以undefineddefget_result(self):'''得到计算出的数独:return:'''#首先初始化数据self._init()#空位的长度length=len(self.vacant_position)#空位的下标positionindex=0#存储已经试过的数据tried_values=[]#index小于length表示计算还没有完成whileindex