Skip to content

Instantly share code, notes, and snippets.

@alpox
Last active April 3, 2024 21:47
Show Gist options
  • Save alpox/cbe1b5b5d0260b0b1977cba3b9d5f6be to your computer and use it in GitHub Desktop.
Save alpox/cbe1b5b5d0260b0b1977cba3b9d5f6be to your computer and use it in GitHub Desktop.
FCC Challenge 3. April 2024
(ns c13
(:require
[clojure.string :as str]
[clojure.spec.alpha :as s]
[clojure.test :refer [testing is]]
[clojure.test.check :as check]
[clojure.test.check.generators :as gen]
[clojure.test.check.properties :as prop]
[com.gfredericks.test.chuck.generators :as gen']))
(def row-width 10)
(def colour-regex #"[a-z]\d{3}")
(def part-line (str/join (repeat 7 "─")))
(s/def ::colour #(re-matches colour-regex %))
(def empty-row (vec (repeat row-width nil)))
(defn- row->index [row] (- (int row) (int \A)))
(defn- column->index [column] (dec column))
(defn- index->row [index] (char (+ index (int \A))))
(defn- index->column [index] (inc index))
(defn- nail-location [row column]
[:nails (row->index row) (column->index column)])
(defprotocol NailBookLike
(add-colour [this colour row column])
(reset-row [this row])
(display [this])
(find-colour [this colour]))
(defrecord NailBook [nails]
NailBookLike
(add-colour [this colour row column]
(when-not (s/valid? ::colour colour)
(throw (ex-info (format "Invalid colour '%s'" colour) {:colour colour})))
(assoc-in this (nail-location row column) colour))
(reset-row [this row]
(assoc-in this [:nails (row->index row)] empty-row))
(display [_]
(let [start-line (str "┌" (str/join "┬" (repeat (inc row-width) part-line)) "┐")
middle-line (str "├" (str/join "┼" (repeat (inc row-width) part-line)) "┤")
end-line (str "└" (str/join "┴" (repeat (inc row-width) part-line)) "┘")]
(with-out-str
(println start-line)
(print "│")
(print (format "%6s │" " "))
(doseq [column-index (range row-width)]
(print (format "%6s │" (index->column column-index))))
(doseq [row-index (range (count nails))]
(println)
(println middle-line)
(print "│")
(print (format "%6s │" (index->row row-index)))
(doseq [column (nth nails row-index)]
(print (format "%6s │" (if column column " ")))))
(println)
(println end-line))))
(find-colour [_ colour]
(let [found (first (for [row-index (range (count nails))
column-index (range row-width)
:when (= (get-in nails [row-index column-index]) colour)]
[(index->row row-index) (index->column column-index)]))]
(when (nil? found)
(throw (ex-info (format "Colour '%s' not found" colour) {:colour colour})))
found)))
(defn make-nail-book []
(->NailBook (vec (take 10 (repeat empty-row)))))
; ---------------------------------------------------------------------------------------
; Testing
; ---------------------------------------------------------------------------------------
(def add-colours-gen
(gen/tuple (gen'/bounded-int 0 9)
(gen'/bounded-int 0 9)
(gen'/string-from-regex colour-regex)))
(def filled-test-book
(reduce
(fn [book [row column colour]]
(add-colour book colour (index->row row) (index->column column)))
(make-nail-book)
(distinct (take 100 (gen/sample-seq add-colours-gen)))))
(def color-prop
(prop/for-all
[[row column v] add-colours-gen]
(let [book (add-colour (make-nail-book) v (index->row row) (index->column column))]
(is (= v (get-in book (nail-location (index->row row) (index->column column))))))))
(testing "Nail book"
(testing "add-colour"
(check/quick-check 100 color-prop))
(testing "reset-colour"
(check/quick-check
10
(prop/for-all [row (gen'/bounded-int 0 9)]
(let [book (reset-row filled-test-book (index->row row))]
(is (= (get-in book [:nails row]) empty-row))))))
(testing "find-colour"
(doseq [row (range 10)
column (range 10)]
(let [colour (get-in filled-test-book
(nail-location (index->row row) (index->column column)))]
(when colour
(is (= [(index->row row) (index->column column)]
(find-colour filled-test-book colour))))))))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment