-2

This is a program that solves a sudoku board using python and the back-tracking algorithm, but I don't seem to understand the recursion in solve(bo). Like it seems like if the condition is not met, then the index is reset to 0 and it continues to try numbers at the same position.

Can someone help explain in simpler terms perhaps, how the function back tracks and rechecks conditions?

board = [
    [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 solve(bo):
    find = find_empty(bo)
    if not find:
        return True
    else:
        row, col = find

    for i in range(1,10):
        if valid(bo, i, (row, col)):
            bo[row][col] = i

            if solve(bo):
                return True

            bo[row][col] = 0

    return False


def valid(bo, num, pos):
    # Check row
    for i in range(len(bo[0])):
        if bo[pos[0]][i] == num and pos[1] != i:
            return False

    # Check column
    for i in range(len(bo)):
        if bo[i][pos[1]] == num and pos[0] != i:
            return False

    # Check box
    box_x = pos[1] // 3
    box_y = pos[0] // 3

    for i in range(box_y*3, box_y*3 + 3):
        for j in range(box_x * 3, box_x*3 + 3):
            if bo[i][j] == num and (i,j) != pos:
                return False

    return True


def print_board(bo):
    for i in range(len(bo)):
        if i % 3 == 0 and i != 0:
            print("- - - - - - - - - - - - - ")

        for j in range(len(bo[0])):
            if j % 3 == 0 and j != 0:
                print(" | ", end="")

            if j == 8:
                print(bo[i][j])
            else:
                print(str(bo[i][j]) + " ", end="")


def find_empty(bo):
    for i in range(len(bo)):
        for j in range(len(bo[0])):
            if bo[i][j] == 0:
                return (i, j)  # row, col

    return None

print_board(board)
solve(board)
print("___________________")
print_board(board)
CodingBoy
  • 39
  • 1
  • 9

1 Answers1

0

Right! So the way this solution operates is it finds the next empty field on the board, attempts to insert number from range 1..9 there and then check the validity. The validity check is a tentative answer to whether a given number is correct, i.e. whether it does not produce a violation of the rules. If so, the number gets inserted into the array and solve is called recursively. Now, here the implicit backtracking is taking place. If this recursive call to solve fails to produce a fully consistent solution to the puzzle, then the whole "branch" starting with our tentative guess gets removed from the call stack, the failed guess is reset on the board (removed), and we continue to the next guess.

Wojciech Gac
  • 1,538
  • 1
  • 16
  • 30
  • so basically the whole branch of solutions is part of this "tentative guess"? – CodingBoy Feb 16 '20 at 23:40
  • Also I still don't understand how it goes on to use other possible solutions. The reset to 0 seems like the whole solve() method is used from a fresh start. Also, how does the program know if a solution was tested already. – CodingBoy Feb 16 '20 at 23:44
  • First of all, the reset to zero does not mean a fresh start. Remember that we are still in the context of a certain recursive call to `solve`, so we backtrack from an incorrect guess and go on with the next one. As for tracking progress, the program doesn't "know" the history of tested guesses, rather the hierarchy of recursive calls is organized so that they span the entire combinatorial space. The program's traversing that space progressively nears us to the correct answer. – Wojciech Gac Feb 17 '20 at 01:24
  • Could an analogy to this algorithm be: in chess, where one player thinks several steps ahead, then if that sequence ends up failing, he/she reverts back to his current state and continues with other possible moves – CodingBoy Feb 17 '20 at 01:32
  • Well... That's an imprecise analogy, since in sudoku it's easy to spot an inconsistency once you arrive at it, while in chess you might be ready for some apparent local disadvantage in order to carry out your long-term goals. But in some sense it is similar. – Wojciech Gac Feb 17 '20 at 10:50