用Python生成数独

上次做出了怎么算数独,开心坏了,鼻子翘起还没两天,脑瓜里又蹦出了个新想法:创造数独。

于是乎,又捣鼓捣鼓,终于整出来了!(吼吼吼吼吼~~~)

这个算法的基本思路是这样的:

1、定义一个空的数独出来;

2、随机将1~9填入第一行;

3、随机将第一列填满;

4、随机将第九列填满;

5、用添加了随机解法的解数独算法填写出一个随机数独谜底;

6、建立一个集合l=[0~80],随机从谜底抠去数字,然后算能否得到解,并验证是否唯一,行就保留,不行就回归上一步;

7、直到集合l里的数字抠完,跳出循环。

啦啦啦,数独生成完毕,大概率将会是一个骨灰级难度哟~

原创文章转载要注明,代码如下,拿走不谢:

import random
import time
def pr(a):#用于输出方便阅读的结果
    for i in range(9):
        if i%3==0:
            print('\t---------\t\t---------\t\t---------')
        for j in range(9):
            if j%3==0:
                print('|',end='\t')
            print(a[i][j],end='\t')
        print('|',end='\n')
    print('\t---------\t\t---------\t\t---------')
def diff(d):
    print('数独难度:',end='')
    if d==0:
        print('极容易')
    if d==1:
        print('容易')
    if d==2:
        print('一般')
    if d==3:
        print('困难')
    if d==4:
        print('极困难')
def con(a):#用于将数据转化为符合格式的序列
    if len(a)==81:
        a_con=[[],[],[],[],[],[],[],[],[]]
        for i in range(9):
            b=a[i*9:i*9+9]
            for j in range(9):
                a_con[i].append(int(b[j]))
        return a_con
    return False
def examine_sudoku(sudoku):#检查是否符合数独规则
    if len(sudoku)!=9:
        return False
    for i in range(9):
        if len(sudoku[i])!=9 or sudoku[i].count([])>0:
            return False
        for j in range(1,10):
            if sudoku[i].count(j)>1:
                return False
    return True
def complete(a):#用于检测数独是否完成
    for i in range(9):
        for j in range(9):
            if type(a[i][j])!=int or a[i][j]==0:
                return False
    return True
def copy(a):#复制数独的值,用于后期假设法运算失败,找回原来的值
    d=[[], [], [], [], [], [], [], [], []]
    for i in range(9):
        for j in range(9):
            if type(a[i][j])==int:
                d[i].append(a[i][j])
            elif type(a[i][j])==list:
                d[i].append([])
                for k in a[i][j]:
                    d[i][j].append(k)
    return d
def extract_b_c(a):#用9行表示的a,得到9列表示的b,及9宫表示的c,并对每个0所在的位置用[1,2,3,4,5,6,7,8,9]代替,作为笔记
    b=[[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],
       [0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],
       [0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0]]
    c=[[],[],[],[],[],[],[],[],[]]
    for i in range(9):
        for j in range(9):
            if a[i][j]==0:
                a[i][j] = [1,2,3,4,5,6,7,8,9]
            b[j][i]=a[i][j]
            s=ij_s(i,j)
            c[s].append(a[i][j])
    return b,c
def ij_s(i,j):#用i和j求得宫所在的位置s
    s=i//3*3+j//3
    return s
def ij_t(i,j):#用i和j求得所在宫里的位置t
    t=i%3*3+j%3
    return t
def st_i(s,t):#用s和t求得原i的值
    i=s//3*3+t//3
    return i
def st_j(s, t):#用s和t求得原j的值
    j=s%3*3+t%3
    return j
def play_1(a,b,c,i,j,change):#将笔记中同行、同列及同宫的笔记里删除已知数字,并将唯一可能的格子变成已知数字
    s=ij_s(i,j)
    for num in range(1,10):
        for k in range(9):
            if type(a[i][k])==list and num in a[i] and num in a[i][k]:
                a[i][k].remove(num)
                change=True
                if len(a[i][k])==1:
                    n=a[i][k][0]
                    a[i][k]=n
                    b[k][i]=n
                    c[ij_s(i,k)][ij_t(i,k)]=n
                    change=True
            if type(b[j][k])==list and num in b[j] and num in b[j][k]:
                b[j][k].remove(num)
                change=True
                if len(b[j][k])==1:
                    n=b[j][k][0]
                    a[k][j]=n
                    b[j][k]=n
                    c[ij_s(k,j)][ij_t(k,j)]=n
                    change=True
            if type(c[s][k])==list and num in c[s] and num in c[s][k]:
                c[s][k].remove(num)
                change=True
                if len(c[s][k])==1:
                    n=c[s][k][0]
                    a[st_i(s,k)][st_j(s,k)]=n
                    b[st_j(s,k)][st_i(s,k)]=n
                    c[s][k]=n
                    change=True
    return a,b,c,change
