Since the use of math/array
came up recently in a topic here, I thought, I'll have a look at the package and see how difficult it would be to implement the game of life (Conway's Game of Life - Wikipedia) using it. Turns out it is pretty simple:
First, here is a function which encodes the game rules for an individual cell (this has nothing to do with math/array)
(define (game-rules cell neighbor-count)
(cond
;; Any live cell with fewer than two live neighbours dies, as if by
;; underpopulation.
((and (equal? cell 1) (< neighbor-count 2)) 0)
;; Any live cell with two or three live neighbors lives on to the next
;; generation.
((and (equal? cell 1) (or (= neighbor-count 2) (= neighbor-count 3))) 1)
;; Any live cell with more than three live neighbors dies, as if by
;; overpopulation.
((and (equal? cell 1) (> neighbor-count 3)) 0)
;; Any dead cell with exactly three live neighbours becomes a live cell,
;; as if by reproduction.
((and (equal? cell 0) (= neighbor-count 3)) 1)
;; All else, cell remains unchanged
(else cell)))
And here is the code to run the simulation, note that the code operates on arrays a whole, without referencing individual elements:
(define initial ;; initial configuration (this is a glider pattern)
(array
#[#[0 0 0 0 0 0 0 0 0 0]
#[0 0 1 0 0 0 0 0 0 0]
#[0 0 0 1 0 0 0 0 0 0]
#[0 1 1 1 0 0 0 0 0 0]
#[0 0 0 0 0 0 0 0 0 0]
#[0 0 0 0 0 0 0 0 0 0]
#[0 0 0 0 0 0 0 0 0 0]
#[0 0 0 0 0 0 0 0 0 0]
#[0 0 0 0 0 0 0 0 0 0]
#[0 0 0 0 0 0 0 0 0 0]]))
(define (rol a dimension) ; rotate left
(define n (vector-ref (array-shape a) dimension))
(append (list (sub1 n)) (build-list (sub1 n) values)))
(define (ror a dimension) ; rotate right
(define n (vector-ref (array-shape a) dimension))
(append (build-list (sub1 n) add1) '(0)))
(define shifts
`((,(::) ,(rol initial 1)) ; left
(,(::) ,(ror initial 1)) ; right
(,(rol initial 0) ,(::)) ; up
(,(ror initial 0) ,(::)) ; down
(,(rol initial 0) ,(rol initial 1)) ; up-left
(,(rol initial 0) ,(ror initial 1)) ; up-right
(,(ror initial 0) ,(rol initial 1)) ; down-left
(,(ror initial 0) ,(ror initial 1)) ; down-right
))
(define (neighbour-count a)
(define ns (map (lambda (shift) (array-slice-ref a shift)) shifts))
(apply array-map + ns))
(define (advance a) ;; advance the world one time unit
(array-map game-rules a (neighbour-count a)))
And here is what it looks like (this animation is with a more complex pattern):
Here is the full program: game-of-life.rkt · GitHub
Enjoy!
Alex.