Fun FridaYS — Dragon Curve
On Friday June 27th we found a task on Rosetta Code
and converted the
Clojure
solution to YS.
Let's do that again today.
The Dragon Curve🔗
I found a pretty cool task called Dragon Curve
on Rosetta Code.
The task is to generate a Dragon Curve
of a given length.
Here's an example of length 511 taken from the Clojure code we are about to convert to YS:
┌┐┌┐ ┌┐┌┐
┌┼┼┼┘ ┌┼┼┼┘
└┘└┼┐┌┐ └┘└┼┐┌┐
┌┼┼┼┘ ┌┼┼┼┘
┌┐┌┐┌┼┼┼┼┐┌┐┌┼┼┼┘
┌┼┼┼┼┘└┼┼┘└┼┼┼┼┼┘
└┘└┼┼┐ └┼┐ └┼┼┼┼┐┌┐
┌┘└┘ └┘ ┌┼┼┼┼┼┼┘
┌┼┐ └┼┼┼┼┼┘ ┌┐┌┐
┌┼┼┘ ┌┼┘└┼┘ ┌┼┼┼┘
└┘└┐ ╶┐ └┼┐ └┐┌┐ └┘└┼┐┌┐
┌┼┐┌┘ └┘ ┌┼┼┘ ┌┼┼┼┘
└┘└┘ └┼┼┐┌┐┌┼┼┼┘
┌┐┌┼┼┼┼┼┼┼┼┘
└┼┼┼┼┼┼┼┼┼┼┐┌┐
┌┐┌┼┼┼┼┼┼┼┼┼┼┼┼┘
└┼┼┼┼┼┼┼┼┼┘└┘└┘
┌┼┘└┼┼┼┼┼┘
└┼┐ └┼┼┼┼┐┌┐
└┘ ┌┼┼┼┼┼┼┘
└┼┘└┘└┘
┌┐┌┘
└┼┼┐┌┐
┌┐┌┼┼┼┼┘
└┼┼┼┼┼┘
┌┼┘└┼┘ ┌┐
└┼┐ └┐┌┐ ╵└┐
└┘ ┌┼┼┘ ┌┘
└┼┼┐┌┐┌┼┐
┌┼┘└┼┼┘└┘
└┼┐ └┼┐
└┘ └┘
The Clojure code looks like this:
(defn i->dir
[n]
(mod (Long/bitCount (bit-xor n (bit-shift-right n 1))) 4))
(defn safe-bit-or [v bit] (bit-or (or v 0) bit))
(let [steps 511
{[minx maxx miny maxy] :bbox data :data}
(loop [i 0
[x y] [0 0]
out {}
[minx maxx miny maxy] [0 0 0 0]]
(let [dir (i->dir i)
[nx ny] [(+ x (condp = dir 0 1 2 -1 0))
(+ y (condp = dir 1 1 3 -1 0))]
[ob ib] (nth [[8 4][2 1][4 8][1 2]] dir)
out (-> (update-in out [y x] safe-bit-or ob)
(update-in [ny nx] safe-bit-or ib))
bbox [(min minx nx) (max maxx nx)
(min miny ny) (max maxy ny)]]
(if (< i steps)
(recur (inc i) [nx ny] out bbox)
{:data out :bbox bbox})))]
(doseq [y (range miny (inc maxy))]
(->> (for [x (range minx (inc maxx))]
(nth " ╵╷│╴┘┐┤╶└┌├─┴┬┼" (get-in data [y x] 0)))
(apply str)
(println))))
The YS Code🔗
I won't go through this step by step this time.
Here's the YS code:
!YS-v0
defn main(steps=511):
data [minx maxx miny maxy] =:
loop i 0 [x y], [0 0], data {}, [minx maxx miny maxy] [0 0 0 0]:
dir =: i-to-dir(i)
nx ny =: +
[(x + condp(== dir 0 1 2 -1 0))
(y + condp(== dir 1 1 3 -1 0))]
ob ib =: dir.nth([[8 4][2 1][4 8][1 2]])
data =: update-in(data [y x] safe-bit-or ob)
.update-in([ny nx] safe-bit-or ib)
bbox =: +
[min(minx nx) max(maxx nx)
min(miny ny) max(maxy ny)]
if i < steps:
recur: i.++, [nx ny], data, bbox
vector: data bbox
each y (miny .. maxy):
say: !:join
each x (minx .. maxx):
get-in(data [y x] 0).nth(" ╵╷│╴┘┐┤╶└┌├─┴┬┼")
defn i-to-dir(n):
n.bit-xor(bit-shift-right(n 1)):Long/bitCount % 4
defn safe-bit-or(v bit):
(v || 0).bit-or(bit)
Let's run it:
$ ys dragon-curve.ys
┌┐┌┐ ┌┐┌┐
┌┼┼┼┘ ┌┼┼┼┘
└┘└┼┐┌┐ └┘└┼┐┌┐
┌┼┼┼┘ ┌┼┼┼┘
┌┐┌┐┌┼┼┼┼┐┌┐┌┼┼┼┘
┌┼┼┼┼┘└┼┼┘└┼┼┼┼┼┘
└┘└┼┼┐ └┼┐ └┼┼┼┼┐┌┐
┌┘└┘ └┘ ┌┼┼┼┼┼┼┘
┌┼┐ └┼┼┼┼┼┘ ┌┐┌┐
┌┼┼┘ ┌┼┘└┼┘ ┌┼┼┼┘
└┘└┐ ╶┐ └┼┐ └┐┌┐ └┘└┼┐┌┐
┌┼┐┌┘ └┘ ┌┼┼┘ ┌┼┼┼┘
└┘└┘ └┼┼┐┌┐┌┼┼┼┘
┌┐┌┼┼┼┼┼┼┼┼┘
└┼┼┼┼┼┼┼┼┼┼┐┌┐
┌┐┌┼┼┼┼┼┼┼┼┼┼┼┼┘
└┼┼┼┼┼┼┼┼┼┘└┘└┘
┌┼┘└┼┼┼┼┼┘
└┼┐ └┼┼┼┼┐┌┐
└┘ ┌┼┼┼┼┼┼┘
└┼┘└┘└┘
┌┐┌┘
└┼┼┐┌┐
┌┐┌┼┼┼┼┘
└┼┼┼┼┼┘
┌┼┘└┼┘ ┌┐
└┼┐ └┐┌┐ ╵└┐
└┘ ┌┼┼┘ ┌┘
└┼┼┐┌┐┌┼┐
┌┼┘└┼┼┘└┘
└┼┐ └┼┐
└┘ └┘
Looks the same to me!
I think you've learned enough YS to understand this conversion, but take some time to go over it and reinforce your understanding.
If you need me to explain something, please ask in the comments.