Skip to content

Instantly share code, notes, and snippets.

@teropa
Created November 3, 2015 09:57
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save teropa/37bf6d41f0296259c683 to your computer and use it in GitHub Desktop.
Save teropa/37bf6d41f0296259c683 to your computer and use it in GitHub Desktop.
Conway's Life in ClojureScript
;; Credits:
;;
;; * ClojureScript
;; * Reagent https://reagent-project.github.io/
;; * Figwheel https://github.com/bhauman/lein-figwheel
;; * core.async https://clojure.github.io/core.async/
;; * Christophe Grand's Life implementation http://clj-me.cgrand.net/2011/08/19/conways-game-of-life/
(ns life.core
(:require [reagent.core :as r]
[cljs.core.async :refer [timeout <!]])
(:require-macros [cljs.core.async.macros :refer [go-loop]]))
;; Initial state, the "Blinker" lifeform
(defonce state (r/atom #{[-1 0] [0 0] [1 0]}))
; Also try the "R-Pentomimo": #{[-1 0] [-1 1] [0 -1] [0 0] [1 0]}
(defn neighbors
"Given a cell, return the collection of its neighbors in every direction"
[[x y]]
(for [dx [-1 0 1]
dy [-1 0 1]
:when (not= [dx dy] [0 0])]
[(+ x dx) (+ y dy)]))
(defn next-pop
"Given a population, return the next generation of it
following the rules of Conway's Life"
[pop]
(let [all-neighbors (mapcat neighbors pop)
neigh-count (frequencies all-neighbors)]
(set (for [[cell count] neigh-count
:when (or (= count 3)
(and (= count 2)
(pop cell)))]
cell))))
(defn evolve
"Begin a process of evolution. Will swap the state
to the next generation every 100ms"
[]
(go-loop []
(<! (timeout 100))
(swap! state next-pop)
(recur)))
(defn grid
"A React/Reagent component that renders life
to an SVG element"
[]
[:svg {:width 450
:height 450
:viewBox "-225 -225 450 450"}
(for [[x y] @state]
[:rect {:width 20
:height 20
:x (* x 20)
:y (* y 20)}])])
;; Render the grid component to the document
(r/render [grid] (.-body js/document))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment