Thanks for sharing this. Coincidentally, I just wrote my first Clojure program which was... an implementation of Conway's Game of Life :-) I took a different approach - I represented the board as a vector of vectors of integers (1 for alive, 0 for dead) and then implemented a new-board function that takes a board as an argument and returns the next generation of that board. It seemed the functional way to do it. I then create an atom whose state is a grid and repeatedly call (swap! board new-board) in order to move it through the generations.
I'll copy the source to my little program at the bottom of this email. If anyone has any comments on the style or possible improvements then I would be very interested to hear them. I'm particularly keen to hear how close to idiomatic Clojure style it is (is there a Clojure equivalent of the adjective "Pythonic"?) (import '(java.awt Color Graphics Dimension FlowLayout) '(javax.swing JPanel JFrame JButton Timer BoxLayout) '(java.awt.event MouseListener ActionListener ActionEvent)) (set! *warn-on-reflection* true) (def width 50) (def height 20) (def cell-width 10) (def cell-height 10) (def sleep-time 100) (def initial-board ; (apply vector (replicate height ; (apply vector (replicate width 0))))) [[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 1 0 0 0 1 1 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 1 1 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 1 1 0 1 0 0 1 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]) (def board-atom (atom initial-board )) (def running-atom (atom false)) ;; Board manipulation functions (defn print-board [b] (doseq [row b] (println (str row)))) (defn within [v min max] (and (>= v min) (< v max))) (defn cell-at [b x y] (if (and (within x 0 width) (within y 0 height)) (nth (nth b y) x) 0)) (defn occurences [l item] (count (filter #(= % item) l))) (defn new-cell-value [cell neighbours] (let [num-1s (occurences neighbours 1)] (if (= cell 0) ; cell is currently dead and will become alive iff it has 3 living ; neighbours (if (= num-1s 3) 1 0) ; else cell is currently alive and will die iff it has fewer than 2 or ; more than 3 living neighbours (if (or (< num-1s 2) (> num-1s 3)) 0 1)))) (defn cell-neighbours [b x y] [(cell-at b (- x 1) (- y 1)) (cell-at b x (- y 1)) (cell-at b (+ x 1) (- y 1)) (cell-at b (- x 1) y) (cell-at b (+ x 1) y) (cell-at b (- x 1) (+ y 1)) (cell-at b x (+ y 1)) (cell-at b (+ x 1) (+ y 1))]) (defn new-value-at [b x y] (let [cell (cell-at b x y) neighbours (cell-neighbours b x y)] (new-cell-value cell neighbours))) (defn new-board [b] (vec (for [y (range height)] (vec (for [x (range width)] (new-value-at b x y)))))) (defn flip-cell [b x y] (let [row (nth b y) cell (nth row x) new-cell (- 1 cell) new-row (assoc row x new-cell)] (assoc b y new-row))) (defn apply-n-times [f n x] (if (zero? n) x (recur f (dec n) (f x)))) ;; GUI functions (defn make-action-listener [f] (proxy [ActionListener] [] (actionPerformed [e] (f e)))) (defn render [#^Graphics g b] (doseq [y (range height)] (doseq [x (range width)] (let [cell (cell-at b x y)] (if (= cell 0) (.setColor g Color/WHITE) (.setColor g Color/BLACK)) (.fillRect g (* x cell-width) (* y cell-height) (dec cell-width) (dec cell-height)))))) (defn make-board-panel [] (let [panel (proxy [JPanel MouseListener] [] (paint [g] (render g @board-atom)) (getPreferredSize [] (Dimension. (* width cell-width) (* height cell-height))))] (doto panel (.addMouseListener (proxy [MouseListener] [] (mouseClicked [e] (let [x (int (/ (.getX e) cell-width)) y (int (/ (.getY e) cell-height))] (swap! board-atom flip-cell x y))) (mousePressed [e]) (mouseReleased [e]) (mouseEntered [e]) (mouseExited [e])))))) (defn make-button [text action] (doto (JButton. text) (.addActionListener (make-action-listener action)))) (defn make-control-panel [] (let [control-panel (JPanel.)] (doto control-panel (.setLayout (BoxLayout. control-panel BoxLayout/Y_AXIS)) (.add (make-button "Start" (fn [e] (swap! running-atom (constantly true))))) (.add (make-button "Stop" (fn [e] (swap! running-atom (constantly false))))) (.add (make-button "Step" (fn [e] (swap! board-atom new-board))))))) (defn make-frame [] (let [frame (JFrame. "Life")] (doto (.getContentPane frame) (.setLayout (FlowLayout.)) (.add (make-board-panel)) (.add (make-control-panel))) (add-watch board-atom "repaint" (fn [k r o n] (.repaint frame))) (doto frame (.pack) (.show)) frame)) (defn go [b] (let [frame (make-frame)] (.start (Timer. sleep-time (make-action-listener (fn [e] (when @running-atom (swap! b new-board)))))))) (go board-atom) 2009/11/16 solussd <solu...@gmail.com> > I just finished an implementation of the Conway's Game of Life > derivative, Highlife, in Clojure. It consists of a simple swing GUI > and makes good use of Refs for coordinating grid updates. A more > detailed description, source, and jars can be found here: > http://www.solussd.com/2009/11/a-clojure-highlife/ enjoy! > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com<clojure%2bunsubscr...@googlegroups.com> > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en