Elementary Cellular Light-Emitting Automaton

In response to an earlier post on driving an 8-bar LED using the Raspberry Pi, Roger Hui commented that 8 lights should be sufficient to display the output of a 1-d Game of Life. The code snippets displayed in this post are based on some working code that Roger was also kind enough to forward to me.

The following two functions provide the basic building blocks for the computation of the next generation of a 1-d cellular automaton:

bits←{(8⍴2)⊤⍵}           ⍝ Encode a number as 8 binary bits
neighbors←{↑¯1 0 1∘.⌽⊂⍵} ⍝ Map vector => 3-row matrix with neighbors

These allow us to perform the following transformations:

      bits 5
0 0 0 0 0 1 0 1
      bits 110
0 1 1 0 1 1 1 0
      neighbors b←0 1 0 0 1 1 1 1
1 0 1 0 0 1 1 1
0 1 0 0 1 1 1 1
1 0 0 1 1 1 1 0
      2⊥neighbors b ⍝ base-2 decode of each column
5 2 4 1 3 7 7 6

With these, it is now easy to define a function to compute the next generation of a pattern for a given Wolfram Code (and test it with a couple of arguments):

      wc←{(bits ⍺)[8-2⊥neighbors ⍵]}
      110 wc b
1 1 0 1 1 0 0 1
      110 wc 110 wc b ⍝ 3rd generation
0 1 1 1 1 0 1 1

We subtract the result of the base-2 decode from 8, because the least significant bit (bit 0) is the 8th element of the vector returned by the bits function. Next, we define an operator which returns a matrix containing a number of generations:

    ∇ r←gens(rule wcgm)pattern;i
[1] ⍝ Wolfram Code Generations
[2]
[3] r←(gens,⍴pattern)⍴pattern
[4] :For i :In 1↓⍳gens
[5]    r[i;]←rule wc r[i-1;]
[6] :EndFor
    ∇

    5 (110 wcg) b ⍝ 5 generations of code 110
0 1 0 0 1 1 1 1
1 1 0 1 1 0 0 1
0 1 1 1 1 0 1 1
1 1 0 0 1 1 1 1
0 1 0 1 1 0 0 0

Finally, we can add 1 to the boolean matrix and use it to index into a 2-element character vector, to get better “visualization” of the result (10 generations of Wolfram code 20):

      '-*'[1+10 (20 wcgm) b]
-*--****
-**-----
---*----
---**---
-----*--
-----**-
-------*
*------*
-*------
-**-----

The function also works with longer inputs – in the example below a random input of length 60 (20 generations of Wolfram code 18, this time using just blank and asterisk for the display):

     ' *'[1+20 (18 wcgm) 1=?60⍴2]
*****    * ***** *** ** *  * ***    *  *** *  ***  ** ***** 
     *  *                **     *  * **     **   **         
    * ** *              *  *   * **    *   *  * *  *        
   *      *            * ** * *    *  * * * **   ** *       
  * *    * *          *        *  * **        * *    *      
 *   *  *   *        * *      * **    *      *   *  * *     
* * * ** * * *      *   *    *    *  * *    * * * **   *    
              *    * * * *  * *  * **   *  *        * * *  *
*            * *  *       **   **    * * ** *      *     ** 
 *          *   ** *     *  * *  *  *        *    * *   *   
* *        * * *    *   * **   ** ** *      * *  *   * * *  
   *      *     *  * * *    * *       *    *   ** * *     **
* * *    * *   * **     *  *   *     * *  * * *      *   *  
     *  *   * *    *   * ** * * *   *   **     *    * * * **
*   * ** * *   *  * * *          * * * *  *   * *  *        
 * *        * * **     *        *       ** * *   ** *      *
    *      *      *   * *      * *     *      * *    *    * 
   * *    * *    * * *   *    *   *   * *    *   *  * *  * *
* *   *  *   *  *     * * *  * * * * *   *  * * * **   **   
   * * ** * * ** *   *     **         * * **        * *  * *

 

Finally, we can light the lights using the BarLED class from our GitHUB repository – and the Quick2Wire interface board and LED Bar – see the original post for an explanation. The video below shows the output resulting from the following APL expressions

      ]load /home/pi/BarLED
      bl←⎕NEW BarLED ⍬
      0.2 bl.Play ↓50(20 wcg) 0 1 0 0 1 1 1 1
      0.2 bl.Play ↓50(18 wcg) 0 1 0 0 1 1 1 1

Many thanks to Roger for the inspiration to take this one step further (and the code)! For a 2-dimensional implementation of Conway’s classic Game of Life, see the video by John Scholes at http://www.youtube.com/watch?v=a9xAKttWgP4.