相信大家对数独都不陌生。
不过笔者并不算十分忠实的数独玩家,但数独是一种规则和形式都十分简单的游戏。
于是萌生了用python来解决数独的想法。
第一条判断方式最为简单,也最容易实现。但是之后的思考模式代码化就不是很容易了。
计划以后添加更多判断方式。
所以最终的结果大概算是一个半成品,但已经能解决比较基本的数独。
示例如下:
本来打算利用pyautogui实现完全的自动化的。但是考虑到不同的网页的数独呈现方式的差异可能会使得程序的局限性更大。于是采用了一种麻烦一点,但可以接受的方式进行数据输入。
用0来代表未知的数字,其他的数字则表示已知数字。
最终需要的就是下面那一行数字。(9*9的表示只是为了自己检查方便)
运行过程如下:
可以看到程序返回了完整数独。
测试文本如下:
028009000
000070180
700050002
000930570
050107004
410000060
630700200
105008403
000095700
028009000000070180700050002000930570050107004410000060630700200105008403000095700
代码如下:
class Square():
def __init__(self,position,num):
self.position = position
self.num = num
def __str__(self):
return '[%s,%s]'% (self.position,self.num)
def getaround(self):
aroundlist = []
x = self.position[0]
y = self.position[1]
if 0 <= x <3:
startx = 0
elif 3 <= x <6:
startx = 3
else :
startx = 6
if 0 <= y < 3:
starty = 0
elif 3 <= y < 6:
starty = 3
else:
starty = 6
for each in wholepart:
if startx <= each.position[0] < startx+3:
if starty <= each.position[1] <starty+3:
aroundlist.append(each)
return aroundlist
def getaline(self):
linelist = []
for each in wholepart:
if each.position[1] == self.position[1]:
linelist.append(each)
return linelist
def getarow(self):
rowlist = []
for each in wholepart:
if each.position[0] == self.position[0]:
rowlist.append(each)
return rowlist
def set(alist,num):
returnlist = []
typelist = [[0,3,0,3],[0,3,3,6],[0,3,6,9],\
[3,6,0,3],[3,6,3,6],[3,6,6,9],\
[6,9,0,3],[6,9,3,6],[6,9,6,9]]
for i in alist:
if typelist[num][0] <= i.position[0] <typelist[num][1] and \
typelist[num][2] <= i.position[1] <typelist[num][3]:
returnlist.append(i)
return returnlist
# 生成整个棋局
wholepart = []
for row in range(9):
for line in range(9):
example = Square((row,line),[])
wholepart.append(example)
replacelist = []
tolist = []
times = 0
enter = input('please enter:')
print(enter)
for i in enter:
if i != '0':
tolist.append(int(i))
replacelist.append(times)
times = times + 1
print(tolist)
print(replacelist)
h = dict(zip(replacelist,tolist))
for known,t in h.items():
wholepart[known].num.append(t)
# 核心代码,计算填什么
# 1.通过交叉初步确定可以填的简单空
def caculate(originpart):
check1=[] #用于递归判断是否凭借已有方法无法继续填空
check2=[] #也就时对比本次递归和上一次递归的结果是否相同,相同则说明已到终点
for i in originpart:
check1.append(i.num)
wholepart = originpart[:]
for crossnum in range(1,10):
copylist = wholepart[:]
eightnumlist = []
for h in wholepart:
if h.num == [crossnum]:
eightnumlist.append(h)
copylist.remove(h)
# 移除8方块
for m in eightnumlist:
doublecopylist = copylist[:] #获得副本,避免跳删
for t in doublecopylist:
if t.position[0] == m.position[0] or \
t.position[1] == m.position[1]:
copylist.remove(t)
# 移除8方块同行同列的元素
anothercopylist = copylist[:]
for h in anothercopylist:
if h.num != []:
copylist.remove(h)
for k in range(9):
processlist = set(copylist,k)
if len(processlist) == 1:
do = True
for each in processlist[0].getaround():
if each.num == [crossnum]:
do = False
if do:
processlist[0].num = [crossnum]
for i in originpart:
check2.append(i.num)
if check1 == check2:
return
else :
caculate(wholepart)
print('-'*40)
# 运算
caculate(wholepart)
# 通过确定某数字必在某条线上从而排除某条线
# 第二层逻辑未成功,有机会跟新(一下内容未使用)
def caculate2(originpart):
wholepart = originpart[:]
for crossnum in range(1, 10): #crossnum就是正在分析的可以填在哪里的数字
copylist = wholepart[:]
eightnumlist = []
for h in wholepart:
if h.num == [crossnum]:
eightnumlist.append(h)
copylist.remove(h)
# 移除8方块
for m in eightnumlist:
doublecopylist = copylist[:] # 获得副本,避免跳删
for t in doublecopylist:
if t.position[0] == m.position[0] or \
t.position[1] == m.position[1]:
copylist.remove(t)
# 移除8方块同行同列的元素
anothercopylist = copylist[:]
for h in anothercopylist:
if h.num != []:
copylist.remove(h)
nocrossnumlist = []
for k in range(9):
processlist = [i.num for i in set(wholepart, k)]
if [crossnum] not in processlist:
nocrossnumlist.append(k)
# 检查是否在同一竖线上
for every in nocrossnumlist:
copynclist = nocrossnumlist[:]
for everyother in copynclist.remove(every):
checklist = set(copylist,everyother)
removable = True
x = [everySquare.position[0] \
for everySquare in checklist]
y = [everySquare.position[0] \
for everySquare in checklist]
startx = x[0]
starty = y[0]
for every in x:
if every != startx:
removable = False
for every in y:
if every != starty:
removable = False
lne = 0
for i in wholepart:
lne += 1
if i.num != []:
if not lne%9 == 0:
print(i.num,end='')
else:
print(i.num,end='\n')
else:
if not lne % 9 == 0:
print('[_]', end='')
else:
print('[_]', end='\n')
对于复杂的数独,这个程序也起到一种辅助的作用。
以上代码还有诸多不足,有很多看上去多余的部分是留着给更复杂的判断方式的。
欢迎指正。
本文含有隐藏内容,请 开通VIP 后查看