I spent an hour or two last night implementing a very simple ‘game of life’ on the parallax propeller embedded microcontroller. My plan is to construct the device using an 8×8 LED array, but for now the proof of context uses the prop’s built-in TV output support to write ones and zeroes to the television. It currently uses the random number generator to setup the game field, and degenerates to a flasher around iteration 250 or so. There’s also some code commented out that will create a slider or a toad.
Here are a couple of screenshots, one showing the game running on my generic clock controller board, connected to a LED matrix, and the other showing what it looks like on the TV:
The parallax website has another implementation of Game of Life, using the VGA driver and mouse support. I’ve not tried it, but the main loop is in prop assembly rather than spin, and is probably faster than my unoptimized brute-force implementation.
Below is the source code in spin (the parts for controlling the LED matrix are omitted, as they’re pretty specific to my hardware):
' Conway's Game of Life ' Implemented for the Parallax Propeller by Dr Scott M Baker ' http://www.smbaker.com/ CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 OBJ text : "TV_Text" CON rows = 8 cols = 8 pitch = cols+2 screensize = (rows+2) * (cols*2) VAR ' The current screen will be held in an array called "cur". ' It is large enough to hold (rows x cols) with an additional 1-cell border ' all the way around. The one-cell border is so that we can easily reflect ' the opposite side to get an infinite playfield. byte cur[ screensize ] byte work[ screensize ] long rnd PUB main text.Start(24) text.out($00) init tvloop PUB init | i, x repeat i from 1 to screensize byte[@cur + i] := 0 ' glider 'byte[@cur + 3*pitch + 5 ] := 1 'byte[@cur + 4*pitch + 3 ] := 1 'byte[@cur + 4*pitch + 5 ] := 1 'byte[@cur + 5*pitch + 4 ] := 1 'byte[@cur + 5*pitch + 5 ] := 1 ' toad 'byte[@cur + 3*pitch + 3 ] := 1 'byte[@cur + 3*pitch + 4 ] := 1 'byte[@cur + 3*pitch + 5 ] := 1 'byte[@cur + 4*pitch + 2 ] := 1 'byte[@cur + 4*pitch + 3 ] := 1 'byte[@cur + 4*pitch + 4 ] := 1 ' just do something random repeat i from 1 to 25 x := ?rnd if (x<0) x:=-x byte[ @cur + (x // screensize) ] := 1 ' copy reflect the edges of the game to the opposite sides (top goes to ' bottom, left to right, etc) PUB copyborder | i repeat i from 1 to cols byte[ @cur+ 0*pitch + i ] := byte [ @cur+ rows*pitch + i ] byte[ @cur+ (rows+1)*pitch + i ] := byte [ @cur+ 1*pitch + i ] repeat i from 1 to rows byte[ @cur+ i*pitch + 0 ] := byte [ @cur+ i*pitch + cols ] byte[ @cur+ i*pitch + (cols+1) ] := byte [ @cur+ i*pitch + 1 ] byte[ @cur+ 0*pitch + 0 ] := byte [ @cur+ rows*pitch + cols ] byte[ @cur+ 0*pitch + (cols+1) ] := byte [ @cur+ rows*pitch + 1 ] byte[ @cur+ (rows+1)*pitch + 0 ] := byte [ @cur+ 1*pitch + cols ] byte[ @cur+ (rows+1)*pitch + (cols+1)] := byte [ @cur+ 1*pitch + 1 ] ' update the game by applying the game of life rules. PUB update | r, c, live, liven, i, livec, changes, ptr copyborder livec := 0 changes := 0 repeat r from 1 to rows repeat c from 1 to cols live := byte [ @cur+ r*pitch + c ] ' count the number of live neighbors, starting with the top left corner ptr := @cur + (r-1) * pitch + (c-1) liven := byte[ptr] + byte[ptr+1] + byte[ptr+2] + byte[ptr+pitch] + byte[ptr+pitch+2] liven := liven + byte[ptr+pitch*2] + byte[ptr+pitch*2+1] + byte[ptr+pitch*2+2] if (live==1) and (liven>1) and (liven<4) ' if a live cell has 2-3 live neighbors, it stays live byte[ @work+ r*pitch + c ] := 1 livec := livec + 1 elseif (live==0) and (liven == 3) ' if a dead cell has exactly three neighbors, it becomes live byte[ @work+ r*pitch + c ] := 1 livec := livec + 1 changes := changes + 1 elseif (live==1) ' otherwise if a live cell has less than 2 it dies of starvation ' or greater than 4, it dies of overcrowding byte[ @work+ r*pitch + c ] := 0 changes := changes + 1 ' copy the work array back into the screen array repeat i from 0 to (screensize-1) byte[@cur + i] := byte[@work + i] ' if the whole game is dead, or if nothing is changing, restart if (livec == 0) or (changes == 0) init PUB tvloop | r, c, count count := 0 repeat update text.str(string($A, 1, $B, 1, "Conways Game of Life, www.smbaker.com")) text.str(string($A, 1, $B, 2, "Iterations:")) text.dec(count) text.out(13) repeat r from 1 to rows repeat c from 1 to cols text.dec( byte[ @cur + r*pitch + c ] ) text.out(13) count:=count+1 waitcnt( clkfreq/20 + cnt )