使用 Python 解 数独


import threading, time, sys, os, copy from multiprocessing import Process, Pool """ # 每一宫分组 a[0-2][0-2] a[0-2][3-5] a[0-2][6-8] a[3-5][0-2] a[3-5][3-5] a[3-5][6-8] a[6-8][0-2] a[6-8][3-5] a[6-8][6-8] # 每一列分组 a[0-8][0] a[0-8][1] a[0-8][2] a[0-8][3] a[0-8][4] a[0-8][5] a[0-8][6] a[0-8][7] a[0-8][08] # 每一行分组 a[0][0-9] a[1][0-9] a[2][0-9] a[3][0-9] a[4][0-9] a[5][0-9] a[6][0-9] a[7][0-9] a[8][0-9] """ """中解""" # a="""904030200 # 600000048 # 001004000 # 400003029 # 090000010 # 820600003 # 000100700 # 240000001 # 009070304""" """小解""" # a="""000200049 # 000007500 # 001000302 # 002401090 # 054309680 # 080705200 # 603000900 # 007500000 # 490008000""" # """中解""" # a="""000000010 # 003024005 # 520003000 # 016002470 # 009070600 # 072600590 # 000500027 # 200380900 # 060000000""" # """小解""" # a="""400800270 # 005200098 # 300000000 # 000092086 # 001000000 # 620040000 # 009000004 # 160005800 # 053008001""" # """小解""" a="""108730000 090000010 024160700 007000005 800501004 500000600 003095870 080000020 000012309""" """非常难解(不是好机器不要使用!!!!)""" # a="""800000000 # 003600000 # 070090200 # 050007000 # 000045700 # 000100030 # 001000068 # 008500010 # 090000400""" # ''' 解 # [8, 1, 2, 7, 5, 3, 6, 4, 9] # [9, 4, 3, 6, 8, 2, 1, 7, 5] # [6, 7, 5, 4, 9, 1, 2, 8, 3] # [1, 5, 4, 2, 3, 7, 8, 9, 6] # [3, 6, 9, 8, 4, 5, 7, 2, 1] # [2, 8, 7, 1, 6, 9, 5, 3, 4] # [5, 2, 1, 9, 7, 4, 3, 6, 8] # [4, 3, 8, 5, 2, 6, 9, 1, 7] # [7, 9, 6, 3, 1, 8, 4, 5, 2] # ''' # a = """200007000 # 003400900 # 040200005 # 030000040 # 000631000 # 080000090 # 700005010 # 001004800 # 000900003""" # 将字符串转换为数组 def str_list(a): lis = a.split("\n") lstt_a = [] for i in lis: # lstt_a.append([int(j) for j in i]) lstt_a.append(list(map(int, i))) return lstt_a # 取一行分组 def qiu_hang(yuanzhi, key): """ a[0][0-9] a[1][0-9] a[2][0-9] a[3][0-9] a[4][0-9] a[5][0-9] a[6][0-9] a[7][0-9] a[8][0-9] :param yuanzhi: 原列表 :param key: 位置参数用到 行‘h'参数 :return: 横向的列表 """ h, l = key return yuanzhi[int(h)] # 取一列分组 def qiu_lie(yuanzhi, key): """ a[0-8][0] a[0-8][1] a[0-8][2] a[0-8][3] a[0-8][4] a[0-8][5] a[0-8][6] a[0-8][7] a[0-8][08] :param yuanzhi: 原列表 :param key: 位置参数 用到列‘l’参数 :return: 纵向的列表 """ h, l = key ret_list = [] for i in range(0, 9): ret_list.append(yuanzhi[int(i)][int(l)]) return ret_list # 取宫里面的所有元素 def qiu_gong(yuanzhi, key): """ :param yuanzhi:原9宫格列表 :param key: 位置参数 :return: 1个宫格列表 """ h, l = key h = int(h) # 先判断行数 if h >= 0 and h <= 2: # 再取宫格 return list_hang(yuanzhi, l, 0, 3) elif h >= 3 and h <= 5: return list_hang(yuanzhi, l, 3, 6) elif h >= 6 and h <= 8: return list_hang(yuanzhi, l, 6, 9) # 宫方式取出所有 def list_hang(yuanzhi, l, hm, hx): """ :param yuanzhi:原列表 :param l: 列信息 :param hm: 最小行值 通过key信息hang确定(固定值) :param hx: 最大行值 通过key信息hang确定(固定值) :return: 1个宫格列表 """ ret_list = [] l = int(l) # 根据列 ’l‘信息判定列范围,从而确定 是哪一个宫 if l >= 0 and l <= 2: for i in range(hm, hx): for j in range(0, 3): ret_list.append(yuanzhi[i][j]) elif l >= 3 and l <= 5: for i in range(hm, hx): for j in range(3, 6): ret_list.append(yuanzhi[i][j]) elif l >= 6 and l <= 8: for i in range(hm, hx): for j in range(6, 9): ret_list.append(yuanzhi[i][j]) return ret_list # 检测可能存在的值 def jiance(yuanzhi, jie): # 判断结束 yuanzhi_new = copy.deepcopy(yuanzhi) # 第一次求出所有可能解 jie2 = qiu_jie(jie, yuanzhi) # 给空白位置赋值 x = chongxinfuzhi(jie2, yuanzhi_new) # x有两种返回值 # 一种是返回一个填好的列表, # 一种返回一个元祖,元祖中有(两种解的列表 和 解列表) # 判定是否为一个填好列表, if len(x) == 9: flg = if_End(x, jie2) # 这个flg 有3种返回值 # False 表示 解还没填写完。 # 正确 填写完毕的 列表 # 1 表示解 已经空了,相当于全部填写到空位里面去了但是不正确结束线程 if flg: if flg != 1: print("正确了", os.getpid()) print_shuzu(flg) return flg else: print("错误进程结束", os.getpid(), flg) return flg # 如果解还有值递归填写 # jiance(x, jie2) t = Process(target=jiance, args=(x, jie2)) t.start() else: # 拆包两解情况,开启两个进程 分别去处理两种解。 # 无限进行递归, # 把所有可能遍历一遍。 # 很像一个动图 围棋遍历那个动图,看过的应该知道。。1生2 2生4 4生8 那种 8生16 ..... """ 爆炸似增长,非常难解的那个a不是好机器不要去解。很可能电脑卡死 # # # # # # # # # # # # # # """ new1, new2, jie2 = x # 多进程实现 t1 = Process(target=jiance, args=(new1, jie2)) t2 = Process(target=jiance, args=(new2, jie2)) t1.start() t2.start() return # 递归实现 深度过大时会报错,简单解的还可以,难解的不可用 # jie3=copy.deepcopy(jie2) # jiance(new1, jie2) # jiance(new2, jie3) def if_End(new1, jie2): # print("进入判断") for i in jie2: if len(jie2[i]) != 0: return False else: fl, i = jiaoyan(new1) if fl: return new1 else: return 1 # 校验 def jiaoyan(yuanzhi_new): a = "00,13,26,31,44,57,62,75,88" lsit_a = a.split(",") for i in lsit_a: gong = qiu_gong(yuanzhi_new, i) hang = qiu_hang(yuanzhi_new, i) lie = qiu_lie(yuanzhi_new, i) # 按照特殊位 'a' 去取出行列宫所有种类的列表去判断。如果去重后长度都为9 if not (len(set(gong)) == 9) or not (len(set(hang)) == 9) or not (len(set(lie)) == 9): return False, i # and 所有位中没有0站位的。就放正确 if 0 in gong or 0 in hang or 0 in lie: return False, i else: return True, 0 # 输出数独所有 def print_shuzu(yuanzhi_new): for i in yuanzhi_new: print(i) # 重新赋值 def chongxinfuzhi(jie, yuanzhi_new): flg = True for i in jie: # 分解解中行列标记{'00': [4, 6, 7, 8, 9], '01': [4, 8, 9], '02': [4, 7, 8], '03': [7, 8, 9], '04': [5, 6, 9], '05': [5, 6, 7, 8, 9], '06': [2, 3, 7, 8], '08': [2, 3, 4, 6, 8, 9], '10': [1, 6, 7, 8, 9], '11': [8, 9], '13': [1, 7, 8, 9], '16': [7, 8], '17': [6, 8], '22': [1, 4, 7, 8], '23': [1, 7, 8, 9], '24': [1, 6, 9], '26': [7, 8], '27': [4, 6, 8], '28': [4, 6, 8, 9], '30': [3, 8], '33': [8, 9], '34': [3, 5, 9], '38': [3, 8], '40': [3, 4, 8], '41': [3, 4, 5, 8], '43': [1, 4, 8], '45': [1, 5, 8], '47': [3, 8], '48': [1, 2, 3, 8], '50': [3, 4, 8], '54': [1, 3, 4], '55': [1, 8], '58': [1, 3, 8], '60': [1, 3, 4, 8, 9], '61': [3, 4, 8, 9], '62': [1, 4, 8], '64': [1, 4, 6, 9], '65': [1, 6, 9], '66': [1, 3, 8], '71': [4, 5], '72': [1, 4, 5, 7], '75': [1, 6, 7], '77': [4, 5, 6], '78': [1, 4, 6], '80': [1, 3, 4, 7, 8, 9], '82': [1, 4, 5, 7, 8], '83': [1, 2, 4, 7, 9], '84': [1, 4, 9], '85': [1, 7, 9], '86': [1, 3, 8], '87': [3, 4, 5, 8], '88': [1, 3, 4, 8]} h, l = i # h=0,i=0 # 这里判断 例如{'00': [4],} 则说明00位置只有一个解 就是 4,则赋值给原列表 if len(jie[i]) == 1: yuanzhi_new[int(h)][int(l)] = jie[i][0] # 如果有解重新赋值到了原列表中则 否定 有多解情况 flg = False else: # 判断是否存在一个解的情况 # if flg and 0: if flg: # 如果都是多种解的情况 是解中没有 可添加的值 return duogejie(yuanzhi_new, jie) return yuanzhi_new # 固定值--填进去的值 # 如果是多个解的情况返回两种解的固定值 def duogejie(yuanzhi, jie): # 复制两份原列表 yuanzhi_new = copy.deepcopy(yuanzhi) for i in jie: h, l = i # 循环‘解’字典, if len(jie[i]) == 2: h1, h2 = jie[i] print(h1,h2) yuanzhi_new[int(h)][int(l)] = h1 yuanzhi[int(h)][int(l)] = h2 jie[i].pop() jie[i].pop() return yuanzhi_new, yuanzhi, jie else: return yuanzhi # 求所有可能的解 def qiu_jie(jie, yuanzhi): # print(jie) for i in jie: gong_lis = qiu_gong(yuanzhi, i) jie[i] = jiancefangfa(gong_lis, jie[i]) hang_lis = qiu_hang(yuanzhi, i) jie[i] = jiancefangfa(hang_lis, jie[i]) lie_lis = qiu_lie(yuanzhi, i) jie[i] = jiancefangfa(lie_lis, jie[i]) return jie # 检测是否存在 def jiancefangfa(list_a, wei): # 大于0 if len(wei) > 0 and wei[0] == 10: wei = [i for i in range(1, 10)] res = [] for i in wei: if i not in list_a: res.append(i) return res def main(): # 字符串转列表 yuanzhi = str_list(a) # 解集合 jie = kong_jie(yuanzhi) # 正确的值 print(os.getpid()) yuanzhi_new = jiance(yuanzhi, jie) # 输出正确的值 if yuanzhi_new: print_shuzu(yuanzhi_new) sys.exit() # 初始化空解 def kong_jie(yuanzhi): jie = {} i = 0 while i < len(yuanzhi): j = 0 while j < len(yuanzhi[i]): if yuanzhi[i][j] == 0: # 初始化空解,所以位用10占位 jie[str(i) + str(j)] = [10] j += 1 i += 1 return jie import cProfile if __name__ == '__main__': cProfile.run("main()")

欢迎讨论 !如果解过于复杂时可能会报错。~~~~~~~~~~~~~~~

posted @ 2018-07-17 09:19  人工-智能  阅读(1308)  评论(0编辑  收藏  举报