最近突然对数独感兴趣,玩了好几天。慢慢摸索出了一些解题规律,就想着能不能用代码自动化实现。趁五一放假试着写了点代码,效果还行,至少不比网上一些教程里慢太多,因此就放到这里跟大家分享一下。
由于本人也是Python新手,很多语句可能不够简洁,还望见谅。
完整代码可见github链接:https://github.com/linking9230/sudoku.git
一、数独输入
我准备了两套数独题目作为测试,一套为困难难度的,另一套为专家难度。
困难:
专家:
我将数据放入到CSV文件中,空白格用0代替,方便读取和识别。
二、代码实现
数独的玩法大家应该都清楚,就是每一格的取值为1-9中的一个,并且在所在行,所在列,以及所在九宫格内不能重复。而游戏的难点就在于,每一个单元格,可填入的数字会有很多,这就使得我们不得不去寻找正确的数字。
当我实际在玩时,有很多小技巧,可以相对快速的找到正确的数字。但是对于编程而言,代码的优势在于计算速度快,因此使用穷举思想,也能够较快速找到正确的数字。
因此,我的第一个想法,就是利用递归循环解决问题。
——————————————————————————————————————
首先,我需要获取任意一个单元格可填入的值列表,代码如下:
def para(i):
r=i//9
c=i%9
rr=r//3
cr=c//3
rr_d=rr*3
rr_u=rr*3+3
cr_d=cr*3
cr_u=cr*3+3
return r,c,rr_d,rr_u,cr_d,cr_u
def ql(m,i):
f_l=[0,1,2,3,4,5,6,7,8,9]
r,c,rr_d,rr_u,cr_d,cr_u=para(i)
a=list(set(list(m[r])+list(m[:,c])+list(m[rr_d:rr_u,cr_d:cr_u].flatten())))
q_l=[x for x in f_l if x not in a]
return q_l,r,c
第一个函数的目的是,我在实际循环过程中,是将99的数独矩阵,展开成了811的一维列表,方便我进行循环。而利用para函数,则可以从一维列表的index返回到9*9矩阵的参数,并且获得该单元格所在九宫格的范围(rr_d,rr_u,cr_d,cr_u即为该九宫格的行列上下限)
第二个函数也很好理解,我把所在行,所在列,所在九宫格的所有值集合起来,用一个set去重,那么剩下未出现的数字,就是该单元格可以选择的值,返回为一个列表。
——————————————————————————————————————
接着,就可以递归循环解答了(后来我才知道,这种递归循环,其实也就是深度优先循环,或者DFS算法,也算歪打正着)。
def dg(m,n,i,l,flag):
#m:matrix
#n:flatten matrix
#i: 第i个单元格
#l:最后一个空单元格的位置
if flag==0:
for j in range(i,l+1):
if n[j]==0:
break
q_l,r,c=ql(m,j)
if