【问题标题】:Python recursive backtracking suduko solverPython递归回溯数独求解器
【发布时间】:2013-10-23 22:23:17
【问题描述】:

我正在为 suduko 求解器编写递归回溯算法。数独子好像很糟糕。

代码:

def recursiveBacktrack(board):
  if(checkEntireBoard(board)):
    return board
  else:
    for node in board:
      if(node.val == "."):
        for val in (1,2,3,4,5,6,7,8,9):
           if(checkNodeConstraintsOk(board, node, val)):
             node.val = val
             posNewBoard = recursiveBacktrack(board)
             if(posNewBoard != None):
               return posNewBoard
             else:
              node.val = "."
         return None

boards 由节点对象组成。每个节点对象都有一个 (x,y) 代表棋盘,一个数值可以是数字,也可以是没有赋值的句点,以及一个平方值(它在哪个 suduko 方块中)。

我知道我的方法checkEntireBoardcheckNodeConstraintsOk 都有效。 checkEntireBoard 检查棋盘是否正确解决,checkNodeConstraintsOk 检查如果 suduko 游戏的约束成立,我是否要将给定节点设置为给定棋盘上的给定值。

由于某种原因,我认为我上面的算法不能正常工作(见下面的输出),我完全按照递归回溯的伪代码,没有发现错误。所以我不得不认为错误在于我对python的了解不足。

------------------------------
7  5  9  | .  4  .  | .  .  .  
6  8  .  | 5  .  .  | .  4  .  
.  3  .  | 2  .  9  | 5  .  .  
------------------------------
5  6  .  | 1  .  .  | 9  .  .  
.  .  3  | .  .  .  | 1  .  .  
.  .  1  | .  .  6  | .  3  7  
------------------------------
.  .  5  | 3  .  7  | .  9  .  
.  7  .  | .  .  8  | .  5  3  
.  .  .  | .  6  .  | 7  2  1  
------------------------------

Found Solution 
------------------------------
7  5  9  | 1  4  2  | 3  4  5  
6  8  1  | 5  3  4  | 2  4  6  
2  3  3  | 2  5  9  | 5  1  7  
------------------------------
5  6  2  | 1  1  3  | 9  5  4  
1  3  3  | 2  4  5  | 1  6  8  
4  5  1  | 6  7  6  | 1  3  7  
------------------------------
3  1  5  | 3  2  7  | 4  9  9  
5  7  4  | 3  6  8  | 7  5  3  
6  2  7  | 4  6  1  | 7  2  1  
------------------------------

如果错误没有出现在我的回溯算法中,我最终会在 codereview.stack 上打开代码审查。但据我所见,问题出在上面。

编辑

def checkEntireBoard(board):
  for node in board:
    if(node.val == "."):
      return False
    if(not checkNodeConstraintsOk(board, node, node.val)):
      return False
  return True

def checkNodeConstraintsOk(board, inNode, posVal):
  val = posVal
  for node in board:
    if(node != inNode and node.val == val):
      if(node.x == inNode.x or node.y == inNode.y or node.sqr == inNode.sqr):
        return False
  return True

EDIT2

解决了,谢谢彼得

Found Solution 
------------------------------
7  5  9  | 6  4  3  | 8  1  2  
6  8  2  | 5  7  1  | 3  4  9  
1  3  4  | 2  8  9  | 5  7  6  
------------------------------
5  6  7  | 1  3  2  | 9  8  4  
8  2  3  | 7  9  4  | 1  6  5  
9  4  1  | 8  5  6  | 2  3  7  
------------------------------
4  1  5  | 3  2  7  | 6  9  8  
2  7  6  | 9  1  8  | 4  5  3  
3  9  8  | 4  6  5  | 7  2  1  
------------------------------

【问题讨论】:

  • 您能否将您的checkEntireBoardcheckNodeConstraintsOk 函数提供给我们,以便人们调试您的代码?因为它确实看起来像checkNodeConstraintsOk 在不应该的情况下返回True;t。
  • 为了检查节点约束,我这样做了。我们只关心与我们具有相同值的节点,而不关心我们自己,因为它显然会具有相同的值。因此,如果我们找到一个具有相同值的节点,并与我们共享一个 x、y 或平方值,那么我们无法将 posVal 分配给 inNode
  • 顺便说一句,“数独很糟糕”是一个模棱两可的词。当然,它会得到错误的答案,但它可能会比正确的算法更快地得到它们,而且它不知道自己弄错了,在这种情况下,大多数人会很高兴。 :)
  • 无论如何,这仍然不足以运行和调试您的代码,而且错误似乎仍然存在于您没有向我们展示的代码中。我们真的需要SSCCE 来提供帮助。
  • 如果我的理论不是问题,那么展示board 及其已知节点是如何创建的仍然是一个好主意。

标签: python algorithm recursion


【解决方案1】:

检查初始节点值的类型。如果他们使用val = "1" 而不是val = 1 进行初始化,那么您的checkNodeConstraintsOk 函数将不会发现冲突,因为值不相等。我看到您的示例中没有一个不正确的值与您的递归回溯器添加的值冲突,只是起始值,所以我怀疑这是问题所在。

【讨论】:

  • 是的,就在钱上! /// 好主意! “我看到您的示例中没有一个不正确的值与您的递归回溯器添加的值冲突,只是起始值,所以我怀疑这是问题所在”
  • @BumSkeeter:这正是我最初想要一个 SSCCE 的原因。问题不在您的原始代码中,因此我要求提供其余代码。你给的多一点,问题还是没有,所以我要求多一点。你争辩说你不想给它。如果你一开始就给了我们解决问题的代码,你就会得到一个即时的解决方案,而不是一个幸运的猜测,结果在 25 分钟后证明是正确的,而且不会浪费很多人想要的时间帮助你。
  • 好的,好的,好的,对不起。从现在开始,我将逐字发布代码。我并没有争辩说我不想提供更多代码,您发表了一条评论,我几乎立即将其作为编辑上传。您的第一条评论是在问题发布几分钟后发布的,我在几秒钟内将额外的代码放在那里,看到问题所需的整个代码在 OP 的 5 分钟内就在那里。我也不认为答案是一个幸运的猜测。彼得有一个非常直观的想法来检查我所做的任务是否相互一致。如果运气好的话,爱因斯坦可能只是个赌徒。