def play_2(a,b,c,i,j,change):#唯一候选数法
    def num_abc():
        num_a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        num_b = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        num_c = [1, 2, 3, 4, 5, 6, 7, 8, 9]
        for k in range(1,10):
            if k in a[i]:
                num_a.remove(k)
            if k in b[j]:
                num_b.remove(k)
            if k in c[s]:
                num_c.remove(k)
        return num_a,num_b,num_c
    s=ij_s(i,j)
    num_a,num_b,num_c=num_abc()
    for n in num_a:
        t=0
        for k in range(9):
            if type(a[i][k])==list and n in a[i][k]:
                t+=1
        if t==1:
            for k in range(9):
                if type(a[i][k]) == list and n in a[i][k]:
                    a[i][k] = n
                    b[k][i] = n
                    c[ij_s(i, k)][ij_t(i, k)] = n
                    num_a, num_b, num_c = num_abc()
            change=True
    for n in num_b:
        t=0
        for k in range(9):
            if type(b[j][k])==list and n in b[j][k]:
                t+=1
        if t==1:
            for k in range(9):
                if type(b[j][k])==list and n in b[j][k]:
                    a[k][j] = n
                    b[j][k] = n
                    c[ij_s(k, j)][ij_t(k, j)] = n
                    num_a, num_b, num_c = num_abc()
            change=True
    for n in num_c:
        t=0
        for k in range(9):
            if type(c[s][k])==list and n in c[s][k]:
                t+=1
        if t==1:
            for k in range(9):
                if type(c[s][k])==list and n in c[s][k]:
                    a[st_i(s,k)][st_j(s,k)]=n
                    b[st_j(s,k)][st_i(s,k)]=n
                    c[s][k]=n
            change=True
    return a,b,c,change
def play_3(a,b,c,i,j,change):#链数删减法,专业用语是这样的,有2链数、3链数的,此方法扩展到n链数(帮助排除不可能项的)
    list_a=[]
    list_b=[]
    list_c=[]
    s=ij_s(i,j)
    for k in range(9):
        if type(a[i][k]) == list:
            list_a.append(a[i][k])
    for k in range(9):
        if type(b[j][k]) == list:
            list_b.append(b[j][k])
    for k in range(9):
        if type(c[s][k]) == list:
            list_c.append(c[s][k])
    for k in range(3,len(list_a)+1):
        l=[]
        n=0
        for m in list_a:
            if len(m)1:
        k=random.randint(0,len(l)-1)
    else:
        k=0
        x=False
    p=l[k]//9
    q=l[k]%9
    del l[k]
    if co[p][q]==0:
        continue
    co[p][q]=0
    cop=copy(co)
    cop_b, cop_c = extract_b_c(cop)
    while change == True:
        change = False
        cop, cop_b, cop_c, change, examine, a_co= play_all_1(cop, cop_b, cop_c, change, examine, a_co)
    if complete(cop)==True:
        a = copy(co)
    else:
        if ti==0:
            print('一般难度已生成,正在精细推敲骨灰难度......')
            ti=1
        for i in range(9):
            for j in range(9):
                if type(cop[i][j])==list and len(cop[i][j])==2:
                    a_copy=copy(cop)
                    n=cop[i][j][0]
                    a_copy[i][j]=a_copy[i][j][1]
                    a_copy_b, a_copy_c = extract_b_c(a_copy)
                    cop[i][j]=n
                    cop_b[j][i]=n
                    cop_c[ij_s(i,j)][ij_t(i,j)]=n
                    change=True
                    while change == True:
                        change = False
                        cop, cop_b, cop_c, change, examine, a_co,d=play_all(cop, cop_b, cop_c, change, examine, a_co,d)
                    while change == True:
                        change = False
                        a_copy, a_copy_b, a_copy_c, change, examine, a_copy2,d=play_all(a_copy, a_copy_b, a_copy_c, change, examine, a_copy2,d)
                    if (complete(cop)==True and complete(a_copy)==False) or (complete(cop)==False and complete(a_copy)==True):
                        if cop==com or cop==com:
                            a = copy(co)
print('数独生成完毕,生成数独所用时间为:',time.time()-t)
pr(a)
t=time.time()
a,d=complate_sudoku(a)
print('解数独所用时间为:',time.time()-t)
diff(d)
pr(a)

 

你可能感兴趣的:(算法,python,python,算法)