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