Clojure-tastic? :-)

Thanks for the doseq help. It should shave a few more LOCs off my
implementation.

Cheers,

Chris

2009/11/28 Joseph Smith <j...@uwcreations.com>

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

Reply via email to