diff --git a/config.json b/config.json index 4576e9ef..f4c5faa6 100644 --- a/config.json +++ b/config.json @@ -1545,6 +1545,14 @@ ], "difficulty": 8 }, + { + "slug": "dragon-curve", + "name": "Dragon curve", + "uuid": "a577573c-7533-4c40-8b59-b31148362e3a", + "practices": [], + "prerequisites": [], + "difficulty": 8 + }, { "slug": "go-counting", "name": "Go Counting", diff --git a/exercises/practice/dragon-curve/.docs/instructions.md b/exercises/practice/dragon-curve/.docs/instructions.md new file mode 100644 index 00000000..63fd98ab --- /dev/null +++ b/exercises/practice/dragon-curve/.docs/instructions.md @@ -0,0 +1 @@ +# Instructions diff --git a/exercises/practice/dragon-curve/.docs/introduction.md b/exercises/practice/dragon-curve/.docs/introduction.md new file mode 100644 index 00000000..e10b99d0 --- /dev/null +++ b/exercises/practice/dragon-curve/.docs/introduction.md @@ -0,0 +1 @@ +# Introduction diff --git a/exercises/practice/dragon-curve/.meta/config.json b/exercises/practice/dragon-curve/.meta/config.json new file mode 100644 index 00000000..3230494d --- /dev/null +++ b/exercises/practice/dragon-curve/.meta/config.json @@ -0,0 +1,20 @@ +{ + "authors": [ + "tasxatzial" + ], + "contributors": [], + "files": { + "solution": [ + "src/dragon_curve.clj" + ], + "test": [ + "test/dragon_curve_test.clj" + ], + "example": [ + ".meta/example.clj" + ] + }, + "blurb": "TODO", + "source": "Anastasios Chatzialexiou", + "source_url": "https://github.com/exercism/clojure/pull/843" +} diff --git a/exercises/practice/dragon-curve/.meta/example.clj b/exercises/practice/dragon-curve/.meta/example.clj new file mode 100644 index 00000000..4217cab8 --- /dev/null +++ b/exercises/practice/dragon-curve/.meta/example.clj @@ -0,0 +1,109 @@ +(ns dragon-curve) + +(def start-turn :right) +(def segment-length 2) ; should be even +(def start-points [[0 0] [segment-length 0]]) +(def start-direction :east) + + +(defn swap-turn + [turn] + (case turn + :left :right + :right :left)) + +(defn unfold-paper-once + [paper-turns] + (-> paper-turns + (into [start-turn]) + (into (reverse (map swap-turn paper-turns))))) + +(defn unfold-paper-times + [n] + (reduce (fn [result _] + (unfold-paper-once result)) + [] (range n))) + +(def paper-turn->direction + {:left {:north :west + :west :south + :south :east + :east :north} + :right {:north :east + :east :south + :south :west + :west :north}}) + +(defn generate-next-point + [point direction] + (let [[x y] point] + (case direction + :north [x (+ y segment-length)] + :east [(+ x segment-length) y] + :south [x (- y segment-length)] + :west [(- x segment-length) y]))) + +(defn generate-points + [paper-turns] + (loop [result start-points + point (second start-points) + direction start-direction + turns paper-turns] + (if (seq turns) + (let [new-direction (get (paper-turn->direction (first turns)) direction) + new-point (generate-next-point point new-direction)] + (recur (conj result new-point) new-point new-direction (rest turns))) + result))) + +(defn find-midpoint + [segment] + (let [[[x1 y1] [x2 y2]] segment] + [(/ (+ x1 x2) 2) (/ (+ y1 y2) 2)])) + +(defn generate-midpoints + [points] + (reduce (fn [result segment] + (conj result (find-midpoint segment))) + [] (partition 2 1 points))) + +(defn find-bounding-box-corners + [points] + (let [xs (map first points) + ys (map second points)] + [[(- (apply min xs) segment-length) (- (apply min ys) segment-length)] + [(+ (apply max xs) segment-length) (+ (apply max ys) segment-length)]])) + +(defn range-with-offset + [start end] + (let [offset (/ segment-length 2)] + (range (+ start offset) (inc (- end offset)) segment-length))) + +(defn generate-grid + [bounding-box-corners] + (let [[[x-left y-bottom] [x-right y-top]] bounding-box-corners] + (for [x (range-with-offset x-left x-right) + y (range-with-offset y-bottom y-top)] + [x y]))) + +(defn find-neighbors + [point] + (map #(generate-next-point point %) [:north :east :south :west])) + +(defn can-fill? + [point obstacles] + (let [neighbors (find-neighbors point) + midpoints (map #(find-midpoint [% point]) neighbors)] + (not (every? obstacles midpoints)))) + +(defn fill-grid + [grid obstacles] + (filter #(can-fill? % obstacles) grid)) + +(defn count-squares + [n] + (let [curve-points (generate-points (unfold-paper-times n)) + curve-midpoints (generate-midpoints curve-points) + bounding-box-corners (find-bounding-box-corners curve-points) + grid (generate-grid bounding-box-corners) + obstacles (set curve-midpoints)] + (- (count grid) (count (fill-grid grid obstacles))))) diff --git a/exercises/practice/dragon-curve/deps.edn b/exercises/practice/dragon-curve/deps.edn new file mode 100644 index 00000000..561c3e2d --- /dev/null +++ b/exercises/practice/dragon-curve/deps.edn @@ -0,0 +1,6 @@ +{:aliases {:test {:extra-paths ["test"] + :extra-deps {io.github.cognitect-labs/test-runner + {:git/url "https://github.com/cognitect-labs/test-runner.git" + :sha "705ad25bbf0228b1c38d0244a36001c2987d7337"}} + :main-opts ["-m" "cognitect.test-runner"] + :exec-fn cognitect.test-runner.api/test}}} \ No newline at end of file diff --git a/exercises/practice/dragon-curve/project.clj b/exercises/practice/dragon-curve/project.clj new file mode 100644 index 00000000..fbaab8d6 --- /dev/null +++ b/exercises/practice/dragon-curve/project.clj @@ -0,0 +1,4 @@ +(defproject dragon-curve "0.1.0-SNAPSHOT" + :description "dragon-curve exercise." + :url "https://github.com/exercism/clojure/tree/main/exercises/practice/dragon-curve" + :dependencies [[org.clojure/clojure "1.12.0"]]) diff --git a/exercises/practice/dragon-curve/src/dragon_curve.clj b/exercises/practice/dragon-curve/src/dragon_curve.clj new file mode 100644 index 00000000..25c037e8 --- /dev/null +++ b/exercises/practice/dragon-curve/src/dragon_curve.clj @@ -0,0 +1,7 @@ +(ns dragon-curve) + +(defn count-squares + "Counts the number of squares in the unfolded dragon curve after n paper folds." + [n] + ;; function body + ) diff --git a/exercises/practice/dragon-curve/test/dragon_curve_test.clj b/exercises/practice/dragon-curve/test/dragon_curve_test.clj new file mode 100644 index 00000000..06c5d856 --- /dev/null +++ b/exercises/practice/dragon-curve/test/dragon_curve_test.clj @@ -0,0 +1,43 @@ +(ns dragon-curve-test + (:require [clojure.test :refer [deftest testing is]] + dragon-curve)) + +(deftest count-squares_test_1 + (testing "0 folds" + (is (= 0 (dragon-curve/count-squares 0))))) + +(deftest count-squares_test_2 + (testing "1 folds" + (is (= 0 (dragon-curve/count-squares 1))))) + +(deftest count-squares_test_3 + (testing "2 folds" + (is (= 0 (dragon-curve/count-squares 2))))) + +(deftest count-squares_test_4 + (testing "3 folds" + (is (= 0 (dragon-curve/count-squares 3))))) + +(deftest count-squares_test_5 + (testing "4 folds" + (is (= 1 (dragon-curve/count-squares 4))))) + +(deftest count-squares_test_6 + (testing "5 folds" + (is (= 4 (dragon-curve/count-squares 5))))) + +(deftest count-squares_test_7 + (testing "6 folds" + (is (= 11 (dragon-curve/count-squares 6))))) + +(deftest count-squares_test_8 + (testing "8 folds" + (is (= 67 (dragon-curve/count-squares 8))))) + +(deftest count-squares_test_9 + (testing "11 folds" + (is (= 724 (dragon-curve/count-squares 11))))) + +(deftest count-squares_test_10 + (testing "13 folds" + (is (= 3232 (dragon-curve/count-squares 13)))))