Skip to content
This repository
branch: master
Fetching contributors…

Cannot retrieve contributors at this time

file 140 lines (124 sloc) 4.191 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
(ns solutions.automaton
  (import [javax.swing JFrame JPanel]
          [java.awt Color Graphics]
          [java.awt.image BufferedImage]))

(def dim-board [ 90 90])
(def dim-screen [600 600])
(def dim-scale (vec (map / dim-screen dim-board)))

(defn new-board
  "Create a new board with about half the cells set to :on."
  ([] (new-board dim-board))
  ([[dim-x dim-y]]
     (for [x (range dim-x)]
       (for [y (range dim-y)]
         (if (< 50 (rand-int 100)) :on :off)))))

(defn with-coords [board]
  (for [[row-idx row] (map-indexed vector board)]
    (for [[col-idx val] (map-indexed vector row)]
      [val row-idx col-idx])))

(defn without-coords [board]
  (for [row board]
    (for [[state] row] state)))

(defn active-neighbors
  "Count the active (:on) neighbors one cell away from me in
any direction. Maximum of 8."
  [[[nw n ne]
    [w _ e ]
    [sw s se]]]
  (count
   (filter
    #{:on}
    (concat [nw n ne w e sw s se]))))

(defn brians-brain-rules
  "Determine the cell's next state based on its current
state and number of active neighbors."
  [above [_ cell _ :as row] below]
  (cond
   (= :on cell) :dying
   (= :dying cell) :off
   (= 2 (active-neighbors [above row below])) :on
   :else :off ))

(defn torus-window
  "The torus window is a cursor over the board, with each item
containining a cell and all its immediate neighbors."
  [coll]
  (partition 3 1 (concat [(last coll)] coll [(first coll)])))

(defn step
  "Advance the automation by one step, updating all cells."
  [board]
  (doall
   (map (fn [window]
          (apply #(apply map brians-brain-rules %&)
                 (doall (map torus-window window))))
        (torus-window board))))

(defn update-board
  "Update the automaton"
  [board-ref]
  (swap! board-ref step))

(def state->color {:on java.awt.Color/WHITE
                   :off java.awt.Color/BLACK
                   :dying java.awt.Color/GRAY})

(defn render-cell [g cell]
  (let [[state x y] cell
        [x-scale y-scale] dim-scale
        x (inc (* x x-scale))
        y (inc (* y y-scale))]
    (doto g
      (.setColor (state->color state))
      (.fillRect x y (dec x-scale) (dec y-scale)))))

(defn render [graphics img board]
  (let [background-graphics (.getGraphics img)]
    (doto background-graphics
      (.setColor java.awt.Color/BLACK)
      (.fillRect 0 0 (dim-screen 0) (dim-screen 1)))
    (doseq [row (with-coords board)
            cell row]
      (when-not (#{:off} (cell 0))
        (render-cell background-graphics cell)))
    (.drawImage graphics img 0 0 nil)))

(defn activity-loop [panel board]
  (while
      @board
    (update-board board)
    (.repaint panel)))

(defn launch-1 []
  (let [[screen-x screen-y] dim-screen
        board (atom (new-board))
        frame (javax.swing.JFrame.)
        panel (proxy [javax.swing.JPanel] [])]
    (doto frame
      (.add panel)
      (.pack)
      (.setSize screen-x screen-y)
      (.show)
      (.setDefaultCloseOperation javax.swing.JFrame/DISPOSE_ON_CLOSE))
    board))

(defn launch-2 []
  (let [[screen-x screen-y] dim-screen
        board (atom (new-board))
        frame (javax.swing.JFrame.)
        img (java.awt.image.BufferedImage. screen-x screen-y java.awt.image.BufferedImage/TYPE_INT_ARGB)
        panel (proxy [javax.swing.JPanel] []
                (paint [g] (render g img @board)))]
    (doto frame
      (.add panel)
      (.pack)
      (.setSize screen-x screen-y)
      (.show)
      (.setDefaultCloseOperation javax.swing.JFrame/DISPOSE_ON_CLOSE))
    board))

(defn launch []
  (let [[screen-x screen-y] dim-screen
        board (atom (new-board))
        frame (javax.swing.JFrame.)
        img (java.awt.image.BufferedImage. screen-x screen-y java.awt.image.BufferedImage/TYPE_INT_ARGB)
        panel (proxy [javax.swing.JPanel] []
                (paint [g] (render g img @board)))]
    (doto frame
      (.add panel)
      (.pack)
      (.setSize screen-x screen-y)
      (.show)
      (.setDefaultCloseOperation javax.swing.JFrame/DISPOSE_ON_CLOSE))
    (future (activity-loop panel board))
    board))
Something went wrong with that request. Please try again.