Python Recursive Sudoku решатель не возвращает решение

#python #numpy #sudoku

#python #numpy #судоку

Вопрос:

Я попытался оптимизировать этот код, и мой окончательный код был таким, как показано ниже

 import numpy as np
sudoku = np.array([[0, 9, 0, 0, 5, 0, 6, 0, 8],
                   [0, 0, 0, 7, 1, 0, 3, 5, 0],
                   [2, 1, 0, 0, 0, 0, 7, 0, 4],
                   [0, 0, 1, 5, 0, 0, 0, 0, 6],
                   [6, 3, 0, 2, 0, 8, 0, 4, 5],
                   [7, 0, 0, 0, 0, 4, 9, 0, 0],
                   [9, 0, 3, 0, 0, 0, 0, 2, 1],
                   [0, 4, 8, 0, 2, 7, 0, 0, 0],
                   [5, 0, 6, 0, 8, 0, 0, 3, 0]])

#Checking if the number (n) can be placed there (row, col)
def check(sudoku, row, col, n):
    # Row check
    if np.sum(sudoku[row,:] == n) != 0: return False;
    # Col check
    if np.sum(sudoku[:,col] == n) != 0: return False;
    # Sqr check
    row0, col0 = (row//3)*3, (col//3)*3
    if np.sum(sudoku[row0:row0 3,col0:col0 3] == n) != 0: return False;
    return True

def solve_sudoku(sudoku):
    rows, cols = np.where(sudoku == 0)
    for row in rows:
        for col in cols:
            for num in range(1, 10):
                if check(sudoku, row, col, num):
                    sudoku[row, col] = num
                    solve_sudoku(sudoku)
                    sudoku[row, col] = 0
            return
    print(sudoku)
    return sudoku

solved = solve_sudoku(sudoku)
  

Моя проблема в том, что, несмотря на то, что решение успешно напечатано, как показано ниже, переменная solved является просто нетипичной и ничего не хранит.

 [[3 9 7 4 5 2 6 1 8]
 [8 6 4 7 1 9 3 5 2]
 [2 1 5 8 3 6 7 9 4]
 [4 8 1 5 9 3 2 7 6]
 [6 3 9 2 7 8 1 4 5]
 [7 5 2 1 6 4 9 8 3]
 [9 7 3 6 4 5 8 2 1]
 [1 4 8 3 2 7 5 6 9]
 [5 2 6 9 8 1 4 3 7]]
  

TL; DR Функция выводит решение, но ничего не возвращает. Что я должен сделать, чтобы сохранить распечатанное решение?

Комментарии:

1. Вам нужно использовать результат вашего рекурсивного вызова solve_sudoku и проверить, завершена ли игра на этом этапе.

Ответ №1:

Рассмотрим этот код:

 if check(sudoku, row, col, num):
    sudoku[row, col] = num
    solve_sudoku(sudoku)
    sudoku[row, col] = 0  # undo this move
  

Если судоку разрешимо, solve_sudoku(sudoku) вызов в конечном итоге найдет решение. Когда вы получите свое решение, вам следует немедленно прекратить отслеживание с помощью return . В противном случае следующая строка sudoku[row, col] = 0 отменит найденное вами решение, и дальнейшие итерации продолжат попытки следующих возможных чисел. Поскольку у Sudoku есть только одно решение, проверка дополнительных чисел после нахождения решения не требуется. Вы можете просто вернуть истинное значение, чтобы завершить рекурсию.

Например, вы можете написать код, подобный этому:

 if solve_sudoku(sudoku):
    return True
  

или

 if solve_sudoku(sudoku):
    return sudoku
  

Это предотвращает sudoku[row, col] = 0 удаление решения и в конечном итоге возвращает решенную сетку исходному вызывающему после развертывания стека рекурсивных вызовов.

Ответ №2:

Проблема здесь, в вашем коде:

                     solve_sudoku(sudoku)
                    sudoku[row, col] = 0
            return
  

В первой строке вы повторяетесь, но игнорируете возвращаемое значение, которое отбрасывает любое возвращаемое значение из этого вызова и все рекурсии ниже него.

В последней строке вы возвращаете значение по умолчанию на None . Любое из этих действий нарушает непрерывность возвращаемых значений рекурсии.

Ответ №3:

print(sudoku) Вызов происходит, когда solve_sudoku вызывается с полностью заполненным массивом судоку (без каких-либо оставшихся нулей), а не в рекурсивном вызове верхнего уровня.

Каждый раз, когда solve_sudoku вызывается неполный массив судоку, вы проверяете каждое число от одного до десяти в самой верхней левой ячейке, заполненной нулем, и если число может быть помещено в ячейку, вы помещаете его туда, пытаетесь решить остальную часть сетки, а затем возвращаете ячейке значение нуля. Как только вы сделаете это для каждого числа от одного до десяти, вы вернетесь None , вот почему вы видите None возврат из solve_sudoku вызова верхнего уровня.

Ответ №4:

Через несколько часов я придумал это решение. решаемая задача сохраняет решение сейчас.

 import numpy as np
sudoku = np.array([[0, 9, 0, 0, 5, 0, 6, 0, 8],
                   [0, 0, 0, 7, 1, 0, 3, 5, 0],
                   [2, 1, 0, 0, 0, 0, 7, 0, 4],
                   [0, 0, 1, 5, 0, 0, 0, 0, 6],
                   [6, 3, 0, 2, 0, 8, 0, 4, 5],
                   [7, 0, 0, 0, 0, 4, 9, 0, 0],
                   [9, 0, 3, 0, 0, 0, 0, 2, 1],
                   [0, 4, 8, 0, 2, 7, 0, 0, 0],
                   [5, 0, 6, 0, 8, 0, 0, 3, 0]])
solved = np.zeros_like(sudoku)

def check(arg, row, col, n):
    if np.sum(arg[row,:] == n) != 0: return False;
    if np.sum(arg[:,col] == n) != 0: return False;
    row0, col0 = (row//3)*3, (col//3)*3
    if np.sum(arg[row0:row0 3,col0:col0 3] == n) != 0: return False;
    return True

def solve_sudoku(arg):
    global solved
    rows, cols = np.where(arg == 0)
    for row in rows:
        for col in cols:
            for num in range(1, 10):
                if check(arg, row, col, num):
                    arg[row, col] = num
                    solve_sudoku(arg)
                    arg[row, col] = 0
            return
    solved = arg.copy()
solve_sudoku(sudoku)
  

Я не знаю, является ли это лучшим способом оптимизации кода, отзывы приветствуются.

Комментарии:

1. Это плохая идея использовать глобальное состояние подобным образом. Он хрупкий (изменения имени переменной нарушают функцию), он не возвращается, в большой кодовой базе было бы кошмаром, если бы произошла ошибка, чтобы выяснить, какие функции, связанные с глобальным состоянием, что и когда сделали. Лучше вернуть решение в стек вызовов, чтобы все изменения состояния были полностью внутренними для функции.

Ответ №5:

 def check(grid, num, x, y):
    for i in range(9):
        if grid[i][y] == num:
            return False
    for j in range(9):
        if grid[x][j] == num:
            return False
    x0 = (x//3) * 3
    y0 = (y//3) * 3
    for i in range(3):
        for j in range(3):
            if grid[x0 i][y0 j] == num:
                return False
    return True

def solve(grid):
    for i in range(9   1):
        if i==9:
            return True
        for j in range(9):
            if grid[i][j] == 0:
                for num in range(1,10):
                    if check(grid, num, i, j):
                        grid[i][j] = num
                        if solve(grid):
                            return True
                        grid[i][j] = 0
                return False
  

Это должно сработать для вас. Он не возвращает массив, но изменяет его. Так что, если вы пройдете

 solve(sudoku_grid) 
  

а затем выведите sudoku_grid, это даст вам решаемый результат