美文网首页
Clojure逻辑式编程求解数独

Clojure逻辑式编程求解数独

作者: mingdongz | 来源:发表于2018-04-26 15:11 被阅读0次
    (ns fun.sudoku
      (:refer-clojure :exclude [==])
      (:require [clojure.core.logic :as logic]
                [clojure.core.logic.fd :as fd]))
    
    ;; 定义数独数据
    (def b1 '[- - 1 - - - 2 - -
              - 6 - - - 5 - 1 3
              - - - - 1 - 7 - 6
              6 - - 5 - 9 - - 8
              - - 8 3 - 4 - 9 -
              9 - - - - - - 2 -
              - 1 - - - - - - 2
              - 5 6 7 - - - - -
              2 - 7 - - 1 5 - -])
    
    ;; 定义一些函数
    (defn print-board [board] ;; 打印数独题目
        (let [row-sep (apply str (repeat 37 "-"))
              bx     (map #(partition 3 %) (partition 9 board))]
            (println row-sep)
            (dotimes [row (count bx)]
            (print "| ")
            (doseq [subrow (nth bx row)]
                (doseq [cell (butlast subrow)]
                (print (str cell "   ")))
                (print (str (last subrow) " | ")))
            (println)
            (when (zero? (mod (inc row) 3))
                (println row-sep)))))
    
    ;; 按行分组
    (defn rowify [board]
        (->> board
                (partition 9)
                (map vec)
                vec))
    ;; 按列分组    
    (defn colify [rows]
        (apply map vector rows))
    ;; 按3x3分组
    (defn subgrid [rows]
        (partition 9
            (for [row (range 0 9 3)
                col (range 0 9 3)
                x (range row (+ row 3))
                y (range col (+ col 3))]
            (get-in rows [x y]))))
    
    ;; 接下来定义逻辑
    ;; 按数独数据初始化“知识”
    (defn init [[lv & lvs] [cell & cells]]
        (if lv
            (logic/fresh []
                (if (= '- cell)
                logic/succeed
                (logic/== lv cell))
                (init lvs cells))
            logic/succeed))
    ;; 初始化逻辑变量
    (def logic-board #(repeatedly 81 logic/lvar))
    
    ;; ok,开始推理
    (defn solve-logically [board]
        (let [legal-nums (fd/interval 1 9)
                lvars (logic-board)
                rows  (rowify lvars)
                cols  (colify rows)
                grids (subgrid rows)]
            (logic/run 1 [q]
                (init lvars board)                
                (logic/everyg #(fd/in % legal-nums) lvars) ;; 条件1: 只能填1-9 
                (logic/everyg fd/distinct rows) ;; 条件2: 行不能重复
                (logic/everyg fd/distinct cols) ;; 条件3: 列不能重复
                (logic/everyg fd/distinct grids) ;; 条件4: 3x3方格内不能重复
                (logic/== q lvars))))  ;; 结果
                  
    
    (comment
        
        (-> b1
            print-board)
        
        (-> b1
            solve-logically
            first
            print-board))
    

    相关文章

      网友评论

          本文标题:Clojure逻辑式编程求解数独

          本文链接:https://www.haomeiwen.com/subject/awtmlftx.html