# Game of Life using math/array

**URL:** https://racket.discourse.group/t/game-of-life-using-math-array/584
**Category:** Show & Tell
**Created:** [January 17, 2022, 1:16pm UTC](https://racket.discourse.group/t/game-of-life-using-math-array/584 "2022-01-17T13:16:59Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![alexh](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/alexh/32/315_2.png) [@alexh](https://racket.discourse.group/u/alexh)
#### Post date: [January 17, 2022, 1:16pm UTC](https://racket.discourse.group/t/game-of-life-using-math-array/584/1 "2022-01-17T13:16:59Z")

</div>

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](https://en.wikipedia.org/wiki/Conway's_Game_of_Life)) 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)

```scheme
(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:

```scheme
(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):

![gol](https://global.discourse-cdn.com/free1/uploads/racket/original/1X/56bfd64265a06a086255f6cf546bf0f9b33f16b3.gif)

Here is the full program: [game-of-life.rkt · GitHub](https://gist.github.com/alex-hhh/06d5e5429b50a60e5d25e301d4af3b4c)

Enjoy!  
Alex.

---

<div class="post-metadata">

### Author: ![Gambiteer](https://avatars.discourse-cdn.com/v4/letter/g/779978/32.png) [@Gambiteer](https://racket.discourse.group/u/Gambiteer)
#### Post date: [April 11, 2025, 6:54pm UTC](https://racket.discourse.group/t/game-of-life-using-math-array/584/2 "2025-04-11T18:54:24Z")

</div>

I like your code (especially your visualization), and referred to it in the SRFI 231 document.

I don't know much about these things, but my understanding is that `math/array` is written in Typed Racket and your program, which uses `math/array`, is written in (plain) Racket, and that interfacing between Typed and plain Racket introduces checks at the boundaries that slow down execution.

I'd be interested in a Typed Racket version of your program (at least for the computational kernel of it, maybe not for the visualization) that might eliminate those checks.

---

<div class="post-metadata">

### Author: ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)
#### Post date: [April 11, 2025, 7:52pm UTC](https://racket.discourse.group/t/game-of-life-using-math-array/584/3 "2025-04-11T19:52:46Z")

</div>

Here's a typed version. Annoyingly `(apply array-map ...)` can't be made to work (so I worked around it), and there were some required type annotations in the snip implementation that shouldn't have been needed. I haven't checked if it's faster:

> <https://gist.github.com/samth/900165ec595bbc5679f1384559841901>

---

<div class="post-metadata">

### Author: ![Gambiteer](https://avatars.discourse-cdn.com/v4/letter/g/779978/32.png) [@Gambiteer](https://racket.discourse.group/u/Gambiteer)
#### Post date: [April 12, 2025, 1:01am UTC](https://racket.discourse.group/t/game-of-life-using-math-array/584/4 "2025-04-12T01:01:32Z")

</div>

Thanks a lot! Comparing the two versions is very informative.

And it seems to be a lot faster; when I load the `#lang racket` version into drracket on my machine (v8.16.0.2 [cs]) , then

```scheme
(time (advance glider-gun))

```

takes

```scheme
cpu time: 58 real time: 58 gc time: 16

```

while your `#lang typed/racket` version takes

```scheme
cpu time: 1 real time: 1 gc time: 0

```

(and at least once all those times were 0 ms).

---

<div class="post-metadata">

### Author: ![Gambiteer](https://avatars.discourse-cdn.com/v4/letter/g/779978/32.png) [@Gambiteer](https://racket.discourse.group/u/Gambiteer)
#### Post date: [April 19, 2025, 6:39pm UTC](https://racket.discourse.group/t/game-of-life-using-math-array/584/5 "2025-04-19T18:39:57Z")

</div>

I put a version using Gambit and SRFI 231 as a gist here: [Conway's Game of Life in Gambit Scheme with SRFI 231 · GitHub](https://gist.github.com/gambiteer/6a3db87763f54934953130aa94db929a)

Your Typed Racket program and my Gambit program use different algorithms, but are of comparable speed: Advancing the state of `glider-gun` 100 times takes roughly 0.024 seconds in compiled Gambit and .064 seconds in Typed Racket.

Thanks again, I've been studying the implementation of `math/array` and this has been helpful
