用Python编写Sudoku Solver

时间:2009-11-23 08:31:35

标签: python sudoku

这是我用蟒蛇语编写的数独求解器,当我运行这个程序时,似乎在更新函数和求解函数中存在问题。

无论我多久看一遍并移动代码,我似乎都没有运气

任何人都可以帮助我吗?


import copy


def display (A):

    if A:
        for i in range (9):
            for j in range (9):
                if type (A[i][j]) == type ([]): print A[i][j][0],
                else: print A[i][j]
            print
        print
    else: print A

def has_conflict(A):

    for i in range(9):
        for j in range(9):
            for (x,y) in get_neighbors(i,j):
                if len(A[i][j])==1 and A[i][j]==A[x][y]: return True
    return False


def get_neighbors(x,y):

    neighbors = []
    for i in range(3):
        for j in range(3):
            a = 3*(x / 3)+i
            b = 3*(y / 3)+j
            if (x,y) != (a,b):
                neighbors += [(a,b)]

    for i in range(9):
        if (x,y) != (x,i) and (x,i) not in neighbors:
            neighbors += [(x,i)]
        if (x,y) != (i,y) and (i,y) not in neighbors:
            neighbors += [(i,y)]

    return neighbors



def update(A,x,y,value):

    B = copy.deepcopy(A)
    B[x][y] = [value]
    for (i,j) in get_neighbors(x,y):
        if B[i][j] == B[x][y]:
            if len(B[i][j]) > 1: B[i][j].remove(value)
            else: return [] 
    if has_conflict(B) == True: return []
    else: return B


def solve(A):

    for x in range (9):
        for y in range(9):
            if len(A[x][y]) == 1: return A[x][y]
            if len(A[x][y]) > 1:
                lst = update(A,x,y,A[x][y])
                if len(lst[x][y]) > 1: solve(lst)
                if lst == []: return []
                if len(lst[x][y]) == 1: return lst
            else: return A[x][y]    



A=[]

infile = open('puzzle1.txt','r')

for i in range(9):

        A += [[]]
        for j in range(9):
            num = int(infile.read(2))
            if num: A[i] += [[num]]
            else: A[i] += [[1,2,3,4,5,6,7,8,9]]

for i in range(9):

        for j in range(9):
            if len(A[i][j])==1: A = update(A, i, j, A[i][j][0])
            if A == []: break
        if A==[]: break

if A<>[]: A = solve(A)

display(A)

以下是一些难题:

拼图1

0 0 0 2 6 0 7 0 1
6 8 0 0 7 0 0 9 0
1 9 0 0 0 4 5 0 0
8 2 0 1 0 0 0 4 0
0 0 4 6 0 2 9 0 0
0 5 0 0 0 3 0 2 8
0 0 9 3 0 0 0 7 4
0 4 0 0 5 0 0 3 6
7 0 3 0 1 8 0 0 0

益智2

1 0 0 4 8 9 0 0 6
7 3 0 0 0 0 0 4 0
0 0 0 0 0 1 2 9 5
0 0 7 1 2 0 6 0 0
5 0 0 7 0 3 0 0 8
0 0 6 0 9 5 7 0 0
9 1 4 6 0 0 0 0 0
0 2 0 0 0 0 0 3 7
8 0 0 5 1 2 0 0 4

拼图3

0 2 0 6 0 8 0 0 0
5 8 0 0 0 9 7 0 0
0 0 0 0 4 0 0 0 0
3 7 0 0 0 0 5 0 0
6 0 0 0 0 0 0 0 4
0 0 8 0 0 0 0 1 3
0 0 0 0 2 0 0 0 0
0 0 9 8 0 0 0 3 6
0 0 0 3 0 6 0 9 0

4 个答案:

答案 0 :(得分:3)

如果要稳定代码,请为每个函数编写小测试用例,以确保它们正常工作。

在您的情况下,运行拼图,并确定哪个字段是错误的。然后猜测哪个函数可能产生错误的输出。用输入调用它来查看它的真正作用。对你发现的每个bug重复一遍。

[编辑] module unittest是你的朋友。

答案 1 :(得分:3)

我会避免像“移动代码”这样的事情。这称为"Programming by Coincidence"(请参阅The Pragmatic Programmer)。像这样的编程不会让你成为更好的程序员。

相反,你应该拿出纸和笔,然后开始思考应该的工作方式。然后,阅读代码并仔细写下实际的内容。只有在您理解后,才能返回计算机终端。

答案 2 :(得分:2)

我想以一种你可以编写实际代码的方式来帮助你,所以这里有一些解释和一些伪代码。

那些不模仿人类演绎逻辑的数独求解器是以暴力为基础的。基本上,您需要一个回溯算法。你有has_conflict方法,它首先检查候选人是否正常。然后你写这样的回溯算法:

Solve(s):
    Pick a candidate.
    Does it have a conflict? If yes, go back, and pick another one.
    No more empty cells? Then cool, return True.
    Have you run out of candidates? Then it cant be solved, return False.

    At this point, it seems ok. So call Solve(s) again, lets see how it works 
    out with the new candidate.
    If Solve returned false, then after all it was a bad candidate. Go
    back to picking another one.
    If Solve returned True, then you solved the sudoku!

这里的主要想法是,如果你的猜测是错误的,尽管最初看起来没有冲突,那么冲突会在调用树的更深处显示出来。

原始的sudokus只有一个解决方案。你可以通过尝试任何候选人尽管Solve的返回值来扩展这个方法到sudokus的不同解决方案(但是这种方法会非常慢)。

有一个很好的技巧可以找出数独有多个解决方案。首先在每次解决调用时按自然顺序尝试候选人。然后向后试试。然后再次执行这两个步骤,但这次从数独的最后一个单元格中运行算法,向后退步。如果这四种解决方案相同,那么它只有一种解决方案。不幸的是,我没有正式的证据,但它似乎一直都在工作。我试图证明这一点,但我对图表并不是那么好。

答案 3 :(得分:0)

解决数独需要一些强制方法,我不会在你的代码中看到它们。

我之前也尝试过,但最后我看到了norvig's codes,它的工作正常。

最终最终学会了他的代码。