Search code examples
pythonrecursionbacktrackingsudoku

Sudoku Backtracking Python to find Multiple Solutions


I have a code to solve a Sudoku recursively and print out the one solution it founds. But i would like to find the number of multiple solutions. How would you modify the code that it finds all possible solutions and gives out the number of solutions? Thank you! :)

code:


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 num in range(1,10):
        if valid(bo, num, (row, col)):
            bo[row][col] = num          

            if solve(bo):                 
                return True

            bo[row][col] = 0              

    return False


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

    # Check column
    for line in range(len(bo)):
        if bo[line][pos[1]] == num and pos[0] != line:
            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
if __name__ == "__main__":
    print_board(board)
    solve(board)
    print("___________________")
    print("")
    print_board(board)


I already tried to change the return True term at the Solve(Bo) Function to return None/ deleted it(For both return Terms) that it continues… Then the Algorithm continues and finds multiple solutions, but in the end fills out the correct numbers from the very last found solutions again into 0’s. This is the solution then printed out.


Solution

  • As asked:

    How would you modify the code that it finds all possible solutions and gives out the number of solutions?

    If you don't want to return ("give out") the solutions themselves, but the number of solutions, then you need to maintain a counter, and use the count you get back from the recursive call to update the owned counter:

    def solve(bo):
        find = find_empty(bo)
        if not find:
            return 1
    
        count = 0
        row, col = find
        for num in range(1, 10):
            if valid(bo, num, (row, col)):
                bo[row][col] = num          
                count += solve(bo)
                bo[row][col] = 0              
    
        return count
    

    In the main program, you would no longer print the board, as you don't expect the filled board now, but a number:

        print(solve(board))  # Will output 1 for your example board.
    

    Getting all solutions

    If you don't just want to know the count, but every individual solution itself, then I would go for a generator function, that yields each solution:

    def solve(bo):
        find = find_empty(bo)
        if not find:
            yield [row[:] for row in bo]  # Make a copy
            return
            
        row, col = find
        for num in range(1, 10):
            if valid(bo, num, (row, col)):
                bo[row][col] = num          
                yield from solve(bo)
                bo[row][col] = 0              
    

    Then the main program can do:

        count = 0
        for solution in solve(board):
            print("SOLUTION:")
            print_board(solution)
            count += 1
        print("NUMBER of SOLUTIONS:", count)