簡體   English   中英

Sudoko 求解器回溯算法不起作用

[英]Sudoko Solver Backtracking Algorithm Not Working

我對編程還很陌生,我最近開始研究 sudoko 求解器,除了求解算法本身之外,一切都很好,我從互聯網上獲得了一些幫助,但是因為我自己編寫了這些方法,所以我找不到我的代碼的准確解決方案,任何幫助將不勝感激!

問題:代碼一直運行,直到它無法將值輸入到空 (0) 索引之一中,而不是回溯,它只是停止。

如果您能讓我知道我做錯了什么,或者建議完全改進代碼的可能方法,那么任何事情都會有很大幫助!

我的代碼在這里:

    import time
    start_time = time.time()

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


    def printBoard():
        print("Suduko Board")
        for row in grid:
            for elem in row:
                print(elem, end=' ')
            print()

    def checkInRow(grid,row, num):
        for i in range(0,9):
            if(grid[row][i] == num):
                return True
        return False

    def checkInCol(grid,col, num):
        for i in range(0,9):
            if(grid[i][col] == num):
                return True
        return False

    def checkInBox(grid, row, col, num):
        #This will give the starting point for the box
        boxX = (row // 3) * 3
        boxY = (col // 3) * 3   
        for i in range(3):
            for j in range(3):
                if((grid[boxY + j][boxX + i]) == num):
                    return True
        return False

    def findNextEmpty(grid, num):
        for row in range(9):
            for col in range(9):
                if(grid[row][col] == num):
                    return row, col
        return None


    def checkSafe(grid, row, col, num): #Returns true if safe returns false if unsafe
        return not checkInRow(grid,row,num) and not checkInCol(grid,col,num) and not checkInBox(grid,row,col,num)


    #PROBLEM IS HERE \/ 

    def solveSudoko(grid, i,j):
        if not findNextEmpty(grid,0):
            return True
        else:
            i = findNextEmpty(grid,0)[0] # Finds Row #
            j = findNextEmpty(grid,0)[1] # Finds Col #
            print(i, j)
            for value in range(1,10):
                if checkSafe(grid,i,j,value) == True:
                    grid[i][j] = value

                    printBoard()
                    print("--- %s seconds ---" % (time.time() - start_time))

                    if(solveSudoko(grid,i,j)):
                        return True

                    grid[i][j] = 0

            return False



    #print(str(value) + " can go in grid[" + str(i) + "]" + "[" + str(j) + "]")


    printBoard()

    solveSudoko(grid,0,0)

問題說明

我相信問題在於您的網格是一個列表,即可變的。 這意味着如果您調用solveSudoko(grid,i,j)它不會制作網格的副本,但您的內存中只有一個網格。 因此,在solveSudoko遇到問題后,由於您更改了原始網格,因此無法回滾。 可能的解決方案是使用非可變數據類型,如元組或有點難看,但也可能是制作網格的副本。

例子:

grid = [1,2,3]
def test(grid):
    grid[0] = 0
test(grid)
print(grid)
---> [0,2,3]

快速但丑陋的解決方案

您可能可以在代碼開頭添加import copy並替換

                    if(solveSudoko(grid,i,j)):

經過

                    if(solveSudoko(copy.deepcopy(grid),i,j)):

例子:

grid = [1,2,3]
def test(grid):
    grid[0] = 0
test(copy.deepcopy(grid))
print(grid)
---> [1,2,3]

請注意,在示例中使用copy.copy而不是copy.deepcopy也可以使用,因為整數是不可變的,但是在您的代碼中使用列表列表時,您需要copy.deepcopy

好的解決方案

例子:

grid = (1,2,3)
def test(grid):
    grid = (0,2,3)
test(grid)
print(grid)
---> (1,2,3)

元組的問題是獲得一個新網格並不好玩。 我可能會使用一個小類來為我管理網格:

class Grid:
    def __init__(self, grid):
        assert type(grid) == tuple
        self.grid = grid

    @staticmethod
    def gird_from_list(list_):
        return Grid(tuple(list_[i][j] for i in range(len(list_)) for j in range(len(list_[0]))))

    def __repr__(self):
        return "\n".join(str(self.grid[i*9:(i+1)*9]) for i in range(9))

    def set(self, i, j, value):
        return Grid(tuple(value if i+j*9==k else x for k,x in enumerate(self.grid)))

tuple_grid = Grid.gird_from_list(gird)
tuple_grid2 = tuple_grid.set(8,8,0)

這里grid_from_list只是將您的列表轉換為我的格式,而__repr__為您提供了一個很好的表示為 2d 網格,即使我實際上只保留了一個 1d 元組。 如果您不知道__repr__總是在您打印類的實例時被調用。

現在打印 tuple_grid 會產生

(7, 8, 0, 4, 0, 0, 1, 2, 0)
(6, 0, 0, 0, 7, 5, 0, 0, 9)
(0, 0, 0, 6, 0, 1, 0, 7, 8)
(0, 0, 7, 0, 4, 0, 2, 6, 0)
(0, 0, 1, 0, 5, 0, 9, 3, 0)
(9, 0, 4, 0, 6, 0, 0, 0, 5)
(0, 7, 0, 3, 0, 0, 0, 1, 2)
(1, 2, 0, 0, 0, 7, 4, 0, 0)
(0, 4, 9, 2, 0, 6, 0, 0, 7)

打印 tuple_grid2 會產生

(7, 8, 0, 4, 0, 0, 1, 2, 0)
(6, 0, 0, 0, 7, 5, 0, 0, 9)
(0, 0, 0, 6, 0, 1, 0, 7, 8)
(0, 0, 7, 0, 4, 0, 2, 6, 0)
(0, 0, 1, 0, 5, 0, 9, 3, 0)
(9, 0, 4, 0, 6, 0, 0, 0, 5)
(0, 7, 0, 3, 0, 0, 0, 1, 2)
(1, 2, 0, 0, 0, 7, 4, 0, 0)
(0, 4, 9, 2, 0, 6, 0, 0, 0)

所以當你調用 set 時網格不會改變,而是給你一個全新的帶有新值的網格。

暫無
暫無

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

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