简体   繁体   English

递归 function 未按预期返回

[英]Recursive function does not return where expected

This is a sudoku solver, in the second function when I try to return the solved board it appears as none, but if you print the board you can see the solution.这是一个数独求解器,在第二个 function 中,当我尝试退回已解决的板时,它显示为无,但如果您打印板,您可以看到解决方案。 here is the code:这是代码:

board = [[5,3,0,0,7,0,0,0,0],
          [6,0,0,1,9,5,0,0,0],
          [0,9,8,0,0,0,0,6,0],
          [8,0,0,0,6,0,0,0,3],
          [4,0,0,8,0,3,0,0,1],
          [7,0,0,0,2,0,0,0,6],
          [0,6,0,0,0,0,2,8,0],
          [0,0,0,4,1,9,0,0,5],
          [0,0,0,0,8,0,0,7,9]]

def solution(row, col, number):
    for i in range(9):
        if board[row][i] == number:
            return False
        if board[i][col] == number:
            return False
        row0 = (row // 3) *3
        col0 = (col // 3) * 3
        for i in range(3):
            for j in range(3):
                if board[row0+i][col0+j] == number:
                    return False
    return True

def solve():
    global board
    for row in range(9):
        for col in range(9):
            if board[row][col] == 0:
                for number in range(1,10):
                    if solution(row, col, number):
                        board[row][col] = number
                        solve()
                        board[row][col] = 0
                return
    [print(x) for x in board] 
    return board


print(solve())

How can I make the solve function return the new board?如何解决 function 退回新板?

The issue with your code is that you have two exiting points, one that returns the board :您的代码的问题是您有两个退出点,一个返回board

return board

and one that returns nothing (ie None )和一个什么都不返回的(即None

return

If you follow how the recursion calls are invoked, you realize that the parent call is actually returning from the None exit point.如果您遵循递归调用的调用方式,您会意识到父调用实际上是从None退出点返回的。 However, just passing board to that exit point does not fix the issue as you have recursive calls to solve() which are followed by setting back to 0 specific cells.但是,仅将board传递到该出口点并不能解决问题,因为您有对solve()的递归调用,然后将其设置回0个特定单元格。 So essentially, you first solve the sudoku and then unwind the whole solution back to where you started.所以本质上,你首先解决数独问题,然后将整个解决方案展开回到你开始的地方。 To solve this you need to keep track of when you actually solve the sudoku and skip the setting back to 0 if the sudoku is solved.要解决此问题,您需要跟踪实际解决数独的时间,如果数独已解决,则将设置跳过回 0。

One way of doing this (slightly rewritten to avoid the perilous use of global ) is:这样做的一种方法(稍微重写以避免危险地使用global )是:

board = [[5,3,0,0,7,0,0,0,0],
          [6,0,0,1,9,5,0,0,0],
          [0,9,8,0,0,0,0,6,0],
          [8,0,0,0,6,0,0,0,3],
          [4,0,0,8,0,3,0,0,1],
          [7,0,0,0,2,0,0,0,6],
          [0,6,0,0,0,0,2,8,0],
          [0,0,0,4,1,9,0,0,5],
          [0,0,0,0,8,0,0,7,9]]


def solution(board, row, col, number):
    for i in range(9):
        if board[row][i] == number:
            return False
        if board[i][col] == number:
            return False
    row0 = (row // 3) *3
    col0 = (col // 3) * 3
    for i in range(3):
        for j in range(3):
            if board[row0+i][col0+j] == number:
                return False
    return True


def solve(board):
    for row in range(9):
        for col in range(9):
            if board[row][col] == 0:
                is_solved = False
                for number in range(1, 10):
                    if solution(board, row, col, number):
                        board[row][col] = number
                        is_solved = solve(board)
                        if not is_solved:
                            board[row][col] = 0
                return is_solved
    return True


def print_board(board):
    for row in board:
        print(row)
    print()

print_board(board)
# [5, 3, 0, 0, 7, 0, 0, 0, 0]
# [6, 0, 0, 1, 9, 5, 0, 0, 0]
# [0, 9, 8, 0, 0, 0, 0, 6, 0]
# [8, 0, 0, 0, 6, 0, 0, 0, 3]
# [4, 0, 0, 8, 0, 3, 0, 0, 1]
# [7, 0, 0, 0, 2, 0, 0, 0, 6]
# [0, 6, 0, 0, 0, 0, 2, 8, 0]
# [0, 0, 0, 4, 1, 9, 0, 0, 5]
# [0, 0, 0, 0, 8, 0, 0, 7, 9]
solve(board)
print_board(board)
# [5, 3, 4, 6, 7, 8, 9, 1, 2]
# [6, 7, 2, 1, 9, 5, 3, 4, 8]
# [1, 9, 8, 3, 4, 2, 5, 6, 7]
# [8, 5, 9, 7, 6, 1, 4, 2, 3]
# [4, 2, 6, 8, 5, 3, 7, 9, 1]
# [7, 1, 3, 9, 2, 4, 8, 5, 6]
# [9, 6, 1, 5, 3, 7, 2, 8, 4]
# [2, 8, 7, 4, 1, 9, 6, 3, 5]
# [3, 4, 5, 2, 8, 6, 1, 7, 9]

Where essentially the solve() function is changed so that:本质上, solve() function 发生了变化,因此:

  • it accepts a board parameter which is modified in-place它接受就地修改的board参数
  • it returns if the board was solved or not如果board已解决,它会返回
  • if the board is already solved it does not unwind the solution如果董事会已经解决,它不会解除解决方案
  • (a print_board() helper function is included for simpler visualization) (包含一个print_board()助手 function 以简化可视化)

(also the solution() has been changed to include a board parameter, to avoid relying on the global board definition, and the final block is outside of the main loop because it is looped there pointlessly). solution()也已更改为包含一个board参数,以避免依赖全局board定义,并且最后一个块在主循环之外,因为它在那里毫无意义地循环)。

The function does not need to return board because it gets modified in-place. function 不需要退回board ,因为它已就地修改。

If one really needs the board to be returned, one can simply include it in the return.如果真的需要退回电路板,可以简单地将其包含在退货中。


Note that if you just replace the lone return inside the loops with a break , this does not seem to work.请注意,如果您只是用break替换循环内的唯一return ,这似乎不起作用。 If it does work, it will take a huge amount of time.如果它确实有效,它将花费大量时间。 I suspect this will eventually lead to infinite looping because you just find some partial solution and unroll it back and forth forever (this assumption is based on replacing the return in my code with a break which yields a partial solution).我怀疑这最终会导致无限循环,因为您只需找到一些部分解决方案并永远来回展开它(这个假设是基于用产生部分解决方案的break替换我的代码中的return )。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM