需要用到的包
from selenium import webdriver
from selenium.webdriver.common.by import By
from shudu_count import *
对坐标的一些操作
class re_zuobiao:
# 获取坐标 坐在 行的 坐标
def re_heng(self, zb):
return [f'{zb[0]}{i}' for i in range(1, 10)]
# 获取坐标 所在列的坐标
def re_shu(self, zb):
return [f'{i}{zb[1]}' for i in range(1, 10)]
# 获取坐标所在宫、横竖的宫 的坐标
# lei=1 返回坐标所属宫
# lei =2 返回 所在功 上下方向功
# lei = 3 返回所在宫 左右宫
# lei = 4 返回 上下左右宫(不包含所属宫)
# lei = 5 返回 上下左右宫(包含所属宫)
def re_gong(self, zb, lei):
gong = []
for i in dic_jiu['fang'].keys():
if lei == 1 and (zb[0] in i[:3] and zb[1] in i[3:]):
gong.append(i)
break
if lei == 5 and (zb[0] in i[:3] or zb[1] in i[3:]):
gong.append(i)
if lei == 2 and (zb[0] not in i[:3] and zb[1] in i[3:]):
gong.append(i)
if lei == 3 and (zb[0] in i[:3] and zb[1] not in i[3:]):
gong.append(i)
if lei == 4 and (zb[0] in i[:3] or zb[1] in i[3:]):
gong.append(i)
if zb[0] in i[:3] and zb[1] in i[3:]:
gong.remove(i)
return gong
# 获取 宫内所有坐标
def re_zb_byf(self, zb, lei):
list_zb = []
gong = self.re_gong(zb, lei)
for i in gong:
for a in range(0, 3):
for b in range(1, 4):
list_zb.append(f'{i[a]}{i[-b]}')
return list_zb
def re_qzb_by_QD(self, zb):
list1 = self.re_heng(zb) + self.re_shu(zb) + self.re_zb_byf(zb, 1)
list2 = sorted(list(set(list1)), key=list1.index)
list2.remove(zb)
return list2
def re_zb_by_HS(self, zb11, zb21, zb33='00'):
zb_lt = []
zb1 = str(zb11)
zb2 = str(zb21)
zb3 = str(zb33)
if (zb1[0] == zb2[0] and zb3 == '00') or (zb1[0] == zb2[0] == zb3[0]):
fang = self.re_gong(zb1, 3)
for i in fang:
for j in range(1, 4):
zb_lt.append(f'{zb1[0]}{i[-j]}')
elif (zb1[1] == zb2[1] and zb3 == '00') or (zb1[1] == zb2[1] == zb3[1]):
fang = self.re_gong(zb1, 2)
for a in fang:
for b in range(0, 3):
zb_lt.append(f'{a[b]}{zb1[1]}')
else:
zb_lt = None
return zb_lt
# 返回没确定值坐标,可填的值字典
def re_no_zb_num(self):
list_zb = [i for i in dic_shu.keys() if dic_shu[i] == 0]
dic_zb_num = {}
for z in list_zb:
dic_zb_num[z] = []
for i in range(1, 10):
gong = self.re_gong(z, 1)[0]
if isinstance(dic_1_9[i][gong], list) and int(z) in dic_1_9[i][gong]:
dic_zb_num[z].append(i)
return dic_zb_num
清除后选值的方法
class RemoveNum:
def __init__(self):
self.rb = re_zuobiao()
# 显性 数组(找到符合显性数组的例子)
def remove_by_gong_tong(self):
dic_zb_n = self.rb.re_no_zb_num()
# 宫内 显性数组
for k in dic_jiu['fang'].keys():
dic_f = {}
list_s = [f'{k[i]}{k[-j]}' for i in range(0, 3) for j in range(1, 4)]
for kk in dic_zb_n.keys():
if kk in list_s:
dic_f[kk] = dic_zb_n[kk]
self.do_remove_by_gong_tong(dic_f, list_s)
# 行显性数组
for i in range(1, 10):
dic_h = {}
dic_s = {}
list_s = [ke for ke in dic_zb_n.keys() if i == int(ke[1])]
list_h = [ke for ke in dic_zb_n.keys() if i == int(ke[0])]
for ss in list_s: dic_s[ss] = dic_zb_n[ss]
for hh in list_h: dic_h[hh] = dic_zb_n[hh]
self.do_remove_by_gong_tong(dic_h, list_h)
self.do_remove_by_gong_tong(dic_s, list_s)
# 显性数组逻辑移除候选值
def do_remove_by_gong_tong(self, dic_x, list_s):
for a in dic_x.keys():
for b in dic_x.keys():
if a != b and dic_x[a] == dic_x[b] and len(dic_x[a]) == 2:
if a in list_s: list_s.remove(a)
if b in list_s: list_s.remove(b)
for ab in list_s:
for ji in dic_x[a]:
self.remove(ab, ji, f'宫内显性数组移除信息;{a}={dic_x[a]},{b}={dic_x[b]}')
for c in dic_x.keys():
if a != b and b != c and a != c:
if len(set(dic_x[a] + dic_x[b] + dic_x[c])) == 3 and (
len(dic_x[a]) + len(dic_x[b]) + len(dic_x[c])) >= 7:
if a in list_s: list_s.remove(a)
if b in list_s: list_s.remove(b)
if c in list_s: list_s.remove(c)
for abc in list_s:
for jj in set(dic_x[a] + dic_x[b] + dic_x[c]):
self.remove(abc, jj, f'f显性数组移除,{a}={dic_x[a]},{b}={dic_x[b]},{c}={dic_x[c]}')
# x-wing排除
def do_remove_by_x_wing(self):
dic_zb_n = self.rb.re_no_zb_num()
dicd = []
for i in range(1, 10):
for zs in range(1, 10):
hang = []
for zg in range(1, 10):
zb = str(zs) + str(zg)
if zb in dic_zb_n.keys():
if i in dic_zb_n[zb]:
hang.append(zb)
hang.append(i)
if len((hang)) == 3: dicd.append(hang)
for i in range(0, len(dicd)):
for j in range(i + 1, len(dicd)):
if dicd[i][2] == dicd[j][2] and dicd[i][0][1] == dicd[j][0][1] and dicd[i][1][1] == dicd[j][1][1]:
list1 = self.rb.re_shu(dicd[i][0])
list2= self.rb.re_shu(dicd[i][1])
list3 = list2+list1
list3.remove(dicd[i][0])
list3.remove(dicd[i][1])
list3.remove(dicd[j][0])
list3.remove(dicd[j][1])
for n in list3:
self.remove(n,dicd[i][2])
# XY-wing
def remove_by_xy_wing(self):
dic_zb_n = self.rb.re_no_zb_num()
dic_x = {}
for x in dic_zb_n.keys():
if len(dic_zb_n[x]) == 2:
dic_x[x] = dic_zb_n[x]
for k in dic_x.keys():
l1 = dic_x[k]
for kk in dic_x.keys():
l2 = dic_x[kk]
if k[0] == kk[0] and len(set(dic_x[k] + dic_x[kk])) == 3:
num1= 0
num2=0
for i in l1:
if i not in l2:num1=i
for j in l2:
if j not in l1:num2 = j
if num1!=0 and num2!=0:
for kkk in dic_x.keys():
if kkk[1]==kk[1] and len(dic_x[kkk])==2 and num1 in dic_x[kkk] and num2 in dic_x[kkk]:
for zb in dic_zb_n.keys():
if kkk[0] ==zb[0]:
self.remove(zb, num2, f'X——Y wing移除:{k}={dic_x[k]},{kk}={dic_x[kk]},{kkk}={dic_x[kkk]}')
# 行列区块排除
def remove_by_hl_qk(self):
dic_zb_n = self.rb.re_no_zb_num()
for i in range(1, 9):
list_h = {}
list_s = {}
for x in dic_zb_n.keys():
if int(x[0]) == i:
list_h[x] = dic_zb_n[x]
if int(x[1]) == i:
list_s[x] = dic_zb_n[x]
self.do_remove_by_hl_qk(list_h, 0)
self.do_remove_by_hl_qk(list_s, 1)
# 行列区块排除,找到可以移除的 待定值,行排除 h_s=0,列排除h_s=1
def do_remove_by_hl_qk(self, dic, h_s):
for a in dic.keys():
for x in dic[a]:
num = 0
a_gong = self.rb.re_gong(a, 1)[0]
for b in dic.keys():
if h_s == 0 and b[1] not in a_gong[-4:] and x in dic[b]:
num += 1
if h_s == 1 and b[0] not in a_gong[:3] and x in dic[b]:
num += 1
if num == 0:
if h_s == 0:
list_rm = [f'{i}{j}' for i in a_gong[:3] for j in a_gong[-3:] if i != a[h_s]]
if h_s == 1:
list_rm = [f'{i}{j}' for i in a_gong[:3] for j in a_gong[-3:] if j != a[h_s]]
for i in list_rm: self.remove(i, x,'行列区块排除,找到可以移除的')
# 确认一个值,移除宫内内其他格,行列其他格此值候选
def remove_by_QD(self, zb, num):
for i in self.rb.re_qzb_by_QD(zb):
self.remove(i, num,f'确认一个值,移除功能内其他格,行列其他格此值候选:根据坐标={zb},移除坐标={i},数={num}')
for l in range(1, 10):
if l != num:
listfg = dic_1_9[l][self.rb.re_gong(zb, 1)[0]]
if isinstance(listfg, list) and len(listfg) > 1 and int(zb) in dic_1_9[l][self.rb.re_gong(zb, 1)[0]]:
dic_1_9[l][self.rb.re_gong(zb, 1)[0]].remove(int(zb))
if len(dic_1_9[l][self.rb.re_gong(zb, 1)[0]]) == 1:
self.set_value(str(dic_1_9[l][self.rb.re_gong(zb, 1)[0]][0]), l,'确认一个值,移除功能内其他格,行列其他格此值候选remove_by_QD')
# 宫内 确定某值在 同行、列,移除行列上别的格子此值的候选
def remove_by_two(self):
for i in dic_1_9.keys():
for ke in dic_1_9[i].keys():
if isinstance(dic_1_9[i][ke], list) and 2 <= len(dic_1_9[i][ke]) <= 3:
list_t = self.rb.re_zb_by_HS(*dic_1_9[i][ke])
if list_t != None and len(list_t) > 1:
for jk in list_t:
self.remove(jk, i,'remove_by_two')
# 移除操作
def remove(self, zb, num, name=''):
qr_g = self.rb.re_gong(zb, 1)[0]
xx = dic_1_9[num][qr_g]
if isinstance(xx, list) and len(xx) > 1 and int(zb) in xx:
dic_1_9[num][qr_g].remove(int(zb))
if 'X——Y wing移除' in name: print(f'移除:[{num}] = P[{zb}]————来自方法{name}')
if len(dic_1_9[num][qr_g]) == 1:
self.set_value(str(dic_1_9[num][qr_g][0]), num,f'{name}')
# 更新每个方块,每行、每列数值已确定格子的数量
# 很鸡肋的方法
def hanglie_qukuai(self):
list1 = [f'{i}{j}' for i in range(1, 10) for j in range(1, 10)]
for i in list1:
bj = 0
for ke in dic_1_9.keys():
for keke in dic_1_9[ke].keys():
remove_list = dic_1_9[ke][keke]
if isinstance(remove_list, list) and int(i) in remove_list:
bj += 1
if bj == 1: set_list = [i, ke]
if bj == 1: self.set_value(set_list[0], set_list[1],'很鸡肋的方法' )
# 修改宫、行、列已确定数字的个数
def update_tianxieshu(self, x, value):
fang = self.rb.re_gong(x, 1)[0]
heng = x[0] + '_19'
shu = '19_' + x[1]
dic_jiu['fang'][fang] += 1
dic_jiu['heng'][heng] += 1
dic_jiu['shu'][shu] += 1
# 方块、横、竖 数值已确定格子数量=8,可推导出第9个格子的数值
if dic_jiu['fang'][fang] == 8:
self.get_8_1('fang', fang)
if dic_jiu['heng'][heng] == 8:
self.get_8_1('heng', heng)
if dic_jiu['shu'][shu] == 8:
self.get_8_1('shu', shu)
# 当前宫内,可能出现的数字
def get_keneng(self, fang):
list_19 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
list_0 = []
for i in range(0, 3):
for j in range(1, 4):
zb = f'{fang[i]}{fang[-j]}'
if dic_shu[zb] != 0 and dic_shu[zb] in list_19:
list_19.remove(dic_shu[zb])
else:
list_0.append(zb)
return list_19, list_0
def do_some(self, zb, lt_19):
# 得到单元格所在 行的所有坐标,看看行内有没有 可能出现的数字 并移除
for i in range(1, 10):
if dic_shu[f'{zb[0]}{i}'] in lt_19:
lt_19.remove(dic_shu[f'{zb[0]}{i}'])
# 得到单元格所在 列的所有坐标,看看行内有没有 可能出现的数字 并移除
for j in range(1, 10):
if dic_shu[f'{j}{zb[1]}'] in lt_19:
lt_19.remove(dic_shu[f'{j}{zb[1]}'])
if len(lt_19) == 1:
self.set_value(zb, lt_19[0],'得到宫内可能出现的值,可功能没有确认值的单元格,判断单元格内不能出现的数字')
else:
for i in range(1, 10):
if i not in lt_19:
self.remove(zb, i, '打印remove_by_fhs')
# 根据 已确定数值的8个格子,得到第9个格子的 数值
# 得到宫内可能出现的值,可功能没有确认值的单元格,判断单元格内不能出现的数字
def remove_by_fhs(self):
# 循环得到所有功
for k in dic_jiu['fang'].keys():
# 判断功能内缺少的数字,以及没有确定值的单元格
if dic_jiu['fang'][k] != 9:
list_19, list_0 = self.get_keneng(k)
# 循环 功能没有确定值的格子,
for i in list_0:
lt_19 = list_19.copy()
self.do_some(i, lt_19)
def get_8_1(self, fenlei, key):
list_1 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
list_2 = []
set_key = ''
if fenlei == 'fang':
for heng in key[:3]:
for shu in key[4:]:
if dic_shu[heng + shu] != 0:
list_2.append(dic_shu[heng + shu])
else:
set_key = heng + shu
if fenlei == 'heng':
for i in range(1, 10):
if dic_shu[key[0] + str(i)] != 0:
list_2.append(dic_shu[key[0] + str(i)])
else:
set_key = key[0] + str(i)
if fenlei == 'shu':
for i in range(1, 10):
if dic_shu[str(i) + key[-1]] != 0:
list_2.append(dic_shu[str(i) + key[-1]])
else:
set_key = str(i) + key[-1]
list3 = list(set(list_1) - set(list_2))
self.set_value(set_key, list3[0],'唯余')
# 确定格子值,赋值
def set_value(self, zb, num,name = ''):
if dic_shu[zb] != 0 and name !=0:
print(f'出错了,dic_shu[{zb}]={dic_shu[zb]},不能再赋值:{num}\n来自方法{name}')
else:
dic_shu[zb] = num
fang = self.rb.re_gong(zb, 1)
dic_1_9[num][fang[0]] = int(zb)
self.update_tianxieshu(zb, num)
self.remove_by_QD(zb, num)
把结果写入对应单元格
def do_wirite(elename, driver, num):
driver.find_element(By.ID,elename).click()
driver.find_element(By.ID,elename).send_keys(num)
# 判断是否还有格子没确定数字
def do_do_do(cishu):
m = True
list = [f'{i}{j}' for i in range(1, 10) for j in range(1, 10)]
for ke in list:
if dic_shu[ke] == 0:
break
elif ke == list[-1] and dic_shu[ke] != 0:
m = False
if cishu == 15: m = False
return m
# 遍历移除
def test_do_new(test_dic, driver):
sd = RemoveNum()
ssss = re_zuobiao()
for key in test_dic.keys():
sd.set_value(key, test_dic[key],'初始赋值')
cishu = 0
while do_do_do(cishu):
sd.remove_by_fhs()
sd.remove_by_two()
sd.hanglie_qukuai()
sd.remove_by_hl_qk()
sd.remove_by_gong_tong()
sd.do_remove_by_x_wing()
# sd.remove_by_xy_wing()
cishu += 1
print(dic_1_9)
print(dic_jiu)
for i in range(1, 10):
str_some = ''
for j in range(1, 10):
s = str(i) + str(j)
if s not in test_dic.keys() and dic_shu[s] != 0:
elename = f's{(i - 1) * 9 + j}'
do_wirite(elename, driver, str(dic_shu[s]))
str_some += (' ' + str(dic_shu[s]) + '-')
if j % 3 == 0:
str_some += '|'
print('——————————————————————————————————————————————————————————————————————')
print(f'第{i}行:{str_some}')
print('***************************')
print(ssss.re_no_zb_num())
# time.sleep(3)
# driver.find_element_by_id('btn-save').click()
def test_doDDD():
for i in range(1, 10):
for j in range(1, 10):
print((i - 1) * 9 + j)
def test_get_num():
# https: // cn.sudokupuzzle.org /
# chrome --remote-debugging-port=9222
opt = webdriver.ChromeOptions()
opt.debugger_address = '127.0.0.1:9222'
driver = webdriver.Chrome(options=opt)
# driver.maximize_window()
driver.implicitly_wait(10)
test_dic = {}
driver.switch_to.frame('f1')
for i in range(1, 82):
if i % 9 == 0:
h = int(i / 9)
s = 9
else:
h = int(i / 9) + 1
s = i % 9
ele = driver.find_element(By.ID,f's{i}').get_attribute('value')
if ele != '':
test_dic[f'{h}{s}'] = int(ele)
print(test_dic)
test_do_new(test_dic, driver)