使用 Python 解 数独

余生颓废 提交于 2020-02-05 02:00:44
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()")

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!