[Python]推算数独
2012-10-15 13:29
2481 查看
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
写了一段推算数独的代码,虽然很粗糙,但能解大部分的数独。(囧,有时候会解决不出,有时候还会出错,目前还没有仔细审核。现在就将就着备份在这里吧,虽然极其地不负责任~~~)
#-*- coding:utf8 -*- import sys data_list = [ #''' #-69-1--3- #--79----- #---84---6 #---3--1-- #53--7--48 #--2--8--- #6---23--- #-----15-- #-1--8-47- #''', ''' 3-------- --------- --------- --------- --------- --------- --------- --------- --------- ''', ##very hard #''' #4-----1-- #7--1-5-4- #---34-2-- #-1-42---5 #2-3-8-4-9 #8---53-1- #--8-16--- #-7-8-4--1 #--9-----4 #''', # #''' #--9----4- #---23-6-1 #-3---6--2 #----14-76 #--6-8-4-- #45-76---- #6--8---5- #8-7-59--- #-2----8-- #''', # # #''' #-----5-7- #2--3-95-1 #15--2---9 #--8-63-52 #36-----18 #42-15-6-- #5---3--26 #8-12-6--5 #-9-5----- #''', # #''' #2-----57- #---17-2-6 #---2----8 #536--2-87 #1--7-6--3 #74-3--692 #6----4--- #4-2-18--- #-15-----4 #''', # # ##hard #''' #2--4-6-7- #--4--2--- #15-97---- #-3--6-4-- #7-1-4-9-3 #--8-9--1- #----54-29 #---7--8-- #-2-6-9--1 #''', # ##medium #''' #-67-2-3-- #--37----- #92-1-3--- #4-2-35-6- #3-------2 #-1-24-9-3 #---5-8-39 #-----92-- #--8-1-75- #''', # ###easy #''' #-61----9- #43--95-6- #9--1-2--3 #---4-1--9 #5-9---7-1 #6--2-9--- #3--9-8--6 #-8-73--42 #-9----31- #''', # #''' #--6-9---7 #84-73216- #---1---42 #49----73- #--3---2-- #-17----96 #93---4--- #-61329-78 #7---5-9-- #''', ] ## 将数据转换成三维数组的形式,以方便处理 def get_init_data(data): data = data.strip() data = data.split('\n') result = [[] for x in data] for i, x in enumerate(data): for y in x: if y=='-':result[i].append(['-']) else: result[i].append([y]) return result ## 输出数据,方便查看和调试 def print_done_data(data): sys.stdout.write('='*80) sys.stdout.write('\n') for i, x in enumerate(data): for j, y in enumerate(x): s = '%s'%(''.join(y)) # 如果没有填入数,则用-表示 if s=='': s='-' sys.stdout.write('%6s'%s) # 每三列的地方,输出分隔符 if j!=8 and j%3==2: sys.stdout.write(' |') else: sys.stdout.write(' ') sys.stdout.write('\n') # 每三行的地方,输出分隔符 if i!=8 and i%3==2: sys.stdout.write('-'*80) sys.stdout.write('\n') sys.stdout.write('='*80) sys.stdout.write('\n') return ## 初始化阵,将各种可能的数字填入 def init_for_adjust(data): for x in data: for y in x: # 对于空白的地方,填入9个数字,并用-开头做标记 if y[0]=='-': y.extend([str(n) for n in range(1,10)]) return data ## 根据给定的行列值,得到所在的小九宫格起始位置 def get_block_ends(row, col): rleft = 6 rright = 9 cleft = 6 cright = 9 if row<3: rleft = 0 rright = 3 elif row<6: rleft = 3 rright = 6 if col<3: cleft = 0 cright = 3 elif col<6: cleft = 3 cright = 6 return (rleft, rright, cleft, cright) ## 删除不可能的值 def remove_impossible(data): for i,x in enumerate(data): for j,y in enumerate(x): # 对于确定的值,那么所有的行,列,小九宫格中将不可能再出现这个值 if len(y)==1 and y[0]!='-': # remove_impossible row for z in x: if z!=y: try:z.remove(y[0]) except:pass #remove_impossible column for z in data: if z[j]!=y: try:z[j].remove(y[0]) except:pass #remove_impossible block (rleft, rright, cleft, cright)=get_block_ends(i, j) for ri in range(rleft, rright): for ci in range(cleft, cright): if data[ri][ci]!=y: try : data[ri][ci].remove(y[0]) except:pass return ## 只有一个可能值的格子,那这个格子一定是这个值 def remove_done(data): ret = True for x in data: for y in x: if len(y)==2 and y[0]=='-': y.remove('-') ret = False return ret ## 确定数独的状态,这里分为错误、未完成、ok三种状态 def sukudo_state(data): # 这里用列表来比较 DONE = [x for x in '123456789'] # test row for row in data: # 如果出现只有['-']的情况,那么是出错了 try: row.index(['-']) return 'error' except: pass t = [] for x in row: t+=x t.sort() if t!=DONE: # 长度相同,但内容不同,那一定是错误 if len(t)==len(DONE): return 'error' # 长度不同,这里认为是没有处理完 return 'not finished' # test column for ci in range(9): t=[] for row in data: t+=row[ci] t.sort() if t!=DONE: if len(t)==len(DONE): return 'error' return 'not finished' # test block for i in range(3): rleft = i*3 rright = rleft+3 for j in range(3): cleft = j*3 cright = cleft+3 t = [] for ti in range(rleft, rright): for tj in range(cleft, cright): t+=data[ti][tj] t.sort() if t!=DONE: if len(t)==len(DONE): return 'error' return 'not finished' return 'ok' ## 一行中只有一个格子出现某个值,那么这个格子就只能是这个值 def intelligent_row(data): # intelligent row for x in data: t = [] for y in x: if len(y)>1 and y[0]=='-': t.extend(y[1:]) s = set(t) for item in s: if t.count(item)==1: for i, y in enumerate(x): try: y.index(item) x[i]=[item] break except:pass ## 一列中只有一个格子出现某个值,那么这个格子就只能是这个值 def intelligent_column(data): # intelligent column for ci in range(9): t = [] for row in data: if len(row[ci])>1 and row[ci][0]=='-': t.extend(row[ci][1:]) s = set(t) for item in s: if t.count(item)==1: for i, y in enumerate(data): try: y[ci].index(item) data[i][ci]=[item] break except:pass ## 一个小九宫格中只有一个格子出现某个值,那么这个格子就只能是这个值 def intelligent_block(data): # intelligent block for i in range(3): rleft = i*3 rright = rleft+3 for j in range(3): cleft = j*3 cright = cleft+3 t = [] for ti in range(rleft, rright): for tj in range(cleft, cright): if len(data[ti][tj])>1 and data[ti][tj][0]=='-': t.extend(data[ti][tj][1:]) s = set(t) for item in s: if t.count(item)==1: for ti in range(rleft, rright): for tj in range(cleft, cright): try: data[ti][tj].index(item) data[ti][tj]=[item] break except:pass return ## 简单地推断,直到结果不再发生变化 def easy_talent(data): save_data = [] while cmp(save_data, data)!=0: remove_impossible(data) save_data = copy.deepcopy(data) intelligent_row(data) remove_done(data) remove_impossible(data) # sys.stdout.write('\n\nafter intelligent row\n') # print_done_data(data) intelligent_column(data) remove_done(data) remove_impossible(data) # sys.stdout.write('\n\nafter intelligent column\n') # print_done_data(data) intelligent_block(data) remove_done(data) remove_impossible(data) # sys.stdout.write('\n\nafter intelligent block\n') # print_done_data(data) remove_done(data) remove_impossible(data) sys.stdout.write('\n\nafter remove done data\n') print_done_data(data) return #找到最少可能的格子,用于假设推算 def get_least_cell(data): (ri, rj) = (10,10) t = False for i in range(9): for j in range(9): if data[i][j][0]=='-': ri, rj = i, j t = True break if t: break for i in range(ri, 9): for j in range(rj, 9): if len(data[i][j])<len(data[ri][rj]) and data[i][j][0]=='-': (ri,rj)=(i,j) return (ri, rj) ## 假设推断,对格子中的各个值进行假设推断 def suppose_talent(data): state = sukudo_state(data) if state=='ok': # 完成后的数独,则输出 print '* done data:' print_done_data(data) return elif state=='error': # 数独不正确,直接返回 return # 数独没有完成时,则会来到这里进行处理 i , j = get_least_cell(data) t = [x for x in data[i][j][1:]] for x in t: # 推断前,先保存当前状态 save_data = copy.deepcopy(data) data[i][j] = [x] # 作了假设后,继续进行简单的推断 easy_talent(data) state =sukudo_state(data) # 如果完成了就输出,如果还未完成,则继续假设 if state =='ok': print '* done data:' print_done_data(data) return elif state=='not finished': suppose_talent(data) return # 推断的不正确时,会来到这里 # 恢复状态 data = save_data return import copy if __name__=='__main__': for data in data_list: data = get_init_data(data) print '*original data:' print_done_data(data) init_for_adjust(data) easy_talent(data) suppose_talent(data) pass
相关文章推荐
- 使用Python求解数独
- Leetcode做题日记:36. 有效的数独(PYTHON)
- 简单实现python数独游戏
- Python如何判断数独是否合法
- python实现自动解数独小程序
- Leetcode做题日记:37. 解数独(PYTHON)
- 使用Python编写程序求解数独游戏答案
- python和java实现数独游戏
- python2 数独图形用户界面设计
- 使用python解决数独问题
- python 实现计算数独
- 利用python抓取网页上的数独,并用回溯法破解
- 算法基础之python实现深度优先搜索的数独问题
- 用python解数独
- 数独解法的Python实现
- [leetcode] Python(5)--有效的数独(36)、旋转图像(48)
- python_lintcode_96. 链表划分_389. 判断数独是否合法
- LeetCode:有效的数独(Python版本)
- 计算机视觉 python 解图片数独题
- Python刷题笔记(1)- 数独判断