Clojure and Processing

0

I had a great time at Devoxx this week – many thanks to Stephan and crew and whoever is making all this delicious beer here in Belgium.

During the end of my Cracking Clojure talk I showed a screencast I did where I progressively build up a solution to Conway’s Life in Clojure.

The end solution is completely stolen from Christophe Grand‘s elegant solution – I just filled in the work leading up to it (and refactored slightly). My end result from the ‘cast:

(defn neighbors [[x y]]
  (for [dx [-1 0 1]
        dy (if (zero? dx)
             [-1 1]
             [-1 0 1])]
    [(+ dx x) (+ dy y)]))

(defn live [n alive?]
  (or (= n 3)
      (and (= n 2) alive?)))

(defn step [world]
  (set
   (for [[cell n] (frequencies (mapcat neighbors world))
         :when (live n (world cell))]
     cell)))

(defn life [initial-world]
  (iterate step initial-world))

Note that the final function life will return you an infinite sequence of steps in the game of life starting from an initial world (a set of cells).

When I went to Vaclav Pech’s talk on GPars on Tuesday he did a Groovy life implementation in GPars with dataflow which was pretty slick and had a real gui. So, in the keynote before my talk I whipped up a ui of my own using Processing and the clj-processing wrappers. My code is gross, especially in comparison to the life impl but it wraps a ref around the infinite sequence, then peels off the next item (in do-step) each time draw is called (on draw) by Processing and writes it to the screen.

To add clj-processing to you project.clj, use:

 [org.clojars.automata/rosado.processing "1.1.0"]

It appears to only play nice with Clojure 1.2.x right now due to a dynamic var in the applet.

(ns demo.lifeui
  (:use [demo.life]
        [rosado.processing]
        [rosado.processing.applet]))

(def glider #{[0 1] [1 2] [2 0] [2 1] [2 2]})
(def blinker #{[3 3] [3 4] [3 5]})
(def worlds (ref (life glider)))

(defn setup []
  (background-int 0)
  (stroke-int 255)
  (framerate 4))

(defn do-step []
  (dosync
   (let [next-world (first @worlds)]
     (alter worlds #(drop 1 %))
     next-world)))

(defn grid [rows cols cells]
  (let [cellw (/ (width) cols)
        cellh (/ (height) cols)]
    (doseq [x (range rows)
            y (range cols)]
      (if (contains? cells [x y])
        (fill-float 250 50 50)
        (fill-float 0))
      (rect (* x cellw) (* y cellh) cellw cellh))))

(defn draw []
  (background 0)
  (grid 32 32 (do-step)))

(defapplet lifeui
  :title "Life"
  :setup setup
  :draw draw
  :size [800 600])

(run lifeui)

One key problem with this whole impl is that it ignores boundary wrapping so please feel free to fix that as an exercise for the reader.

Speak Your Mind

Tell us what you're thinking...
and oh, if you want a pic to show with your comment, go get a gravatar!