数独代码python_数独


目录

  1. 用Python解数独[0]
  2. 用Python解数独[1]:求每个单元格的行值域
  3. 用Python解数独[2]:求列值域和九宫格值域
  4. 用Python解数独[3]:求总值域
  5. 用Python解数独[4]:缩减值域
  6. 用Python解数独[5]:检测唯一值缩减值域
  7. 用Python解数独[6]:递归获得最终答案
  8. 用Python解数独[7]:递归(完结篇)

[2][1] 解决数独问题基本思路

2、求每个单元格的列值域

上回书说到,行值域已经得到,求列值域和九宫格值域的方法和行值域应该是一样的,但问题在于,如何表达列和九宫格,或者说如何用代码把数独里的每一列、每一个九宫格表达出来。


soduku = [[] for i in range(9)]

soduku[0] = ['',8,9,1,'',3,'','','']
soduku[1] = ['',2,7,4,'','',8,'','']
soduku[2] = ['','','',5,2,'','','','']
soduku[3] = ['',7,6,9,'','',5,'',8]
soduku[4] = [8,'',3,6,'',1,2,'','']
soduku[5] = ['',4,5,3,8,7,1,6,'']
soduku[6] = [7,'',8,2,1,4,3,9,5]
soduku[7] = [9,3,1,7,6,5,4,'',2]
soduku[8] = [4,'',2,'','',9,'','',6]


有一种很笨的方法:

第1列是由每一行的第1个元素组成的,用代码表示就是


soduku_col = [[] for i in range(9)]
for i in soduku:
    soduku_col[0].append(i[0])


第n列就是由每一行的第n个元素组成的,我们把上面的代码重复执行9遍就行了:


soduku_col = [[] for i in range(9)] 
for j in range(9):
    for i in soduku:     
        soduku_col[j].append(i[j])


将代码整理为函数:


def col_invert(soduku):
    soduku_col = [[] for i in range(9)] 
    for j in range(9):
        for i in soduku:     
            soduku_col[j].append(i[j])
    return soduku_col


当然其实Python有一个现成的函数——zip(),就是做这件事情的,代码可以修改


soduku_col = list(zip(*soduku))


我们看到zip函数里的参数是"*soduku",这个用法大家可以自行查询下,等价于下面这种写法:


soduku_col = list(zip(soduku[0],soduku[1],soduku[2],soduku[3],soduku[4],soduku[5],soduku[6],soduku[7],soduku[8]))


如果参数是"soduku",相当于输入的参数是soduku,参数数量是1个; 如果参数是"*soduku",相当于将列表soduku中的每一个元素当作参数,参数数量就是9个;

求列值域,有以下几步:

  • 根据当前数独数组,通过zip函数得到由每一列组成的新数独数组;
  • 根据rowValueRange(行值域函数),求新数独数组的“行值域”;
  • 通过zip函数将得到的“行值域数组”进行一次行列转换,从而得到原数独数组的列值域;
def colValueRange(soduku):
    soduku_invert = list(zip(*soduku))
    temp = rowValueRange(soduku_invert)
    s_column_vrange = list(zip(*temp))
    return s_column_vrange


3、求每个单元格的九宫格值域

我们用了列值域的处理经验,求九宫格值域的关键就是这个“九宫格转换函数”,如果把一个数独数组,转化为数独九宫格数组,这个问题看起来有点难,我们先回顾一下数独


数独代码python_matrix python 取元素_02


如果表示第一个九宫格,它由前三行的前三个元素组成,如果用代码表示可以这样写:


soduku_matrix = [[] for i in range(9)]
for i in range(9):
    for j in range(9):
        if i <= 3 and j <= 3:
            soduku_matrix[0].append(soduku[i][j])


如果我们愿意,我们可以用类似的方法得到剩余8个九宫格,但这样的代码好像有些粗暴,有更好的方法吗?我们观察数独棋盘,我们发现九宫格是以3为单位的:

第一个九宫格:前三行的前三个元素;
第二个九宫格:前三行的中间三个元素;
第三个九宫格:前三行的后三个元素;
......

我们可以加入整除操作:


soduku_matrix = [[] for i in range(9)]
for i in range(9):
    for j in range(9):
        k = i//3
        l = j//3


那么如何建立k , l 与九宫格下标的关系呢:

k = 0, l = 0 ,下标 m = 0
k = 0, l = 1 ,下标 m = 1
k = 0, l = 2 ,下标 m = 2
k = 1, l = 0 ,下标 m = 3
k = 1, l = 1 ,下标 m = 4
k = 1, l = 2 ,下标 m = 5
k = 2, l = 0 ,下标 m = 6
k = 2, l = 1 ,下标 m = 7
k = 2, l = 2 ,下标 m = 8

m与k , l应该是一种线性关系,因此列方程:m = ak + bl,得到 m = 3k + l

所以代码可以改为:


soduku_matrix = [[] for i in range(9)]
for i in range(9):
    for j in range(9):
        k = i//3
        l = j//3
        m = k*3 + l
        soduku_matrix[m].append(soduku[i][j])


我们整理出九宫格转换函数和九宫格值域函数:


def matrix_invert(lista):
    listb = [[] for i in range(9)]
    for i in range(9):
        for j in range(9):
            k = i//3
            l = j//3
            m = k*3 + l
            listb[m].append(soduku[i][j])
    return listb

def matrixValueRange(soduku):
    matrix = matrix_invert(soduku)
    temp = rowValueRange(matrix)
    matrix_vrange = matrix_invert(temp)
    return matrix_vrange


数独数组a通过九宫格转化为数独数组b,然后数独数组b通过九宫格转化,可以再转化为数独数组a。这个大家可以自己观察数独棋盘体会一下。

现在我们已经获得了一个单元格的行值域、列值域和九宫格值域,可以考虑通过三个值域来获得这个单元格的总值域了。这个问题可以抽象为有lista , listb和listc,求三个列表的交集。

下面我们的项目代码将变得越来越复杂,但其实并没有引入其它复杂的概念,依然是循环、条件判断和列表相关方法,预知后事如何,且听下回分解!


下一篇链接:用Python解数独[3]:求总值域