September 18, 2018
Just Juxt #35: Game of Life (4clojure #94)
The game of life is a cellular automaton devised by mathematician John Conway.
The ‘board' consists of both live (#) and dead ( ) cells. Each cell interacts with its eight neighbours (horizontal, vertical, diagonal), and its next state is dependent on the following rules:
- Any live cell with fewer than two live neighbours dies, as if caused by under-population.
- Any live cell with two or three live neighbours lives on to the next generation.
- Any live cell with more than three live neighbours dies, as if by overcrowding.
- Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
Write a function that accepts a board, and returns a board representing the next generation of cells.
(ns live.test
(:require [cljs.test :refer-macros [deftest is testing run-tests]]))
(defn conway [board]
(let [w (count (first board))
c (juxt quot mod)
g (set (keep-indexed #({\# (c % w)} %2)
(mapcat seq board)))
neighbours (fn [[x y]]
(for [dx [-1 0 1] dy (if (zero? dx) [-1 1] [-1 0 1])]
[(+ dx x) (+ dy y)]))
ng (set (for [[loc n] (frequencies (mapcat neighbours g))
:when (or (= n 3) (and (= n 2) (g loc)))]
loc))]
(->>
(range (* w (count board)))
(map #(if (ng (c % w)) \# " "))
(partition w)
(map #(apply str %)))))
(deftest conway-test
(is (= (conway [" "
" ## "
" ## "
" ## "
" ## "
" "])
[" "
" ## "
" # "
" # "
" ## "
" "]))
(is (= (conway [" "
" "
" ### "
" "
" "]))
[" "
" # "
" # "
" # "
" "])
(is (= (conway [" "
" "
" ### "
" ### "
" "
" "])
[" "
" # "
" # # "
" # # "
" # "
" "])))
(run-tests)