Skip to content

Instantly share code, notes, and snippets.

@edbond
Created November 3, 2010 17:56
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save edbond/661431 to your computer and use it in GitHub Desktop.
Save edbond/661431 to your computer and use it in GitHub Desktop.
Clojure game of life
(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