优化数独求解方法

时间:2017-05-25 05:28:19

标签: haskell sudoku

为一个作业制作一个数独求解器,我在解决数独的空白单元格时遇到了问题。我可以轻松地使用独特的解决方案来解决单元格,但是当我遇到具有多个解决方案的单元格时(在数独的当前状态下),我想继续下一个空白以尝试尽可能多地填充数据,然后再尝试“相应的价值观和分支我的解决方案。

我的问题是我不知道如何跟踪我所处的空白值。

blank :: Sudoku -> Pos
blank sudoku
  | elem '.' $ toString sudoku = ( (positInRow `div` 9), (positInRow `mod` 9) )
  | otherwise = error "no blanks"
    where
      positInRow = fromJust $ elemIndex '.' $ toString sudoku

nextBlank :: Sudoku -> Pos -> Pos
nextBlank sudoku (x, y)
  | elem '.' $ drop (x*9+y) $ toString sudoku = blank (fromString $ drop (x*9+y) $ toString sudoku)
  | otherwise = error "no blanks"

这是我尝试过的解决方案,但是如果我尝试以递归方式解决数独游戏,那么如果原始的下一个空白没有更新数独的值,它将陷入无限循环,找到相同的“nextBlank”。

有没有办法正确实现这个功能?

1 个答案:

答案 0 :(得分:1)

首先让我将你的代码包装在一些样板文件中,这样我们就可以运行了 容易的事情:

module RandomNoise where

import Data.Maybe
import Data.List

type Pos = (Int, Int)
type Sudoku = String

toString :: Sudoku -> String
toString = id

fromString :: String -> Sudoku
fromString = id

blank :: Sudoku -> Pos
blank sudoku
  | elem '.' $ toString sudoku = (positInRow `div` 9, positInRow `mod` 9)
  | otherwise = error "no blanks"
  where
    positInRow = fromJust $ elemIndex '.' $ toString sudoku

nextBlank :: Sudoku -> Pos -> Pos
nextBlank sudoku (x, y)
  | elem '.' $ drop (x*9+y) $ toString sudoku = blank (fromString $ drop (x*9+y) $ toString sudoku)
  | otherwise = error "no blanks"

testSudoku = "uiae.uiae.uiae.uiae"

firstBlank = blank testSudoku
secondBlankOrNot = nextBlank testSudoku firstBlank

如果您启动ghci并加载包含该内容的文件, 你可以看到,

firstBlank = (0,4)
secondBlank = (0,0)

drop (0*9+4) testSudoku

产量

".uiae.uiae.uiae"

所以这里有几个问题。

  1. 您没有从字符串中删除足够的字母。您也需要删除该位置指定的空白。
  2. 在nextBlank中,你需要将被删除的字符串的长度添加到空白中确定的索引,然后再将它们转换到一个位置,否则你将获得一些垃圾位置,这个位置与最后一个空白的位置有关。我建议将索引用于字符串表示,并将位置计算为单独函数的最后一步。