Created
March 24, 2011 19:55
-
-
Save mecdemort/885740 to your computer and use it in GitHub Desktop.
Game of life
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(definterface AutomataOps | |
(^long bound [^long x]) | |
(^long getCell [^long x ^long y]) | |
(^long countNeighbors [^long x ^long y]) | |
(^long alive [^long cell ^long neighbors]) | |
(^long updateCell [^long x ^long y])) | |
(defprotocol Automata | |
(update [this])) | |
(deftype CellularAutomata [^long dim ^longs cells ^longs birth ^longs live] | |
AutomataOps | |
(bound [this x] | |
(cond (neg? x) (+ x dim) | |
(>= x dim) (- x dim) | |
:else x)) | |
(getCell [this x y] | |
(let [x (.bound this x) | |
y (.bound this y)] | |
(aget cells (+ (unchecked-multiply dim x) y)))) | |
(countNeighbors [this x y] | |
(-> (.getCell this (dec x) (dec y)) | |
(+ , (.getCell this (dec x) y)) | |
(+ , (.getCell this (dec x) (inc y))) | |
(+ , (.getCell this x (dec y))) | |
(+ , (.getCell this x (inc y))) | |
(+ , (.getCell this (inc x) (dec y))) | |
(+ , (.getCell this (inc x) y)) | |
(+ , (.getCell this (inc x) (inc y))))) | |
(alive [this cell neighbors] | |
(if (zero? cell) | |
(if (and (<= (aget birth 0) neighbors) | |
(<= neighbors (aget birth 1))) | |
(long 1) | |
cell) | |
(if (and (<= (aget live 0) neighbors) | |
(<= neighbors (aget live 1))) | |
cell | |
(long 0)))) | |
(updateCell [this x y] | |
(.alive this (.getCell this x y) (.countNeighbors this x y))) | |
Automata | |
(update [this] | |
(CellularAutomata. | |
dim | |
(amap cells i res | |
(let [i (long i) | |
x (unchecked-divide i dim) | |
y (unchecked-remainder i dim)] | |
(.updateCell this x y))) | |
birth | |
live))) | |
(defn new-automata [dim] | |
(CellularAutomata. | |
dim | |
(long-array (repeatedly (* dim dim) #(rand-int 2))) | |
(long-array [3 3]) | |
(long-array [2 3]))) | |
(def dim 100) | |
(def world (atom (new-automata dim))) | |
(defn iterate-world [] | |
(swap! world update)) | |
;;--------------------- UI -------------------------------- | |
(import | |
'(java.awt Color Graphics Dimension) | |
'(java.awt.event WindowAdapter MouseAdapter) | |
'(java.awt.image BufferedImage) | |
'(javax.swing JPanel JFrame SwingUtilities)) | |
(declare start stop) | |
(let [scale 5 | |
animation-sleep-ms 50 | |
run-sleep-ms 75 | |
running (atom true) | |
stopfn #(reset! running nil) | |
render (fn [g] | |
(let [world @world | |
img (BufferedImage. (* scale dim) | |
(* scale dim) | |
BufferedImage/TYPE_INT_ARGB) | |
bg (.getGraphics img)] | |
(doto bg | |
(.setColor Color/BLUE) | |
(.fillRect 0 0 (.getWidth img) (.getHeight img)) | |
(.setColor Color/WHITE)) | |
(doseq [x (range dim) | |
y (range dim) | |
:when (zero? (.getCell world x y))] | |
(.fillRect bg (* x scale) (* y scale) scale scale)) | |
(.drawImage g img 0 0 nil) | |
(.dispose bg))) | |
mouse-listener (proxy [MouseAdapter] [] | |
(mouseClicked [e] | |
(if @running | |
(stopfn) | |
(#'start)))) | |
panel (doto (proxy [JPanel] [] (paint [g] (render g))) | |
(.setPreferredSize | |
(Dimension. | |
(* scale dim) | |
(* scale dim))) | |
(.addMouseListener mouse-listener)) | |
window-listener (proxy [WindowAdapter] [] | |
(windowClosed [e] (stopfn))) | |
frame (doto (JFrame.) | |
(.add panel) | |
(.addWindowListener window-listener) | |
(.setDefaultCloseOperation JFrame/DISPOSE_ON_CLOSE) | |
.pack)] | |
(defn start [] | |
(.show frame) | |
(reset! running true) | |
(future | |
(while @running | |
(SwingUtilities/invokeAndWait #(.repaint frame)) | |
(Thread/sleep animation-sleep-ms))) | |
(future | |
(while @running | |
(iterate-world) | |
(Thread/sleep run-sleep-ms)))) | |
(def stop stopfn)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment