在 Clojure 中,如何检查数独解决方案是否有效?

1 clojure sudoku

为了学习 Clojure 的基础知识,我正在编写一个数独解决方案检查器。我已将提供的解决方案存储在二维向量中。

(def solution [[4 2 9 8 1 3 5 6 7]  
               [5 1 6 4 7 2 9 3 8] 
               [7 8 3 6 5 9 2 4 1] 
               [6 7 2 1 3 4 8 5 9] 
               [3 9 5 2 8 6 1 7 4] 
               [8 4 1 7 9 5 6 2 3] 
               [1 5 8 3 6 7 4 9 2] 
               [9 3 4 5 2 8 7 1 6] 
               [2 6 7 9 4 1 3 8 5]])
Run Code Online (Sandbox Code Playgroud)

在 Java 中,我可以轻松地使用嵌套循环来分割水平线、垂直线和正方形,但我不确定如何在 Clojure 中实现这一点。

我的第一次尝试产生了这样的东西来获得水平线的总和:

(def horizontals [])

(for [i solution] 
  (conj horizontals (reduce + i)))
Run Code Online (Sandbox Code Playgroud)

打印出来的:

([45] [45] [45] [45] [45] [45] [45] [45] [45])
Run Code Online (Sandbox Code Playgroud)

这是检查水平线的“正确”方法吗?或者在 Clojure 中有更好的方法吗?我将如何检查垂直或正方形的总和?

ama*_*loy 5

水平线很容易。它实际上只是solutions:您想要一个数字列表的列表,而这就是您已经拥有的!

我无法想象你为什么要总结,因为这与检查数独解决方案(应该涉及检查唯一性)无关。但是,如果您这样做了,您可以将每个水平与(map #(reduce + %) solution).

垂直涉及一个巧妙的技巧:您可以使用(apply map vector m)转置嵌套向量的“矩阵”。所以只需将溶液旋转 90 度,然后检查它的水平线!当然,如果你愿意,你可以用同样的方式把它们加起来,虽然我又不明白为什么。

正方形更有趣,有几种方法可以解决。我会使用get-in和一系列坐标对,例如:

 (defn squares [solution]
   (for [y (range 3)
         x (range 3)]
     (for [y' (range 3)
           x' (range 3)]
       (get-in solution [(+ y' (* 3 y))
                         (+ x' (* 3 x))]))))
Run Code Online (Sandbox Code Playgroud)

为了完整性:我确实说过你应该检查唯一性而不是求和(毕竟 9 5s 总和为 45,但这绝对不是一个好的解决方案!)。以下是验证 9 个数字列表是否构成有效行/列/正方形的一种方法:

(defn valid? [numbers]
  (and (= 9 (count numbers)) 
       (= (set (range 1 10)) 
          (set numbers)))
Run Code Online (Sandbox Code Playgroud)