ynd / mona-clojure
- Source
- Commits
- Network (1)
- Issues (0)
- Downloads (0)
- Wiki (1)
- Graphs
-
Branch:
master
mona-clojure / mona-clojure.clj
| 30723987 » | ynd | 2009-01-19 | 1 | (import | |
| 2 | '(java.awt Graphics Graphics2D Color Polygon) | ||||
| 3 | '(java.awt.image BufferedImage PixelGrabber) | ||||
| 4 | '(java.io File) | ||||
| 5 | '(javax.imageio ImageIO) | ||||
| 6 | '(javax.swing JFrame JPanel JFileChooser)) | ||||
| 7 | |||||
| 8 | ; --------------------------------------------------------------------- | ||||
| 9 | ; This section defines the building blocks of the genetic programs. | ||||
| 10 | |||||
| 11 | ; color :: Integer -> Integer -> Integer -> Integer -> Color | ||||
| 12 | (defn color [red blue green alpha] {:type :Color :red red :blue blue :green green :alpha alpha}) | ||||
| 13 | |||||
| 14 | ; point :: Integer -> Integer -> Point | ||||
| 15 | (defn point [x y] {:type :Point :x x :y y}) | ||||
| 16 | |||||
| 17 | ; polygon :: Color -> [Point] -> Polygon | ||||
| 18 | (defn polygon [color points] {:type :Polygon :color color :points points}) | ||||
| 19 | |||||
| 20 | ; draw-polygon :: Graphics -> Polygon -> Nothing | ||||
| 21 | (defn draw-polygon [graphics polygon] | ||||
| 22 | (doto graphics | ||||
| 23 | (.setColor (new Color (:red (:color polygon)) | ||||
| 24 | (:blue (:color polygon)) | ||||
| 25 | (:green (:color polygon)) | ||||
| 26 | (:alpha (:color polygon)))) | ||||
| 27 | (.fillPolygon (let [jpolygon (new Polygon)] | ||||
| 28 | (doseq [p (:points polygon)] (. jpolygon (addPoint (:x p) (:y p)))) | ||||
| 29 | jpolygon))) | ||||
| 30 | nil) | ||||
| 31 | |||||
| 32 | ; ---------------------------------------------------------------------- | ||||
| 33 | ; This sections defines helper functions. | ||||
| 34 | |||||
| 35 | ; random-double :: Double | ||||
| 36 | (defn random-double | ||||
| 37 | "Returns a double between -1.0 and 1.0." | ||||
| 38 | [] | ||||
| 39 | (- (* 2 (rand)) 1)) | ||||
| 40 | |||||
| 41 | ; remove-item :: Sequence -> Integer -> Sequence | ||||
| 42 | (defn remove-item | ||||
| 43 | "Returns a sequence without the n-th item of s." | ||||
| 44 | [s n] | ||||
| 45 | (cond | ||||
| 46 | (vector? s) (into (subvec s 0 n) | ||||
| 47 | (subvec s (min (+ n 1) (count s)) (count s))) | ||||
| 48 | (list? s) (concat (take n s) | ||||
| 49 | (drop (inc n) s)))) | ||||
| 50 | |||||
| 51 | ; replace-item :: [a] -> Integer -> a -> [a] | ||||
| 52 | (defn replace-item | ||||
| 53 | "Returns a list with the n-th item of l replaced by v." | ||||
| 54 | [l n v] | ||||
| 55 | (concat (take n l) (list v) (drop (inc n) l))) | ||||
| 56 | |||||
| 57 | ; grab-pixels :: BufferedImage -> [Integer] | ||||
| 58 | (defn grab-pixels | ||||
| 59 | "Returns an array containing the pixel values of image." | ||||
| 60 | [image] | ||||
| 61 | (let [w (. image (getWidth)) | ||||
| 62 | h (. image (getHeight)) | ||||
| 63 | pixels (make-array (. Integer TYPE) (* w h))] | ||||
| 64 | (doto (new PixelGrabber image 0 0 w h pixels 0 w) | ||||
| 65 | (.grabPixels)) | ||||
| 66 | pixels)) | ||||
| 7a4839bc » | ynd | 2009-01-25 | 67 | ||
| 30723987 » | ynd | 2009-01-19 | 68 | ; ---------------------------------------------------------------------- | |
| 69 | ; This sections define the primitives of the genetic algorithm. | ||||
| 70 | |||||
| 226a8c84 » | ynd | 2009-01-24 | 71 | ; program :: S-Expression -> Maybe Integer -> Maybe BufferedImage -> Program | |
| 30723987 » | ynd | 2009-01-19 | 72 | (defn program [code fitness image] {:type :Program :code code :fitness fitness :image image}) | |
| 73 | |||||
| 74 | ; initial-program :: Program | ||||
| 226a8c84 » | ynd | 2009-01-24 | 75 | (def initial-program (program '(fn [graphics]) nil nil)) | |
| 30723987 » | ynd | 2009-01-19 | 76 | ||
| 77 | ; program-header :: Program -> S-Expression | ||||
| 78 | (defn program-header [p] (take 2 (:code p))) | ||||
| 79 | |||||
| 80 | ; program-expressions :: Program -> S-Expression | ||||
| 81 | (defn program-expressions [p] (drop (count (program-header p)) (:code p))) | ||||
| 82 | |||||
| 83 | ; mutate :: a -> Map -> a | ||||
| 84 | (defmulti mutate :type) | ||||
| 85 | |||||
| 86 | ; mutate :: Color -> Map -> Color | ||||
| 87 | (defmethod mutate :Color [c settings] | ||||
| 226a8c84 » | ynd | 2009-01-24 | 88 | (let [dr (int (* (:red c) (random-double))) | |
| 89 | dg (int (* (:green c) (random-double))) | ||||
| 90 | db (int (* (:blue c) (random-double))) | ||||
| 91 | da (int (* (:alpha c) (random-double)))] | ||||
| 30723987 » | ynd | 2009-01-19 | 92 | (assoc c :red (max (min (- (:red c) dr) 255) 0) | |
| 93 | :green (max (min (- (:green c) dg) 255) 0) | ||||
| 383db7b9 » | ynd | 2009-01-27 | 94 | :blue (max (min (- (:blue c) db) 255) 0) | |
| 651980f4 » | ynd | 2009-01-27 | 95 | :alpha (max (min (- (:alpha c) da) 255) 0)))) | |
| 30723987 » | ynd | 2009-01-19 | 96 | ||
| 97 | ; mutate :: Point -> Map -> Point | ||||
| 98 | (defmethod mutate :Point [p settings] | ||||
| 99 | (let [dx (int (* (:x p) (random-double))) | ||||
| 100 | dy (int (* (:y p) (random-double)))] | ||||
| 101 | (assoc p :x (max (min (- (:x p) dx) (:image-width settings)) 0) | ||||
| 102 | :y (max (min (- (:y p) dy) (:image-height settings)) 0)))) | ||||
| 103 | |||||
| 104 | ; mutate :: Polygon -> Map -> Polygon | ||||
| 105 | (defmethod mutate :Polygon [p settings] | ||||
| 106 | ; mutate-point :: Polygon -> Map -> Polygon | ||||
| 107 | (defn mutate-point [p settings] | ||||
| 108 | (let [n (rand-int (count (:points p)))] | ||||
| 109 | (assoc p :points (assoc (:points p) n (mutate (get (:points p) n) settings))))) | ||||
| 110 | |||||
| 111 | ; mutate-color :: Polygon -> Map -> Polygon | ||||
| 112 | (defn mutate-color [p settings] (assoc p :color (mutate (:color p) settings))) | ||||
| 113 | |||||
| 272a8352 » | ynd | 2009-01-20 | 114 | (let [roulette (rand-int 2)] | |
| 30723987 » | ynd | 2009-01-19 | 115 | (cond | |
| 272a8352 » | ynd | 2009-01-20 | 116 | (= 0 roulette) (mutate-point p settings) | |
| 117 | (= 1 roulette) (mutate-color p settings)))) | ||||
| 30723987 » | ynd | 2009-01-19 | 118 | ||
| 119 | ; mutate :: Program -> Map -> Program | ||||
| 120 | (defmethod mutate :Program [p settings] | ||||
| 121 | ; add-polygon :: Program -> Map -> Program | ||||
| 122 | (defn add-polygon [p settings] | ||||
| 123 | (assoc p :code | ||||
| 226a8c84 » | ynd | 2009-01-24 | 124 | (concat (:code p) | |
| 125 | [(list 'draw-polygon | ||||
| 126 | (first (nth (:code initial-program) 1)) | ||||
| 127 | (polygon | ||||
| 128 | (color (rand-int 255) (rand-int 255) (rand-int 255) (rand-int 255)) | ||||
| 129 | (vec (map | ||||
| 130 | (fn [n] | ||||
| 131 | (point | ||||
| 132 | (rand-int (:image-width settings)) | ||||
| 133 | (rand-int (:image-height settings)))) | ||||
| 134 | (range 5)))))]) | ||||
| 30723987 » | ynd | 2009-01-19 | 135 | :fitness nil :image nil)) | |
| 136 | |||||
| 137 | ; remove-polygon :: Program -> Map -> Program | ||||
| 138 | (defn remove-polygon [p settings] | ||||
| 226a8c84 » | ynd | 2009-01-24 | 139 | (let [n (rand-int (count (program-expressions p)))] | |
| 30723987 » | ynd | 2009-01-19 | 140 | (assoc p :code (concat (program-header p) | |
| 141 | (remove-item (program-expressions p) n)) | ||||
| 142 | :fitness nil :image nil))) | ||||
| 143 | |||||
| 144 | ; mutate-polygon :: Program -> Map -> Program | ||||
| 145 | (defn mutate-polygon [p settings] | ||||
| 146 | (let [expressions (program-expressions p) | ||||
| 226a8c84 » | ynd | 2009-01-24 | 147 | n (rand-int (count expressions)) | |
| 30723987 » | ynd | 2009-01-19 | 148 | target (nth expressions n)] | |
| 149 | (assoc p :code | ||||
| 150 | (concat (program-header p) | ||||
| 151 | (replace-item expressions | ||||
| 152 | n | ||||
| 153 | (list (nth target 0) | ||||
| 154 | (nth target 1) | ||||
| 155 | (mutate (nth target 2) settings)))) | ||||
| 156 | :fitness nil :image nil))) | ||||
| 157 | |||||
| 226a8c84 » | ynd | 2009-01-24 | 158 | (let [polygon-count (count (program-expressions p)) | |
| 30723987 » | ynd | 2009-01-19 | 159 | roulette (cond | |
| 226a8c84 » | ynd | 2009-01-24 | 160 | (empty? (program-expressions p)) 4 | |
| 161 | (>= polygon-count (:max-polygons settings)) (rand-int 4) | ||||
| 162 | :else (rand-int 5))] | ||||
| 30723987 » | ynd | 2009-01-19 | 163 | (cond | |
| 226a8c84 » | ynd | 2009-01-24 | 164 | (> 3 roulette) (mutate-polygon p settings) | |
| 165 | (= 3 roulette) (remove-polygon p settings) | ||||
| 166 | (= 4 roulette) (add-polygon p settings)))) | ||||
| 30723987 » | ynd | 2009-01-19 | 167 | ||
| 168 | ; fitness :: Program -> Map -> Program | ||||
| 169 | (defn fitness [individual settings] | ||||
| 170 | (if (:fitness individual) | ||||
| 171 | individual | ||||
| 172 | (let [gen-image (new BufferedImage (:image-width settings) | ||||
| 173 | (:image-height settings) | ||||
| 174 | BufferedImage/TYPE_INT_ARGB) | ||||
| 175 | src-pixels (:source-pixels settings)] | ||||
| 226a8c84 » | ynd | 2009-01-24 | 176 | (apply (eval (:code individual)) [(. gen-image (createGraphics))]) | |
| 30723987 » | ynd | 2009-01-19 | 177 | (def gen-pixels (grab-pixels gen-image)) | |
| 178 | (loop [i (int 0) | ||||
| 179 | lms (int 0)] | ||||
| 180 | (if (< i (alength gen-pixels)) | ||||
| 181 | (let [src-color (new Color (aget src-pixels i)) | ||||
| 182 | gen-color (new Color (aget gen-pixels i)) | ||||
| 183 | dr (- (. src-color (getRed)) (. gen-color (getRed))) | ||||
| 184 | dg (- (. src-color (getGreen)) (. gen-color (getGreen))) | ||||
| 185 | db (- (. src-color (getBlue)) (. gen-color (getBlue)))] | ||||
| 186 | (recur (unchecked-inc i) (int (+ lms (* dr dr) (* dg dg) (* db db ))))) | ||||
| 187 | (assoc individual :fitness lms :image gen-image)))))) | ||||
| 188 | |||||
| 189 | ; select :: [Program] -> Map -> [Program] | ||||
| 190 | (defn select [individuals settings] | ||||
| 191 | (take (:select-rate settings) | ||||
| 192 | (sort-by :fitness | ||||
| 193 | (pmap (fn [i] (fitness i settings)) | ||||
| 194 | individuals)))) | ||||
| 195 | |||||
| 196 | ; evolve :: Map -> Nothing | ||||
| 197 | (defn evolve [settings] | ||||
| 198 | (loop [i 0 | ||||
| 199 | population (list initial-program)] | ||||
| 200 | (let [fittest (select population settings) | ||||
| 201 | newborns (map (fn [i] (mutate i settings)) fittest)] | ||||
| 202 | ((:new-generation-callback settings (fn [a b])) i fittest) | ||||
| 203 | (when-not (= (first population) (first fittest)) | ||||
| 204 | ((:new-fittest-callback settings (fn [a b])) i fittest)) | ||||
| 205 | (recur (inc i) (concat fittest newborns))))) | ||||
| 206 | |||||
| 207 | ; ---------------------------------------------------------------------- | ||||
| 208 | ; This sections defines the graphical interface. | ||||
| 209 | |||||
| 210 | ; main :: Nothing | ||||
| 211 | (defn main [] | ||||
| 212 | (def file-chooser (new JFileChooser)) | ||||
| 213 | (doto file-chooser | ||||
| 214 | (.setCurrentDirectory (new File ".")) | ||||
| 215 | (.showOpenDialog nil)) | ||||
| 216 | |||||
| 217 | (let [jframe (new JFrame "Fittest Program") | ||||
| 218 | fittest (atom (list initial-program)) | ||||
| 219 | image (ImageIO/read (. file-chooser (getSelectedFile))) | ||||
| 220 | settings {:image-width (. image (getWidth)) | ||||
| 221 | :image-height (. image (getHeight)) | ||||
| 222 | :source-pixels (grab-pixels image) | ||||
| 223 | :select-rate 1 :max-polygons 50 | ||||
| 224 | :new-fittest-callback (fn [i f] | ||||
| 225 | (swap! fittest (fn [o n] n) f) | ||||
| 226 | (. jframe (repaint)))}] | ||||
| 227 | (doto jframe | ||||
| 228 | (.setSize (. image (getWidth)) (. image (getHeight))) | ||||
| 229 | (.add (proxy [JPanel] [] | ||||
| 230 | (paint [g] | ||||
| 231 | (doto g | ||||
| 232 | (.setColor Color/white) | ||||
| 233 | (.fillRect 0 0 (. image (getWidth)) (. image (getHeight))) | ||||
| 234 | (.drawImage (:image (first @fittest)) nil 0 0))))) | ||||
| 235 | (.setVisible true)) | ||||
| 236 | (evolve settings))) | ||||
| 237 | |||||
| 238 | (main) | ||||
