Initial check-in
This commit is contained in:
commit
5a74507c79
5 changed files with 122 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
pom.xml
|
||||
*jar
|
||||
lib
|
||||
classes*
|
||||
*~
|
15
README
Normal file
15
README
Normal file
|
@ -0,0 +1,15 @@
|
|||
# ray1729.clojure.sudoku
|
||||
|
||||
FIXME: write description
|
||||
|
||||
## Usage
|
||||
|
||||
FIXME: write
|
||||
|
||||
## Installation
|
||||
|
||||
FIXME: write
|
||||
|
||||
## License
|
||||
|
||||
FIXME: write
|
5
project.clj
Normal file
5
project.clj
Normal file
|
@ -0,0 +1,5 @@
|
|||
(defproject ray1729.clojure.sudoku "1.0.0-SNAPSHOT"
|
||||
:description "FIXME: write"
|
||||
:dependencies [[org.clojure/clojure "1.2.0-master-SNAPSHOT"]
|
||||
[org.clojure/clojure-contrib "1.2.0-SNAPSHOT"]]
|
||||
:dev-dependencies [[swank-clojure "1.2.1"]])
|
91
src/ray1729/clojure/sudoku/core.clj
Normal file
91
src/ray1729/clojure/sudoku/core.clj
Normal file
|
@ -0,0 +1,91 @@
|
|||
(ns ray1729.clojure.sudoku.core
|
||||
(:use [clojure.contrib.string :only (join)])
|
||||
(:require [clojure.contrib.error-kit :as ekit]))
|
||||
|
||||
(ekit/deferror *inconsistent-grid* [] []
|
||||
{:msg "Inconsistent grid"
|
||||
:unhandled (ekit/throw-msg Exception)})
|
||||
|
||||
(def rows "ABCDEFGHI")
|
||||
(def cols "123456789")
|
||||
(def grid-keys (for [r rows c cols] (str r c)))
|
||||
(def candidates (apply hash-set "123456789"))
|
||||
|
||||
(def empty-grid (apply sorted-map (interleave grid-keys (repeat candidates))))
|
||||
|
||||
(defn print-grid [grid]
|
||||
(letfn [(cell->str [cell] (join "" (map #(or (cell %) \.) candidates)))
|
||||
(row->str [row] (join " | " (map #(join " " %) (partition 3 (map cell->str row)))))]
|
||||
(let [rows (map row->str (partition 9 (vals grid)))
|
||||
separator "------------------------------+-------------------------------+------------------------------"]
|
||||
(doseq [r (apply concat (interpose [separator] (partition 3 rows)))] (println r)))))
|
||||
|
||||
(defn row-keys [[r c]] (map #(str r %) cols))
|
||||
|
||||
(defn col-keys [[r c]] (map #(str % c) rows))
|
||||
|
||||
(defn box-keys [[r c]]
|
||||
(let [row-map (into {} (for [ps (partition 3 rows) e ps] [e ps]))
|
||||
col-map (into {} (for [ps (partition 3 cols) e ps] [e ps]))]
|
||||
(for [row (row-map r) col (col-map c)] (str row col))))
|
||||
|
||||
(defn units [s] (vector (row-keys s) (col-keys s) (box-keys s)))
|
||||
|
||||
(defn peers [s] (disj (into #{} (apply concat (units s))) s))
|
||||
|
||||
(declare assign)
|
||||
(declare eliminate)
|
||||
|
||||
(defn parse-grid [s]
|
||||
(let [values (filter #(not (= \0 (val %))) (zipmap grid-keys (map first (re-seq #"\d" s))))]
|
||||
(reduce #(assign %1 (key %2) (val %2)) empty-grid values)))
|
||||
|
||||
(defn assign [grid cell value]
|
||||
(if ((grid cell) value)
|
||||
(reduce #(eliminate %1 %2 value) (assoc grid cell #{value}) (peers cell))
|
||||
(ekit/raise *inconsistent-grid*)))
|
||||
|
||||
(defn eliminate [grid cell value]
|
||||
(if (not ((grid cell) value))
|
||||
grid
|
||||
(let [new-candidates (disj (grid cell) value)
|
||||
num-candidates (count new-candidates)]
|
||||
(cond
|
||||
(= num-candidates 0) (ekit/raise *inconsistent-grid*)
|
||||
(= num-candidates 1) (assign grid cell (first new-candidates))
|
||||
:else (assoc grid cell new-candidates)))))
|
||||
|
||||
(defn solved? [grid]
|
||||
(every? #(= 1 (count %)) (vals grid)))
|
||||
|
||||
(defn solve [grid]
|
||||
(if (solved? grid)
|
||||
grid
|
||||
(let [cell (first (filter #(> (count (grid %)) 1) (keys grid)))
|
||||
candidates (grid cell)
|
||||
candidate (first candidates)]
|
||||
(ekit/with-handler
|
||||
(do
|
||||
(println (str "Trying " cell "=" candidate))
|
||||
(recur (assign grid cell candidate)))
|
||||
(ekit/handle *inconsistent-grid* []
|
||||
(if (next candidates)
|
||||
(do (println (str "Trying next candidate for " cell))
|
||||
(recur (eliminate grid cell candidate)))
|
||||
(ekit/do-not-handle)))))))
|
||||
|
||||
(comment
|
||||
|
||||
(def g1 (parse-grid
|
||||
"003020600
|
||||
900305001
|
||||
001806400
|
||||
008102900
|
||||
700000008
|
||||
006708200
|
||||
002609500
|
||||
800203009
|
||||
005010300"))
|
||||
|
||||
(def g2 (parse-grid "400000805030000000000700000020000060000080400000010000000603070500200000104000000"))
|
||||
)
|
6
test/ray1729/clojure/sudoku/core_test.clj
Normal file
6
test/ray1729/clojure/sudoku/core_test.clj
Normal file
|
@ -0,0 +1,6 @@
|
|||
(ns ray1729.clojure.sudoku.core-test
|
||||
(:use [ray1729.clojure.sudoku.core] :reload-all)
|
||||
(:use [clojure.test]))
|
||||
|
||||
(deftest replace-me ;; FIXME: write
|
||||
(is false))
|
Loading…
Reference in a new issue