在haskell中回溯数独

时间:2016-03-02 14:33:27

标签: haskell recursion sudoku backtracking

我试图在Haskell中构建一个回溯数据求解器。但我还是坚持了最后一点。我创建了一个名为nextBoards的函数,它返回所有可能的soduko板,其中下一个空位用可能的值填充。现在我试图在Haskell中使用回溯,但我不能使用像while循环这样的东西,现在我真的很困惑如何做到这一点。我之前在Java中做过一个数独求解器,但我现在完全不知道如何在Haskell中做到这一点。

-- Generate the next boards for a given board
nextBoards :: Board -> [Board]
nextBoards b = 
    let position = findFirstEmpty b
    in [update z (snd position) (fst position) b | z <- options b (snd position) (fst position)]

-- We found the real solution
solve :: Board -> [Board] -> Board
solve focus options
    | not (notEmpty focus) = focus
-- We hit a dead path try the next option
solve focus options
    | solve (head options) (tail options)
-- We are solving the focus, generate the next boards
-- and save the rest in the options
solve focus options
    | solve (head (nextBoards focus)) (tail (nextBoards focus))

我真的不知道如何继续。

1 个答案:

答案 0 :(得分:0)

您可以在(部分)解决方案空间(例如所有可能的Board s)S上实现回溯解决方案,其类型签名如下:

backtrack :: S -> [S]

S当前状态,[S]所有有效电路板列表。现在通常有三种可能的选择:

  • 我们找到了一个solved的状态,我们返回一个包含我们解决方案的列表( singleton ):

    backtrack s | solved s = [s]
    
  • 我们找到了一条死路,在这种情况下我们不再付出努力,并返回一个空列表:

                | invalid s = []
    
  • 或者我们可能需要进一步部署我们的解决方案,我们生成children:从s前进一步的状态,并递归调用回溯,我们返回{{1这些孩子的所有concat

    backtrack

或者把它们放在一起:

            | otherwise = concatMap backtrack $ children s

只需为backtrack :: S -> [S] backtrack s | solved s = [s] | invalid s = [] | otherwise = concatMap backtrack $ children s 状态生成invalid的空列表(正如您的解决方案可能做的那样),或者通过阻止生成无效{{1},可以省略children保护}}第

现在为您的问题奠定基础,生成invalid将归结为您的Board功能:

children

或稍微美化你的功能:

nextBoards

现在,solve(或children = nextBoards )方法定义为:

children :: Board -> [Board]
children s = [update s y x v | v <- options s y x]
    where (x,y) = findFirstEmpty s

backtrack将生成一个所有有效解决的Sudoku主板的列表(最初填充的地方,仍然填写)。该列表是懒惰生成的,因此如果您想要一个有效的解决方案,则只需使用backtrack :: Board -> [Board] backtrack s | not (notEmpty s) = [s] | otherwise = concatMap backtrack $ children s

backtrack