Very cool. I had originally planned to add some stats keeping to my  
implementation along with connected component coloring (hence the  
ref'd maps). I also found refs convenient for synchronizing my  
neighbor calculations with grid updates since I have random seeding,  
the ability to change the grid while it is running, and pausing. Looks  
like your implementation will always maintain a correctly calculated  
grid.

You might replace:
> (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))))))

with:

(defn render [#^Graphics g b]
   (doseq [y (range height) x (range width)]      ...

No need for the nested doseqs.

I'm thinking... clojuriffic? clojured? clojonic? :)

---
Joseph Smith
j...@uwcreations.com
(402)601-5443





On Nov 26, 2009, at 3:37 AM, Chris Jenkins wrote:

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

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

Reply via email to