Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dragon-curve exercise #843

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
1 change: 1 addition & 0 deletions exercises/practice/dragon-curve/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Instructions
1 change: 1 addition & 0 deletions exercises/practice/dragon-curve/.docs/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Introduction
20 changes: 20 additions & 0 deletions exercises/practice/dragon-curve/.meta/config.json
Original file line number Diff line number Diff line change
@@ -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"
}
109 changes: 109 additions & 0 deletions exercises/practice/dragon-curve/.meta/example.clj
Original file line number Diff line number Diff line change
@@ -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)))))
6 changes: 6 additions & 0 deletions exercises/practice/dragon-curve/deps.edn
Original file line number Diff line number Diff line change
@@ -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}}}
4 changes: 4 additions & 0 deletions exercises/practice/dragon-curve/project.clj
Original file line number Diff line number Diff line change
@@ -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"]])
7 changes: 7 additions & 0 deletions exercises/practice/dragon-curve/src/dragon_curve.clj
Original file line number Diff line number Diff line change
@@ -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
)
43 changes: 43 additions & 0 deletions exercises/practice/dragon-curve/test/dragon_curve_test.clj
Original file line number Diff line number Diff line change
@@ -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)))))