# pseudohkoo / src / pseudohkoo / core.clj

 ``` 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109``` ```(ns pseudohkoo.core) (require 'clojure.set) ; NOTE: some of these functions will disappear - I've been writing them to ; help me understand Clojure as well as aspects of the problem space ;; box functions (defn extract-slice [vec index] ; extracts a three item slice from vec which corresponds to the slice of 3x3 box index is within ; this needs a better description! (let [start-index (* 3 (quot index 3))] (subvec vec start-index (+ start-index 3)))) (defn get-box [grid row-index column-index] ; return set of values of 3x3 box containing given location (set (flatten (map (fn [row] (extract-slice row column-index)) (extract-slice grid row-index))))) ;; line functions (defn format-value [value] ; returns either an integer or a vector, depending on whether ; value holds single or multiple values respectively (if (= 1 (count value)) (first value) (vec value))) (defn current-values [line] ; returns the set of known/definite current values for the line (set (filter integer? line))) (defn required-values [line] ; returns the set of required values for the line ; i.e. the set of numbers needed for a line to be complete (set (range 1 (+ (count line) 1)))) (defn missing-values [line] ; returns the set of numbers that are still missing from the line (clojure.set/difference (required-values line) (current-values line))) (defn refine-line [line] ; returns a line with non-definite values refined, where possible (map (fn [cell] (if (nil? cell) (format-value (missing-values line)) (if (vector? cell) (format-value (clojure.set/intersection (missing-values line) (set cell))) cell))) line)) ;; row functions (defn get-row [grid row-index] ; returns the specified row from the grid, or [] if row out-of-bounds (nth grid row-index [])) (defn refine-row [row] ; return a row with non-definite values refined, where possible (refine-line row)) (defn row-complete? [row] ; returns true if row has been completed or false if not (= (required-values row) (set row))) (defn update-row [row column-index new-value] ; returns a copy of row with the indicated column set to new-value (let [head (take column-index row) tail (nthnext row (+ column-index 1))] (concat head [new-value] tail))) ;; column functions (defn get-column [grid column-index] ; returns the specified column from the grid (map (fn [row] (nth row column-index)) grid)) (defn get-columns [grid] ; retrieve all columns from the grid (this is like flipping the grid along a diagonal) (map (fn [index] (get-column grid index)) (range (count (first grid))))) (defn refine-column [column] ; return a column with non-definite values refined, where possible (refine-line column)) (defn replace-column [grid column-index new-column] ; returns a copy of the grid with the given column replaced by the new one (map (fn [index] (update-row (get-row grid index) column-index (nth new-column index))) (range (count new-column)))) ;; grid functions (defn refine [grid] ; returns vector of refined columns (map (fn [column] (refine-column column)) (get-columns (map refine-row grid)))) (defn remap-columns-to-grid [columns grid] ; remaps refined columns back to the grid (get-columns columns)) (defn refine-grid [grid] ; return a "refined" grid - replacing nil cells with definite or possible values as appropriate (remap-columns-to-grid (refine grid) grid)) (defn grid-complete? [grid] ; returns true if grid is finished or false if not (reduce (fn [x y] (and x y)) (map row-complete? grid))) ```