Open3

Dice of DomeをClojureで

kip2kip2

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>
kip2kip2

ランダムウォークの画像生成まで(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はこんな感じ。

いい感じにばらついたやつ。