簡體   English   中英

為數獨編寫回溯求解器時出錯

[英]Error in writing a backtracking solver for sudoku

所以最近我試圖寫一個回溯方法來解決一個數獨難題(二維列表),我遇到了一些我似乎無法弄清楚調試的錯誤。

我的代碼:

def areLegalValues(values: list):
    if len(values) in [1,4,9,16,25]:
        for value in values:
            if value <= len(values):
                if value != 0 and values.count(value)>1:
                    return False
            else:
                return False
        return True
    return False

def isLegalRow(board: list, row: list):
    compareList = [ ]

    for r in range(len(board)):

        if r == row:

            for c in range(len(board[0])):
                #print(board[r][c])
                compareList.append(board[r][c])
    return areLegalValues(compareList)

def isLegalCol(board: list, col: list):
    compareList = [ ]
    for r in range(len(board)):
        for c in range(len(board[0])):
            if c == col:
                compareList.append(board[r][c])
                #print(compareList)
    return areLegalValues(compareList)

def isLegalBlock(board: list, block: list):
    compareList = [ ]
    N = int((len(board))**(1/2))
    blockRowNumber = int(block//N)
    blockColNumber = int(block%N)
    for row in range(blockRowNumber*N, blockRowNumber*N+N):
        #print(row)
        for col in range(len(board[0])):
            if col in range(blockColNumber*N, blockColNumber*N+N):
                #print(board[row][col])
                compareList.append(board[row][col])
                # print(compareList)
    return areLegalValues(compareList)

def isLegalSudoku(board: list):
    boardLength = len(board)
    for row in range(len(board)):
        if isLegalRow(board,row) != True:
            return False
        for col in range(len(board[0])):
            if isLegalCol(board,col) != True:
                return False
    for block in range(boardLength):
        if isLegalBlock(board, block) != True:
            return False
    return True

def solveSudoku(board, row=0):
    if row == len(board):
        return board
    else:
        for col in range(len(board[row])):
            if board[row][col] == 0:
                for number in range(1, len(board)+1):
                    board[row][col] == number
                    if isLegalSudoku(board) == True:
                        solution = solveSudoku(board, row+1)
                        if solution != None:
                            return solution
                    board[row][col] == 0
        return None

測試代碼:

def testSolveSudoku():
    print('Testing solveSudoku()...', end='')
    Board = [
        [1, 0, 3, 0],
        [4, 3, 0, 1],
        [2, 0, 1, 0],
        [0, 0, 4, 2]
    ]
    Sol = [
        [1, 2, 3, 4],
        [4, 3, 2, 1],
        [2, 4, 1, 3],
        [3, 1, 4, 2]
    ]
    print(solveSudoku(Board))
    assert(solveSudoku(Board) == Sol)
    print('Passed!')

*正如名字所暗示的,isLegalValues 接受一個列表,如果該列表包含合法值,則返回,也就是說,該列表不能有非零數字的重復,0 可以工作。 isLegalRow 和 isLegalCol 遍歷數獨板並建立一個包含特定行/列值的列表並將它們插入 isLegalValues。 isLegalBlock 找到板子中的塊,並獲取一個塊號並將其插入 isLegalValues。 (通過廣泛的測試,這些似乎都有效)

我目前遇到的問題是,由於某種原因,我的代碼完成了解決難題,但設法完成了運行。 例子:

    [1, 2, 3, 0],
    [4, 3, 2, 1],
    [2, 4, 1, 0],
    [3, 0, 4, 2]

應該改為

[1, 2, 3, 4],
[4, 3, 2, 1],
[2, 4, 1, 3],
[3, 1, 4, 2]

但我一直返回上面 2 行的代碼。 (帶 0 的那個)

似乎部分代碼正在工作,因為所有被替換的值都是有效的,但回溯似乎有問題。 我想知道是否有人能指出出了什么問題,我該如何解決它?

謝謝

基本上,我犯了一個錯誤,我不斷地用這段代碼跳過同一列中的值,並且也從未嘗試解決最后一列。

解決方案:

def solveSudoku(board: list):
    """takes in a sudoku board and solves the board through use of backtracking
    and returns the dectructively changed board"""
    checkZeroes = True
    for row in range(len(board)):
        for col in range(len(board[0])):
            if board[row][col] == 0:
                checkZeroes = False
    
    if checkZeroes == True:
        return board
    else:
        for row in range(len(board)):
            for col in range(len(board[0])):
                if board[row][col] == 0:
                    for number in range(1,len(board)+1):
                        board[row][col] = number
                        if isLegalSudoku(board) == True:
                            solution = solveSudoku(board)
                            if solution != None:
                                return solution
                        board[row][col] = 0
                    return None

這完成了任務,雖然有點慢,首先檢查整個電路板是否有 0(基本情況),然后循環遍歷電路板中的所有值,如果值為 0,則測試所有可能的值(合法)數字。 然后它檢查整個董事會是否合法,然后繼續。 如果有錯誤,它會回溯。 如果沒有解決方案,則返回 None。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM