前几天和隔壁邻居玩斗地主被发现了,牌被没收了,斗地主是斗不了了,但我还想和邻居玩耍。如果你还想斗斗地主,戳:趁老王不在,和隔壁邻居斗斗地主,比比大小
想破脑袋终于让我想到一个游戏,数独!什么叫数独?数独就是可以让我趁老王不在的时候和隔壁邻居一起玩耍的游戏!
数独的规则1、数字 1-9 在每一行只能出现一次。
2、数字 1-9 在每一列只能出现一次。
3、数字 1-9 在每一个 3x3 宫内只能出现一次。3x3 的宫内为A1-C3,A4-C6,A7-C9,D1-F3,D4-F6,D7-F9...
数独题目示例 大致思路1、数独我们使用一个二维列表存储,没有值的位置我们使用''空字符窜占位。(二维数组)
2、得到每一个3*3的宫内,每一行,每一列已有的数据,然后存放起来。3、得到所有的空缺位置,再遍历空缺位置,尝试放置数据,然后进行判断,如果满足条件安继续放置下一个。以此类推,在途中有不满足条件的情况,就进行回溯,返回上一次满足条件的情况,在进行另一次尝试。
演示环境操作系统:windows10
代码编辑器:pycharm 2018.2
具体代码1、首选我们创建一个类SudoKu。编写构造函数。
class SudoKu(): def __init__(self,sudo_ku_data): # 判断传入的数独是否满足格式 if not isinstance(sudo_ku_data,list): raise TypeError(f'sudo_ku_data params must a list, but {sudo_ku_data} is a {type(sudo_ku_data)}') if len(sudo_ku_data) != 9 or len(sudo_ku_data[0]) != 9: raise TypeError(f'sudo_ku_data params must a 9*9 list, but {sudo_ku_data} is a {len(sudo_ku_data)}*{len(sudo_ku_data[0])} list') 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 = {}2、编写添加每一行,每一列,每一宫方法,方便我们后面调用
def _add_row_data(self,row,value): ''' 添加数据到self.every_row_data中,即对每一行已有的数据进行添加 :param row: :param value: :return: ''' # 如果当前行不存在,就以当前行为key,初始化值为set()(空的集合) if row not in self.every_row_data: self.every_row_data[row] = set() # 如果这个值已经出现过在这一行了,说明传入的不是一个正确的数独 if value in self.every_row_data[row]: raise TypeError(f'params {self.sudo_ku} is a invalid SudoKu') self.every_row_data[row].add(value) def _add_column_data(self,column,value): ''' 添加数据到self.every_column_data中,上面的函数思路一样 :param column: :param value: :return: ''' if column not in self.every_column_data: self.every_column_data[column] = set() if value in self.every_column_data[column]: raise TypeError(f'params {self.sudo_ku} is a invalid SudoKu') self.every_column_data[column].add(value) def _get_three_to_three_key(self,row,column): ''' 得到该位置在哪一个3*3的宫内 :param row: :param column: :return: ''' if row in [0,1,2]: if column in [0,1,2]: key = 1 elif column in [3,4,5]: key = 2 else: key = 3 elif row in [3,4,5]: if column in [0,1,2]: key = 4 elif column in [3,4,5]: key = 5 else: key = 6 else: if column in [0,1,2]: key = 7 elif column in [3,4,5]: key = 8 else: key = 9 return key def _add_three_to_three_data(self,row,column,value): ''' 添加数据到self.every_three_to_three_data中 :param row: :param column: :param value: :return: ''' # 首先得到在哪一个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() if value in self.every_three_to_three_data[key]: raise TypeError(f'params {self.sudo_ku} is a invalid SudoKu') self.every_three_to_three_data[key].add(value)3、遍历数独,对每种数据进行初始化
def _init(self): ''' 根据传入的数独,初始化数据 :return: ''' 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)