python 中的数独求解器未打印板

Sudoku Solver in python not printing board

我一直在开发 python 程序来解决数独难题,但我不确定我做错了什么。我以为我已经修好了,但现在我无法让它打印电路板或解决它。我已经编写了要解决的算法以及创建电路板的功能。如果有人能告诉我哪里出了问题,我将不胜感激。这是我的代码(抱歉缩进错误 - 它们是由复制和粘贴引起的):

    class Sudoku:
def __init__(self, board, cells):
    self.board = board
    self.cells = cells

#Creates a board
def newboard(self):
    values = self.cells.split(" ")
    val_counter = 0

    if len(values) != 81:
        print("Error: Not enough values.")
        exit()

    else:
        for i in range(9):
            for j in range(9):
                self.board[i][j] = values[val_counter]
                val_counter += 1

# Returns row
def findValidRow(self):
    for i in range(9):
        for j in range(9):
            if int(self.board[i][j]) == 0:
                return int(i)
    return -1

# Returns col
def findValidCol(self):
    for i in range(9):
        for j in range(9):
            if int(self.board[i][j]) == 0:
                return int(j)
    return -1

def possible(self, row, col, val):
    # Check row for value
    for i in range(9):
        if self.board[row][i] == val:
            return False
    # Checks col for value
    for j in range(9):
        if self.board[j][col]:
            return False
    # Checks square for value
    coordX, coordY = 3 * (row // 3), 3 * (col // 3)
    for x in range(coordX, coordX + 3):
        for y in range(coordY, coordY + 3):
            if coordX == row and coordY == col:
                continue
            if self.board[coordX][coordY] == val:
                return False
    return True

    # Solves the board

def solve(self):
    # Checks if cells are all solved
    if self.findValidCol() == -1:
        print(self.board)
        return True

    # Finds first cell to fill
    row = self.findValidRow()
    col = self.findValidCol()

    for i in range(1, 10):
        if self.possible(row, col, i):
            self.board[row][col] = i
            # Updates values to find new cell to fill

            if self.solve():
                return True
            # Backtracks
            self.board[row][col] = 0

    return False


    # Get cell values and calls solve function
    get_cells = input("Enter cell values seperated by 1 space. Enter 0 for empty cells: ")
    b = Sudoku([[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0,    0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0, 0, 0, 0]], get_cells)
    b.newboard()
    b.solve()

你的第一个问题在这里:

# Check row for value
for i in range(9):
    if self.board[row][i] == val:
        return False
# Checks col for value
for j in range(9):
    if self.board[j][col]:
        return False

具体来说,行:

if self.board[j][col]:

应该是:

if self.board[j][col] == val:

下一个问题在这里:

coordX, coordY = 3 * (row // 3), 3 * (col // 3)
for x in range(coordX, coordX + 3):
    for y in range(coordY, coordY + 3):
        if coordX == row and coordY == col:
            continue
        if self.board[coordX][coordY] == val:
            return False

当我认为您应该使用 xy 时,您在循环中使用 coordXcoordY 的地方:

for x in range(coordX, coordX + 3):
    for y in range(coordY, coordY + 3):
        if x == row and y == col:
            continue
        if self.board[x][y] == val:
            return False

否则,您将一遍又一遍地重复相同的测试。我在打印电路板时看到的最后一个问题是,您的电路板内容是 intstr 的混合体——您需要尽早掌握这一点并且只使用其中一个。

下面是我对你的代码的修改,它解决了我手头的测试数独问题:

class Sudoku:
    def __init__(self, board, cells):
        self.board = board
        self.cells = cells

    def newBoard(self):
        ''' Creates a board '''

        values = self.cells.split(" ")

        assert len(values) == 81, "Error: Not enough values."

        for i in range(9):
            for j in range(9):
                self.board[i][j] = int(values.pop(0))

    def findValidCell(self):
        ''' Returns empty cell indicies or None '''

        for row in range(9):
            for col in range(9):
                if self.board[row][col] == 0:
                    return (row, col)
        return None

    def possible(self, row, col, val):
        # Check row for value
        for i in range(9):
            if self.board[row][i] == val:
                return False

        # Checks col for value
        for j in range(9):
            if self.board[j][col] == val:
                return False

        # Checks square for value
        coordX, coordY = 3 * (row // 3), 3 * (col // 3)

        for x in range(coordX, coordX + 3):
            for y in range(coordY, coordY + 3):
                if x == row and y == col:
                    continue

                if self.board[x][y] == val:
                    return False

        return True

    def printBoard(self):
        print(*self.board, sep='\n')

    def solve(self):
        ''' Solves the board '''

        # Checks if cells are all solved
        cell = self.findValidCell()

        if cell is None:
            return True

        # Finds first cell to fill
        row, col = cell

        for i in range(1, 10):
            if self.possible(row, col, i):
                self.board[row][col] = i
                # Updates values to find new cell to fill

                if self.solve():
                    return True

                # Backtracks
                self.board[row][col] = 0

        return False

# Get cell values and calls solve function
get_cells = input("Enter cell values separated by 1 space. Enter 0 for empty cells: ")
b = Sudoku([
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0],
    ], get_cells)

b.newBoard()
if b.solve():
    b.printBoard()

@cdlane 给出的答案很有效。我刚刚注意到我将使用一些优化来提高 possible 函数的边际性能,结果是:

def possible(self, row, col, val):
    # Check row or column for value
    for i in range(9):
        if (self.board[row][i] == val) or (self.board[i][col] == val):
            return False

    # Checks 3x3 containing square for value
    coordX, coordY = 3 * (row // 3), 3 * (col // 3)

    for x in range(coordX, coordX + 3):
        for y in range(coordY, coordY + 3):
            if self.board[x][y] == val:
                return False
    return True

你可以看到我在同一个 for 循环中检查了行和列,我消除了一个 不必要的单元格位置检查,因为候选单元格在该点包含零。

并且因为我希望在错误消息中包含更多信息,所以我将断言修改为:

    assert len(values) == 81, "Error: {} values {} != {}".format(("Not enough"if len(values)<81 else "Too many"),len(values),81)