找到9个3x3“块”的数独板(Haskell)

bq3bfh9z  于 2022-11-14  发布在  其他
关注(0)|答案(4)|浏览(165)

我正在学习Haskell,我决定开始一个小的数独解算器作为一个项目。我一直使用this assignment作为指导,我最近在子问题D2上碰壁,这是创建一个函数,将生成数独块(9 3x 3网格)从数独板(9 x9网格)。
我开始写下面的代码,但我很快意识到这是一个可怕的想法。这是笨重的代码,不是惯用的Haskell(在我看来),完全违反了干原则。

type Block = [Maybe Int]
data Sudoku = Sudoku [[Maybe Int]]

blocks :: Sudoku -> [Block]
blocks (Sudoku rs) = block1 : block2 : block3 : block4 : block5 : block6 : block7 : block8 : block9 : []
  where block1 = [(rs!!0)!!0] ++ [(rs!!0)!!1] ++ [(rs!!0)!!2] ++ [(rs!!1)!!0] ++ [(rs!!1)!!1] ++ [(rs!!1)!!2]++ [(rs!!2)!!0] ++ [(rs!!2)!!1] ++ [(rs!!2)!!2]  
        block2 = ...
        block3 = ...
        ...

**我想知道如何写一个更简洁和惯用的函数来完成任务?**你会如何实现它?任何想法都是赞赏的!

我也参考了this之前的和可能相关的问题,但我不知道如何转换Python解决方案到Haskell,我甚至不应该。我也看到了this的问题,但我有不同的结构我的数独板。
我目前所有的代码都可以在here中找到。另外,如果我能澄清任何事情,请让我知道。

h6my8fg2

h6my8fg21#

首先,编写一个groupBy3函数,该函数按三个元素对列表进行分组:

groupBy3 :: [a] -> [[a]]

然后使用以下操作链:

  • map groupBy3
  • transpose
  • concat
  • groupBy3
  • map concat

写在我的手机上,所以它是未经测试的,但它应该是接近。
更新:我验证了这一点:

groupBy3 (a:b:c:ds) = [a,b,c] : groupBy3 ds
groupBy3 []         = []
groupBy3 as         = [ as ]  -- won't happen

boxes =  map concat . groupBy3 . concat . transpose . map groupBy3

grid = [ [ [i,j] | j <- ['1'..'9'] ] | i <- ['a'..'i'] ]

test1 = boxes grid
inkz8wg9

inkz8wg92#

虽然这不是这个问题的确切答案,但是使用数组比使用列表要好得多。因为需要更改元素,所以可能需要使用mutable arrays
然后,您可以将块实现为基数组的“视图”,只需对索引操作应用不同的偏移量,而无需复制它们。

6rqinv9w

6rqinv9w3#

另一种方法,虽然可能不如公认的答案那么优雅:

map concat [(map  (take 3 . drop i) . (take 3 . drop j)) grid | i <- [0, 3, 6], j <- [0, 3, 6]]

其中grid是9x9数独网格。

ig9co6j1

ig9co6j14#

下面是另一种方法:boxsize = 3用于(9 x 9)网格,对于(4 X 4)网格,可以使用boxsize = 2

boxsize :: Int
boxsize = 3

boxes :: [[a]] -> [[a]]
boxes [] = []
boxes xss = takeBox (take boxsize xss) ++ boxes (drop boxsize xss)
            where 
                takeBox ([]:_) = []
                takeBox yss = concatMap (take boxsize) yss : takeBox (map (drop boxsize) yss)

相关问题