Search code examples
iosswiftrecursionbacktrackingsudoku

Swift doesn't return the correct value in recursive function


I tried to implement backtracking solution for a sudoku solver in swift. This is my code:

func solve(board: [[Int]]) -> (isSolved: Bool, board: [[Int]]){
    var board = board
    var empty_pos: (Int, Int)
    var check_empty = findEmpty(board: board)

    if check_empty.isEmpty == false{
        return (true, board)
    }else{
        empty_pos = check_empty.pos

        for num in 1..<10{
            if isValid(board: board, num: num, pos: empty_pos){

                board[empty_pos.0][empty_pos.1] = num

                if solve(board: board).isSolved{
                    return (true, board)
                }else{
                    board[empty_pos.0][empty_pos.1] = 0
                }
            }
        }
    }
    return (false, board)}

When I run the code, the function returns true with the original board. However, when I print the board in the if solved block, I noticed that function solves the board, but it doesn't return it, and continues to call the function until it makes all of the 0 values 0 again. I think the function doesn't quit in the if solve(board: board).isSolved part. What should I do to solve this? Thank you!


Solution

  • The issue is that you are not returning the modified return value from solve, but just discarding it and returning the local variable board.

    You should be saving the return value from the recursive call and if its isSolved property is true, return the board from the recursive call, not the local var.

    func solve(board: [[Int]]) -> (isSolved: Bool, board: [[Int]]) {
        var board = board
        var emptyPos: (Int, Int)
        var checkEmpty = findEmpty(board: board)
    
        if !checkEmpty.isEmpty {
            return (true, board)
        } else {
            emptyPos = checkEmpty.pos
    
            for num in 1..<10 {
                if isValid(board: board, num: num, pos: emptyPos){
    
                    board[emptyPos.0][emptyPos.1] = num
    
                    let solved = solve(board: board)
                    if solved.isSolved {
                        return (true, solved.board)
                    } else{
                        board[emptyPos.0][emptyPos.1] = 0
                    }
                }
            }
        }
        return (false, board)
    }
    

    Unrelated to your question, but you should be conforming to the Swift naming convention, which is lowerCamelCase for variable and function names.