Skip to content

Instantly share code, notes, and snippets.

@amtal
Created May 30, 2011 10:08
Show Gist options
  • Save amtal/998684 to your computer and use it in GitHub Desktop.
Save amtal/998684 to your computer and use it in GitHub Desktop.
Conway's Life in Lisp Flavored Erlang...
;;; Global clock implementation of Life.
(defmodule life_sync_cell
(export (start_link 1) (set_neighbours 2) (tick 1)
(init 1) (handle_cast 2))
(using gen_server)
(behaviour gen_server))
(include-file "deps/lfe_utils/include/using.lfe")
;;; Exported:
;; Start a cell process and gets its pid.
(defun start_link (am-alive)
(gen_server:start_link 'life_sync_cell
(tuple am-alive (self))
'[]))
;; Tell cell about neighbouring pids.
(defun set_neighbours (pid ns)
(gen_server:cast pid `(add-ns ,ns)))
;; Global time step.
;;
;; Triggers a single alive|dead message to controller.
(defun tick (pid)
(gen_server:cast pid 'tick))
;;; Internals:
(defrecord state
life ; 'dead|'alive
master ; who to report life to
(ns '[]) ; known neighbour pids
(ns-alive 0) ; how many are alive
(ns-heard 0) ; how many checked in this time step: can not
; progress until all neighbours are heard
(tick-pending 'false))
(defun init
(((tuple am-alive master))
(tuple 'ok
(make-state life (if am-alive 'alive 'dead)
master master))))
(defun handle_cast
((`(add-ns ,ns) st) ; initialization
(broadcast st `(n-status ,(st-life st)))
(tuple 'noreply (set-st-ns st ns)))
((`(n-status ,x) st) ; neighbour alive/dead info
(let* (((st) (set-state st ns-alive (+ (count-change x) (st-ns-alive st))
ns-heard (+ 1 (st-ns-heard st))))
((st) (if (and (st-tick-pending st) (all-heard st))
(timetick st)
st)))
(tuple 'noreply st)))
(('tick st) ; global timestep request
(tuple 'noreply
(if (all-heard st)
(timetick st)
(set-st-tick-pending st 'true)))))
;; Step automaton.
(defun timetick (st)
(let* (((life) (: life is-alive (st-ns-alive st)))
((st) (set-state st ns-heard 0
ns-alive 0
tick-pending 'false
life life))
((pid) (self)))
(! (st-master st) (tuple 'life pid life))
st))
;; Broadcast a message to neighbouring cells.
(defun broadcast (state msg)
(lc ((<- n (st-ns state)))
(gen_server:cast n msg)))
;; Test if all neighbours reported their state yet.
(defun all-heard (st)
(== (st-ns-heard st)
(length (st-ns st))))
;; Neighbour count inc/dec.
(defun count-change
(('dead) 0)
(('alive) 1))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment