Tiny Implementation of Conway’s Life…

March 22, 2015 | Arduino, Embedded, My Projects, My Stories | By: Mark VandeWettering

I had a few minutes, so I thought I’d try making a graphics demo that runs on the tiny little 0.96″ OLED display I mentioned last week. One of the first programs I ever wrote was an implementation of Conway’s Game of Life, having learned about it from Martin Gardner’s Mathematical Games column in Scientific American. I remember that on my old Atari 400, it took a couple of seconds at least per generation, at a resolution of just 40×20 or so. Because of the limited memory (and small size of the display) I decided a 96×64 resolution. There is just enough memory to handle two full sized bit buffers. With a bit more work, I could make it work at the full resolution of the OLED display, but you need to do some of the updates in place, which makes it a bit harder.

[sourcecode lang=”cpp”]
//
// a tiny implementation of Conway’s Life
// written by Mark VandeWettering (brainwagon@gmail.com)
// https://brainwagon.org
//

#include "U8glib.h"

#define XSIZE (128-32)
#define XSIZE_UINT8 (XSIZE/8)
#define YSIZE (64)

uint8_t current[YSIZE][XSIZE_UINT8] ;
uint8_t next[YSIZE][XSIZE_UINT8] ;

#define MODX(x) (((x)+XSIZE)%XSIZE)
#define MODY(y) (((y)+YSIZE)%YSIZE)

#define ISSET(a, x, y) \
(a[MODY(y)][MODX(x)/8] & (0x1<<(MODX(x)&7)))

#define SET(a, x, y) \
a[MODY(y)][MODX(x)/8] |= (0x1<<(MODX(x)&7))

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);

void
init()
{
int i, j ;
for (j=0; j<YSIZE; j++)
for (i=0; i<XSIZE_UINT8; i++)
current[j][i] = random(256) ;
}

void
setup()
{
randomSeed(analogRead(0));
init() ;
}

void
draw()
{
u8g.setDefaultBackgroundColor() ;
u8g.drawBox(0, 0, 128, 64) ;
u8g.setDefaultForegroundColor() ;
u8g.drawXBM(16, 0, XSIZE, YSIZE, (const uint8_t *) next) ;
}

void
loop()
{
int i, j ;

memset((void *) next, 0, sizeof(next)) ;
for (j=0; j<YSIZE; j++) {
for (i=0; i<XSIZE; i++) {
int sum = 0 ;
if (ISSET(current, i-1, j-1)) sum ++ ;
if (ISSET(current, i , j-1)) sum ++ ;
if (ISSET(current, i+1, j-1)) sum ++ ;
if (ISSET(current, i-1, j )) sum ++ ;
if (ISSET(current, i+1, j )) sum ++ ;
if (ISSET(current, i-1, j+1)) sum ++ ;
if (ISSET(current, i , j+1)) sum ++ ;
if (ISSET(current, i+1, j+1)) sum ++ ;

if (ISSET(current, i, j)) {
if (sum == 2 || sum == 3)
SET(next, i, j) ;
} else {
if (sum == 3)
SET(next, i, j) ;
}
}
}

memcpy((void *) current, (void *) next, sizeof(current)) ;

u8g.firstPage() ;
do {
draw() ;
} while (u8g.nextPage()) ;
}
[/sourcecode]

It works! It initializes the display to random values, and then runs Life. If the display gets boring, just hit the result button….


Comments

Comment from Dak
Time 3/24/2015 at 2:39 pm

Funny parallels: one of the first programs I wrote was Life. In, ah, Fortran. Had a loop detector, too.