Created
November 3, 2010 17:56
-
-
Save edbond/661431 to your computer and use it in GitHub Desktop.
Clojure 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
(ns clojure101.game_of_life | |
(:gen-class) | |
(:require [clojure.contrib.swing-utils :as swing] | |
[clojure.java.javadoc :as javadoc]) | |
(:use [clojure.contrib.pprint :only [pprint]]) | |
(:import [javax.swing JFrame JToolBar JButton] | |
[java.util EventObject])) | |
; (set! *warn-on-reflection* true) | |
(def running (ref false)) | |
(defn pp-field | |
[field padding] | |
(let [ones field ;(into {} (filter #(not (zero? (last %))) field)) | |
xx (->> (keys ones) (map first)) | |
yy (->> (keys ones) (map last)) | |
minx (- (apply min xx) padding) | |
maxx (+ (apply max xx) padding) | |
miny (- (apply min yy) padding) | |
maxy (+ (apply max yy) padding) | |
print-row (fn [y] | |
(println | |
(map #(get field [% y] 0) (range (inc minx) maxx))))] | |
(dorun (map #(print-row %) (range (inc miny) maxy))))) | |
(defn make-field | |
[ones] | |
(zipmap ones (repeat 1))) | |
(def blinker | |
(make-field [[1 2] [2 2] [3 2]])) | |
(def r-pentomino | |
(make-field [[1 2][2 1][2 2][2 3][3 1]])) | |
(defn next-state | |
"Returns next state for cell based on number of neighbors" | |
[state neighbors-count] | |
(cond | |
; Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction. | |
(and (= state 0) (= neighbors-count 3)) 1 | |
; Any live cell with two or three live neighbours lives on to the next generation. | |
(and (= state 1) (<= 2 neighbors-count 3)) 1 | |
; Any live cell with more than three live neighbours dies, as if by overcrowding. | |
; Any live cell with fewer than two live neighbours dies, as if caused by under-population. | |
:else 0)) | |
;; Neighbors functions | |
(defn neighbors | |
"Return neighbors indexes" | |
[field x y] | |
(let [indexes [[-1 -1] [-1 0] [-1 1] [0 -1] [0 1] [1 -1] [1 0] [1 1]] | |
xy (map (fn [[a b]] [(+ x a) (+ y b)]) indexes)] | |
xy)) | |
(defn neighbors-vals | |
"Return values for field in neighbor cells" | |
[field x y] | |
(let [neighbors (neighbors field x y)] | |
(map #(get field % 0) neighbors))) | |
(defn neighbors-sum | |
[field x y] | |
(reduce + (neighbors-vals field x y))) | |
(defn cell-next-state | |
[field x y] | |
(let [cell-val (get field [x y] 0) | |
neighbors-sum (neighbors-sum field x y)] | |
(next-state cell-val neighbors-sum))) | |
(defn next-population | |
"For each cell and it's neighbors get next state" | |
[field] | |
(let [cells (keys field) | |
cells-and-neighbors (mapcat (fn [[x y]] (neighbors field x y)) cells) | |
next-state (fn [acc [x y]] | |
(let [next-state (cell-next-state field x y)] | |
(if (= 1 next-state) | |
(assoc acc [x y] next-state) | |
acc)))] | |
(reduce next-state {} (distinct cells-and-neighbors)))) | |
(defn nth-population | |
[field n] | |
(if (zero? n) | |
field | |
(recur (next-population field) (dec n)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment