Coding Train, Challenge 102, Water Ripple

Simulación de goteo en superficie de agua

Código bastante corto pero bastante complejo de traducir. Importante usar estructuras de datos mutables (en este caso volatile!). Usando maps y vectores de ClojureScript el rendimiento es paupérrimo, solo funciona con canvas muy pequeños, al menos con mi implementación.

Resultado

Código

(def side 500)
(def cols side)
(def rows side)
(def dampling 0.99)

(def current (volatile! (clj->js (mapv (fn [_] (mapv (constantly 0) (range side))) (range side)))))
(def previous (volatile! (clj->js (mapv (fn [_] (mapv (constantly 0) (range side))) (range side)))))
(def temp (volatile! (clj->js (mapv (fn [_] (mapv (constantly 0) (range side))) (range side)))))

(defn mouse-dragged []
  (let [x (Math/floor js/mouseX)
        y (Math/floor js/mouseY)]
    (aset @previous x y 2550)))

(defn setup []
  (js/pixelDensity 1)
  (let [canvas (js/createCanvas cols rows)]
    (.parent canvas "p5jsparent")
    (js/loadPixels)))

(defn draw []
  (js/background 0)
  (js/loadPixels)

  (doseq [i (range 1 (dec cols))
          j (range 1 (dec rows))]
    (let [index (* 4 (+ i (* j cols)))
          n-value (* dampling
                     (-
                      (/
                       (+
                        (aget @previous (inc i) j)
                        (aget @previous (dec i) j)
                        (aget @previous i (inc j))
                        (aget @previous i (dec j)))
                       2)
                      (aget @current i j)))]
      (aset @current i j n-value)
      (aset js/pixels index       n-value)
      (aset js/pixels (+ index 1) n-value)
      (aset js/pixels (+ index 2) n-value)))
  (js/updatePixels)
  (vreset! temp @previous)
  (vreset! previous @current)
  (vreset! current @temp))

Enlaces