Open3
Dice of DomeをClojureで
経緯
Clojureを学ぶにあたって、実際に動くものを作りたい。
そこで我らが聖典Land of Lispから、Dice of DomeをClojureに移植する形で作ってみようかと思った。
偉大なる聖典
SVGを作成するところから
本書の順番とは異なるが、まず手をつけられそうなところからやる。
SVGを作りたいので、先にこちらから手を付ける試み。
ログを取るのは途中から思いついたので、svgマクロまでは結果だけのコードを示す。
(defmacro tag [name atts & body]
`(do
(print-tag '~name
(map (fn [[k# v#]]
[(name k#) v#])
(partition 2 ~atts))
nil)
(print ~@body)
(print-tag ~name nil true)))
(defmacro html [& body]
`(tag "html" []
~@body))
(defmacro body [& body]
`(tag "body" []
~@body))
(html
(body
"Hello, HTML!"))
; <html><body>Hello, HTML!</body></html>
(defmacro svg [width height & body]
`(tag "svg"
[:xmlns "http://www.w3.org/2000/svg"
:xmlns:xlink "http://www.w3.org/1999/xlink"
:height ~height
:width ~width]
~@body))
(macroexpand-1 '(svg 100 100 "svg body"))
(svg 100 100 "svg body")
; <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="100" width="100">svg body</svg>
ランダムウォークの画像生成まで(17.2)
(defn brightness [col amt]
(map (fn [x] (min 255 (max 0 (+ x amt))))
col))
(defn svg-style [color]
(let [adjusted-color (brightness color -100)]
(format "fill:rgb(%d,%d,%d);stroke:rgb(%d,%d,%d)"
(nth color 0) (nth color 1) (nth color 2)
(nth adjusted-color 0) (nth adjusted-color 1) (nth adjusted-color 2))))
(defn circle [center radius color]
(tag "circle" [:cx (first center)
:cy (second center)
:r radius
:style (svg-style color)]))
(defn polygon [points color]
(let [points-str (apply str
(interpose " "
(map (fn [[x y]] (str x "," y)) points)))
style (svg-style color)]
(tag "polygon"
[:points points-str
:style style])))
(defn random-walk
[value length]
(when-not (zero? length)
(cons value
(random-walk (if (zero? (rand-int 2))
(dec value)
(inc value))
(dec length)))))
(defn save-svg-to-file [filename svg-content]
(spit filename svg-content))
(def svg-content
(svg 400 200
(apply str (for [_ (range 10)] (polygon (concat [[0 200]]
(map-indexed (fn [i n] [i n]) (random-walk 100 400))
[[400 200]])
(repeatedly 3 #(rand-int 256)))))))
(save-svg-to-file "random-walk.svg" svg-content)
生成したランダムウォークのSVGはこんな感じ。
いい感じにばらついたやつ。