1 Star 0 Fork 0

swankhli/suduku

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
sudoku v1.py 25.06 KB
一键复制 编辑 原始数据 按行查看 历史
swankhli 提交于 2023-01-03 04:59 . 第一次上传
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
# -*- coding: utf-8 -*-
"""
Created on Wed Dec 28 12:19:37 2022
@author: s'wan
数独 v1,循环算法,同时调整候选集
"""
#%% import
import numpy as np
from itertools import combinations,product,permutations
#%% define
### 从文本解析九宫格
def parse(txt):
#arr=np.array([[None]*9]*9)
arr=np.zeros((9,9),'int8')
for j,line in enumerate(txt.split('\n')):
#print(j,line)
if len(line)<9:
continue
for i in range(9):
if line[i]!=' ':
arr[j-1,i]=int(line[i])
return arr
def is_error(arr):
def __check_error(sub):
u,c = np.unique(sub,return_counts=True)
return len((np.where(c[np.where(u>0)[0]]>1)[0]))>0
for r in range(9):
if __check_error(arr[r]):
return True
#[__check_error(arr[r]) for r in range(9)]
for c in range(9):
if __check_error(arr[:,c]):
return True
#[__check_error(arr[:,c]) for c in range(9)]
for g in range(9):
rs,cs = divmod(g,3)
if __check_error(arr[rs*3:rs*3+3,cs*3:cs*3+3].reshape(-1)):
return True
return False
### 检查子集 是否合乎规则
def __check(sub):
u = np.unique(sub)
#return not (u[0]<1 or u[-1]>9 or len(u)!=9)
return u[0]==1 and u[-1]==9 and len(u)==9
'''
[__check(row) for row in arr]
[__check(arr[:,c]) for c in range(9)]
for g in range(9):
r,c = divmod(g,3)
print(__check(arr[r*3:r*3+3,c*3:c*3+3]))
'''
### 检查大九宫 是否合乎规则
def is_done(arr):
for row in arr:
if not __check(row) :
return False
for c in range(9):
if not __check(arr[:,c]) :
return False
for g in range(9):
r,c = divmod(g,3)
#print(arr[r*3:r*3+3,c*3:c*3+3])
if not __check(arr[r*3:r*3+3,c*3:c*3+3]):
return False
return True
__count=lambda sub,val: sum(sub.reshape(-1)==0)
__has=lambda sub,val: sum(sub.reshape(-1)==0) > 0
### 子集(行,列,宫) 缺的数字
def absence(sub):
u = np.unique(sub)
return list(set(range(1,10)).difference(u[u>0]))
### 计算 每格 候选集
univer = set(range(1,10))
def candidate_set(arr):
may=np.full((9,9),None)
for r in range(9):
for c in range(9):
if arr[r,c]==0:
rr,cc = int(r/3),int(c/3)
'''p1=absence(arr[r])
p2=absence(arr[:,c])
p3=absence(arr[rr*3:rr*3+3,cc*3:cc*3+3])
#print(r,c,list(set(p1).intersection(p2).intersection(p3)))
#may[r,c]=list(set(p1).intersection(p2).intersection(p3))
may[r,c]=set(p1).intersection(p2).intersection(p3)'''
may[r,c]=univer.difference(set(arr[r]).union(arr[:,c]).union(arr[rr*3:rr*3+3,cc*3:cc*3+3].reshape(-1)))
return may
'''
may=candidate_set(arr)
'''
### 对于只有一个候选数的格子,其他格子不能候选此数
def exclude_1(sub): # t--candidate 候选各数
### 统计 格子的候选数量
cell_val_counts=np.array([len(s) if isinstance(s,set) else 0 for s in sub])
# 检查 只有一个候选数的格子
check_cells = np.where(cell_val_counts==1)[0]
for cell in check_cells:
for other_cell in range(9):
if other_cell!=cell and isinstance(sub[other_cell],set): # 这个数其他格子不能候选
sub[other_cell]=sub[other_cell].difference(sub[cell])
#print(cell,other_cell,sub[other_cell],sub[other_cell].difference(sub[cell]))
return len(check_cells)
'''
摒除法,只出现一次的数字,是所在格唯一候选数
2.基础摒除法,隐性唯一候选数法
'''
def exclude_hide_1(sub):
### 统计 各数字被候选次数
val_counts=np.array([sum([v in s for s in sub if isinstance(s,set)]) for v in range(1,10)])
# 只被候选一次的数字所在的格,仅候选此数
check_vals=np.where(val_counts==1)[0] + 1 # 只出现一次的数字
val_cell={val:np.where([val in s if isinstance(s,set) else False for s in sub])[0] for val in check_vals}
for val,cell in val_cell.items():
sub[cell]=set([val])
return len(check_vals)
###三链数(2,3,4,...) 删减法:子集(行列宫)的某3个格候仅候选某3个数,则其他格不能选此3数
### n格仅候选n个数,但其他格可能也候选这n个数 #####
def exclude_n(sub,no=3):
### 候选个数 >1 且 <=no 的 格子集合
check_cells=np.array([cell for cell in range(9) if isinstance(sub[cell],set) and len(sub[cell])>1 and len(sub[cell])<=no])
count=0
### N 个格子,no个一组,全部的组合
for cell_comb in combinations(check_cells,no): # 格子的组合
val_union=set() # 格子组合候选数字并集
for cell in cell_comb:
val_union=val_union.union(sub[cell]) # 格子组合候选数字并集
if len(val_union)==no: # 并集 大小 正好是 格子数
for cell in range(9):
if cell not in cell_comb and isinstance(sub[cell],set): # 其他格子 不能 候选这几个数
#print(cell,sub[cell],val_union,sub[cell].difference(val_union))
sub[cell]=sub[cell].difference(val_union)
#pass
count+=1
return count
### 隐性三链数(2,3,4,...)删减法:某3个数仅出现在子集(行列宫)的某3个格候选集,则此3格不能选其他数
### n个数仅被n格候选,但n格可能还候选别的数 #####
def exclude_hide_n(sub,no=3):
### 统计 数字候选次数
val_counts=np.array([sum([val in s for s in sub if isinstance(s,set)]) for val in range(1,10)])
check_vals=np.where(list(map(lambda val:val>1 and val<=no,val_counts)))[0] + 1 ### 出现次数 大于1且小于等于no 的数
if len(check_vals) < no: ### 至少要no个数
return 0
# 存储 候选 每个数 的格子
val_cell={val:np.where([val in s if isinstance(s,set) else False for s in sub])[0] for val in check_vals}
### N 个数字,3个组合,全部的组合数
count=0
for val_comb in combinations(check_vals,no):
cell_union=set() # 组合各数出现位置的并集
for val in val_comb:
cell_union=cell_union.union(val_cell[val])
if len(cell_union)==no: # 出现的位置数正好是数字个数
ext = set(range(1,10)).difference(val_comb) # 格需要排除的候选数字
for cell in range(9):
if cell in cell_union and isinstance(sub[cell],set):
sub[cell]=sub[cell].difference(ext) # 此no格只候选此no数
#print(val_comb,cell_union,sub[cell],sub[cell].difference(ext))
count+=1
return count
'''
for r in range(9):
#print('exclude_1c',r, exclude_1c(may[r])) # 格只有一个候选
print('exclude_1t',r, exclude_1t(may[r])) # 数只出现一次
#print('exclude_2',r, exclude_n(may[r],2))
#print('exclude_hide_2',r, exclude_hide_n(may[r],2))
#print('exclude_3',r, exclude_n(may[r],3))
print('exclude_hide_3',r, exclude_hide_n(may[r],3))
for c in range(9):
#print('exclude_1c',c, exclude_1c(may[:,c])) # 格只有一个候选
#print('exclude_1t',c, exclude_1t(may[:,c])) # 数只出现一次
#print('exclude_2',c, exclude_n(may[:,c],2))
print('exclude_hide_2',c, exclude_hide_n(may[:,c],2))
#print('exclude_3',c, exclude_n(may[:,c],3))
print('exclude_hide_3',c, exclude_hide_n(may[:,c],3))
for g in range(9):
rs,cs = divmod(g,3)
sub=may[rs*3:rs*3+3,cs*3:cs*3+3].reshape(-1)
#print('exclude_1c',g, exclude_1c(sub)) # 格只有一个候选
#print('exclude_1t',g, exclude_1t(sub)) # 数只出现一次
#print('exclude_2',g, exclude_n(sub,2))
#print('exclude_hide_2',g, exclude_hide_n(sub,2))
print('exclude_3',g, exclude_n(sub,3))
print('exclude_hide_3',g, exclude_hide_n(sub,3))
'''
### 3.区块摒除法
### 若某行(列)块确定候选某数,则同行(列)其他行(列)块 不能 候选此数
### 擦g之外其他宫的候选
def erase_row_candidate(may,row,gong,val):
#print('erase_row_candidate',row,gong,val)
for g in set(range(3)).difference([gong]):
for col in range(g*3,g*3+3): #所有同行格
if isinstance(may[row,col],set):
may[row,col]=may[row,col].difference([val]) # val不再候选
def erase_col_candidate(may,col,gong,val):
#print('erase_col_candidate',col,gong,val)
for g in set(range(3)).difference([gong]):
for row in range(g*3,g*3+3): #所有同列格
if isinstance(may[row,col],set):
may[row,col]=may[row,col].difference([val]) # val不再候选
def exclude_block(arr,may):
count=0
for s in range(0,9,3):
# 统计3行的所有已填数
vals= np.unique(list(filter(lambda v:v>0,arr[s:s+3].reshape(-1))))
# 遍历每个数
for val in vals:
# 1 确定所在块的 宫位置
pos=np.where(arr[s:s+3]==val) # pos[0] 所在行,pos[1]所在列
on_gongs = np.int8(np.floor(pos[1]/3)) # 所在宫
# 要检查的 行 和 宫
rows = list(set(list(range(s,s+3))).difference(pos[0]+s))
gongs = list(set(list(range(3))).difference(on_gongs))
if len(gongs)==1: # 只需处理1宫
erase_row_candidate(may,rows[0],gongs[0],val)
count+=1
elif len(gongs)==2: # 2宫,看有没有某宫可定:只有宫的某块填!!!!
status = [(r,g,np.all(list(map(lambda v:v is None,may[r,g*3:g*3+3])))) for r,g in product(rows,gongs)]
filled = np.where(list(map(lambda t: t[2],status)))[0] ### 已填的块
for i in filled:
other_same_gong = np.where(list(map(lambda t: t[1]==status[i][1] and t[0]!=status[i][0],status)))[0][0]
erase_row_candidate(may,status[other_same_gong][0],status[other_same_gong][1],val)
count+=1
other_same_line = np.where(list(map(lambda t: t[1]!=status[i][1] and t[0]==status[i][0],status)))[0][0]
erase_row_candidate(may,status[other_same_line][0],status[other_same_line][1],val)
count+=1
for s in range(0,9,3):
# 统计3列的所有已填数
vals= np.unique(list(filter(lambda v:v>0,arr[:,s:s+3].reshape(-1))))
# 遍历每个数
for val in vals:
# 1 确定所在块的 宫位置
pos=np.where(arr[:,s:s+3]==val) # pos[0] 所在行,pos[1]所在列
on_gongs = np.int8(np.floor(pos[0]/3)) # 所在宫
# 要检查的 列 和 宫
cols = list(set(list(range(s,s+3))).difference(pos[1]+s))
gongs = list(set(list(range(3))).difference(on_gongs))
if len(gongs)==1: # 只需处理1宫
erase_col_candidate(may,cols[0],gongs[0],val)
count+=1
elif len(gongs)==2: # 2宫,看有没有某宫可定:只有宫的某块填!!!!
status = [(c,g,np.all(list(map(lambda v:v is None,may[g*3:g*3+3,c])))) for c,g in product(cols,gongs)]
filled = np.where(list(map(lambda t: t[2],status)))[0] ### 已填的块
for i in filled:
other_same_gong = np.where(list(map(lambda t: t[1]==status[i][1] and t[0]!=status[i][0],status)))[0][0]
erase_col_candidate(may,status[other_same_gong][0],status[other_same_gong][1],val)
count+=1
other_same_line = np.where(list(map(lambda t: t[1]!=status[i][1] and t[0]==status[i][0],status)))[0][0]
erase_col_candidate(may,status[other_same_line][0],status[other_same_line][1],val)
count+=1
return count
'''
块排斥法:某数只被宫内某行(列)候选,则该行其他宫不能候选此数
'''
def union_set(sub):
un=set()
for s in sub:
if isinstance(s,set):
un=un.union(s)
return un
def repel_block(arr,may):
for rg in range(3):
for cg in range(3):
row_cand=[union_set(may[row,cg*3:cg*3+3]) for row in range(rg*3,rg*3+3)]
diff_union = {i+rg*3:row_cand[i].difference(row_cand[j].union(row_cand[k])) for i,j,k in permutations(range(3))}
for row,s in diff_union.items():
'''if len(s)>0:###
print('repel_row',rg,cg,row,s)'''
if len(s)==1:
#print('repel_row',rg,cg,row,s)
erase_row_candidate(may,row,cg,list(s)[0])
col_cand=[union_set(may[rg*3:rg*3+3,col]) for col in range(cg*3,cg*3+3)]
diff_union = {i+cg*3:col_cand[i].difference(col_cand[j].union(col_cand[k])) for i,j,k in permutations(range(3))}
for col,s in diff_union.items():
'''if len(s)>0:###
print('repel_col',rg,cg,col,s)'''
if len(s)==1:
#print('repel_col',rg,cg,col,s)
erase_col_candidate(may,col,rg,list(s)[0])
### 5.矩形摒除法(矩形顶点删减法)
### 某两列(行)仅在相同行(列)可取某数,则这两行(列)其他格不能取此数
### 三链列(行)删减法 --矩形删减法扩展
def intersection(k_kv,ks):
its=set(range(9))
for k in ks:
its = its.intersection(k_kv[k].keys())
return its
def set_equal(k_kv,rows,val):
for row in rows[1:]:
if k_kv[rows[0]][val] != k_kv[row][val]:
return False
return True
def exclude_rectangle(arr,may,no=2):
count=0
## 计算各行 被选2次的数字所在位置
rows_v2ps=[]
for row in range(9):
v2ps={val:{col for col in range(9) if isinstance(may[row,col],set) and val in may[row,col]} \
for val in range(1,10) if val not in arr[row]}
rows_v2ps.append({v:ps for v,ps in v2ps.items() if len(ps)==no})
rows_v2ps={row:v2ps for row,v2ps in enumerate(rows_v2ps) if len(v2ps)>0}
## 寻找 数字 与 位置 都相同的 行对
'''for r1,r2 in combinations(rows_v2ps, 2):
jiaoji = set(rows_v2ps[r1].keys()).intersection(rows_v2ps[r2].keys())
for val in jiaoji:
if rows_v2ps[r1][val] == rows_v2ps[r2][val]:
print('row',{r1,r2},val,rows_v2ps[r1][val])
### 从两列的其他候选 删除 该值
for col in rows_v2ps[r1][val]:
for row in range(9):
if row not in (r1,r2) and isinstance(may[row,col],set):
may[row,col]=may[row,col].difference([val])'''
for rows in combinations(rows_v2ps, no):
jiaoji = intersection(rows_v2ps,rows)
for val in jiaoji:
if set_equal(rows_v2ps,rows,val):
#print('row',rows,val,rows_v2ps[rows[0]][val])
### 从两列的其他候选 删除 该值
for col in rows_v2ps[rows[0]][val]:
for row in range(9):
if row not in rows and isinstance(may[row,col],set):
may[row,col]=may[row,col].difference([val])
count+=1
## 计算各列 被选2次的数字所在位置
cols_v2ps=[]
for col in range(9):
v2ps={val:{row for row in range(9) if isinstance(may[row,col],set) and val in may[row,col]} \
for val in range(1,10) if val not in arr[:,col]}
cols_v2ps.append({v:ps for v,ps in v2ps.items() if len(ps)==no})
cols_v2ps={col:v2ps for col,v2ps in enumerate(cols_v2ps) if len(v2ps)>0}
## 寻找 数字 与 位置 都相同的 列对
'''for c1,c2 in combinations(cols_v2ps, 2):
jiaoji = set(cols_v2ps[c1].keys()).intersection(cols_v2ps[c2].keys())
for val in jiaoji:
if cols_v2ps[c1][val] == cols_v2ps[c2][val]:
print('col',{c1,c2},val,cols_v2ps[c1][val])
### 从两行的其他候选 删除 该值
for row in cols_v2ps[c1][val]:
for col in range(9):
if col not in (c1,c2) and isinstance(may[row,col],set):
may[row,col]=may[row,col].difference([val])'''
for cols in combinations(cols_v2ps, no):
jiaoji = intersection(cols_v2ps,cols)
for val in jiaoji:
if set_equal(cols_v2ps,cols,val):
#print('col',cols,val,cols_v2ps[cols[0]][val])
### 从两列的其他候选 删除 该值
for row in cols_v2ps[cols[0]][val]:
for col in range(9):
if col not in cols and isinstance(may[row,col],set):
may[row,col]=may[row,col].difference([val])
count+=1
return count
### 多数字 链摒除
def exclude_link(sub):
count = exclude_1(sub) # 1链 摒除
count += exclude_hide_1(sub) # 隐性1链 摒除
count += exclude_n(sub,2) # 2链 摒除
count += exclude_hide_n(sub,2) # 隐性2链 摒除
count += exclude_n(sub,3) # 3链 摒除
count += exclude_hide_n(sub,3) # 隐性3链 摒除
count += exclude_n(sub,4) # 4链 摒除
count += exclude_hide_n(sub,4) # 隐性4链 摒除
return count
### 总搜寻
def search(arr):
may=candidate_set(arr)
repel_block(arr,may) # 寻找区块以摒除
for r in range(9):
sub=may[r]
exclude_link(sub)
#print('row',r,exclude_link(sub))
may[r]=sub
for c in range(9):
sub=may[:,c]
exclude_link(sub)
#print('col',c,exclude_link(sub))
may[:,c]=sub
for g in range(9):
rs,cs = divmod(g,3)
sub=may[rs*3:rs*3+3,cs*3:cs*3+3].reshape(-1)
exclude_link(sub)
#print('gong',g,exclude_link(sub))
may[rs*3:rs*3+3,cs*3:cs*3+3] = sub.reshape(3,3)
exclude_block(arr,may) # 划分区块以摒除
exclude_rectangle(arr, may,2) # 矩形摒除
exclude_rectangle(arr, may,3) # 三连行(列)摒除
#exclude_rectangle(arr, may,4)
count=0
for r in range(9):
for c in range(9):
if isinstance(may[r,c],set) and len(may[r,c])==1:
arr[r,c]=list(may[r,c])[0]
count+=1
return count
'''
count=81
while count>0 and not is_done(arr):
#while not is_done(arr):
count = search(arr)
print(count)
np.array([[len(may[r,c]) if isinstance(may[r,c],set) else None for c in range(9)] for r in range(9)])
'''
#%% usage
### 2,001
txt="""
61 3 2
5 81 7
7 34
9 6378
32795
57 3 9 2
19 76
8 24 76
64 1 25
"""
arr=parse(txt)
### 3,001 能解
arr=np.array([
[8,1,5, 0,0,0, 0,0,0],
[0,0,0, 9,0,0, 0,0,7],
[0,3,7, 0,0,0, 1,0,8],
[0,0,0, 0,9,0, 7,0,6],
[0,4,0, 0,5,0, 0,1,0],
[3,0,2, 0,1,0, 0,0,0],
[1,0,9, 0,0,0, 3,4,0],
[2,0,0, 0,0,6, 0,0,0],
[0,0,0, 0,0,0, 6,5,1],
])
### 6,001, 不能解,中间 人工 置数 可解;答案唯一;这类问题如何破局??
arr=np.array([
[0,0,1, 3,5,0, 0,0,0],
[0,3,0, 0,0,7, 0,0,0],
[5,0,0, 0,0,0, 9,0,0],
[7,0,0, 2,0,0, 4,0,0],
[9,0,0, 0,0,0, 6,0,0],
[0,2,0, 0,0,8, 0,0,7],
[0,0,4, 6,8,0, 1,0,2],
[0,0,0, 0,0,0, 0,8,0],
[0,0,0, 0,0,4, 3,0,0],
])
'''
search(arr)
search(arr)
search(arr)
arr[0,6]=2 # 8 #
arr[8,8]=5
arr[5,2]=3 #6 # 都走不动,不是关键点
is_error(arr)
is_done(arr)
'''
### 6,091 能解
arr=np.array([
[1,0,0, 5,0,0, 0,9,0],
[0,0,3, 0,4,0, 0,0,6],
[0,0,0, 0,0,0, 0,3,0],
[0,6,0, 0,0,7, 0,0,0],
[4,0,9, 0,0,0, 8,0,5],
[0,0,0, 6,0,0, 0,2,0],
[0,9,0, 0,0,0, 0,0,0],
[2,0,0, 0,5,0, 1,0,0],
[0,4,0, 0,0,3, 0,0,8],
])
### 9,001 能解
arr=np.array([
[0,7,0, 4,0,0, 6,0,2],
[0,0,4, 0,9,0, 0,0,0],
[1,0,0, 0,2,5, 0,0,0],
[6,0,5, 0,0,0, 4,1,0],
[0,0,7, 0,8,4, 0,6,5],
[4,0,2, 0,0,0, 7,8,0],
[8,0,0, 0,7,2, 0,0,0],
[0,0,6, 0,4,0, 0,0,0],
[0,9,0, 8,0,0, 1,0,4],
])
### 9,050 能解
arr=np.array([
[0,0,1, 0,2,0, 0,0,0],
[9,8,0, 0,0,0, 2,0,0],
[0,0,0, 4,0,0, 6,0,0],
[0,0,5, 0,0,2, 9,0,0],
[0,4,0, 0,8,0, 5,0,6],
[8,0,0, 0,0,0, 0,0,0],
[0,0,3, 5,0,4, 0,0,1],
[0,6,2, 0,0,0, 0,4,0],
[0,0,0, 0,1,0, 0,0,0],
])
### 10,050, 能解
arr=np.array([
[0,0,0, 0,0,0, 0,0,0],
[0,3,8, 5,0,0, 4,1,0],
[0,6,0, 7,0,0, 0,2,0],
[0,0,0, 8,0,5, 3,4,0],
[0,0,0, 0,9,0, 0,0,0],
[0,1,7, 6,0,2, 0,0,0],
[0,5,0, 0,0,3, 0,6,0],
[0,7,2, 0,0,1, 5,8,0],
[0,0,0, 0,0,0, 0,0,0],
])
### 10,101 能解
arr=np.array([
[1,0,0, 4,0,0, 0,0,5],
[0,2,3, 0,0,0, 0,6,0],
[0,0,0, 0,0,8, 0,7,0],
[0,0,9, 0,5,0, 0,0,1],
[0,0,0, 6,0,7, 0,0,0],
[5,0,0, 0,2,0, 4,0,0],
[0,3,0, 9,0,0, 0,0,0],
[0,4,0, 0,0,0, 3,2,0],
[7,0,0, 0,0,6, 0,0,9],
])
### 网上 单元摒除法
arr=np.array([
[8,0,0, 0,9,2, 0,0,0],
[5,0,0, 0,3,0, 0,6,0],
[0,1,0, 0,0,0, 0,9,0],
[0,8,0, 0,7,0, 0,0,0],
[0,0,9, 0,0,0, 0,8,2],
[0,0,5, 0,2,0, 0,4,0],
[6,0,3, 5,0,0, 4,0,0],
[0,0,0, 1,0,0, 0,0,7],
[0,0,0, 0,0,7, 9,0,0],
])
#%% old code
### {{ 野路子
def findSameSet(sub):
cnt = len(sub)
for i in range(cnt-1):
if sub[i] is None:
continue
for j in (range(i+1,cnt)):
if sub[j] is None:
continue
if sub[i]==sub[j]:
return i,j
return None,None
def DiffSame2_Rest1(sub):
a,b = findSameSet(sub) # 有相同候选集
if not a is None:
equalSet=sub[a]
if len(equalSet)==2: # 相同候选集 因素个数是2
for i,ss in enumerate(sub):
if isinstance(ss,list) and i != a and i != b: # 相同候选集之外的 候选集
tmp=list(set(ss).difference(equalSet))
if len(tmp)==1: # 刨除相同候选集的元素,只剩一个元素
return i,tmp[0]
return None,None
### 野路子}}
### 某数只出现在一个候选集中,则该单元就是次数
def onlyOne(sub):
counts=np.array([sum([v in s for s in sub if isinstance(s,list)]) for v in range(1,10)])
pos=np.where(counts==1)[0]
res=[]
for p in pos:
v=p+1
i=np.where([v in s if isinstance(s,list) else False for s in sub])[0][0]
res.append((i,v))
return res
'''
for r in range(9):
print(r,len( onlyOne(may[r])))
for c in range(9):
print(c,len( onlyOne(may[:,c])))
for g in range(9):
rs,cs = divmod(g,3)
print(g,len( onlyOne(may[rs*3:rs*3+3,cs*3:cs*3+3].reshape(-1))))
'''
def search(arr):
count=0
for r in range(9):
for c in range(9):
if isinstance(may[r,c],list) and len(may[r,c])==1:
arr[r,c]=may[r,c][0]
count+=1
'''if count > 0:
return count
'''
'''
stat=np.array([[len(may[r,c]) if isinstance(may[r,c],set) else None for c in range(9)] for r in range(9)])
pos=np.where(stat==2)
[(x,y,may[x,y]) for x,y in zip(pos[0],pos[1])]
'''
for r in range(9):
res=onlyOne(may[r])
for t in res:
arr[r,t[0]]=t[1]
count+=1
'''c,val = DiffSame2_Rest1(may[r])
if not c is None:
arr[r,c] = val
count+=1'''
for c in range(9):
res=onlyOne(may[:,c])
for t in res:
arr[t[0],c]=t[1]
count+=1
'''r,val = DiffSame2_Rest1(may[:,c])
if not r is None:
arr[r,c] = val
count+=1'''
for g in range(9):
rs,cs = divmod(g,3)
res=onlyOne(may[rs*3:rs*3+3,cs*3:cs*3+3].reshape(-1))
for t in res:
rr,cc = divmod(t[0],3) # 宫内位置
r,c = rs*3+rr,cs*3+cc
arr[r,c]=t[1]
count+=1
'''rs,cs = divmod(g,3)
p,val = DiffSame2_Rest1(may[rs*3:rs*3+3,cs*3:cs*3+3].reshape(-1))
if not p is None:
rr,cc = divmod(p,3) # 宫内位置
r,c = rs*3+rr,cs*3+cc
arr[r,c] = val
count+=1'''
return count
count=81
while count>0 and not check(arr):
#while not check(arr):
count = search(arr)
print(count)
check(arr)
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/swankhli/suduku.git
[email protected]:swankhli/suduku.git
swankhli
suduku
suduku
master

搜索帮助