Conway's Game Of Life

# Thread: Conway's Game Of Life

1. ## Conway's Game Of Life

hello

after seeing a few youtube videos on 'Conway's game of life' id like to have a go at building one on a 8x8 led matrix to start with, then maybe something bigger later.

http://en.wikipedia.org/wiki/Conway's_Game_of_Life

im just looking for some advice on how to check each of the cell's neighbours are alive or dead without writing a shed load of IF/THEN statments for each cell (on a 8x8 led matrix there would be 64 cells with upto 8 neighbours for each cell)

2. If each LED is represented in a Bit Array, numbered from 0-63, from 0 at top left to 63 at bottom right, then, for any given LED 'x', it's neighbours are simply x-9, x-8, x-7, x-1, x+1, X+7, x+8 and x+9. The same routine can then be used on any cell in the array. Some extra code will have to account for display edges otherwise the patterns will 'wrap' out of one side of the screen and re-enter from the other... but then again that then will look like an interesting 'perpetual' colony!

so far i have come up with this bit of untryed code,
from the grid below if cell (x) 31 is alive, and you wish to check its neighbours: x-9, x-8, x-7, x-1, x+1, X+7, x+8 and x+9
you will end up checking 22, 23, 24,30,32,38,39,40
which almost works for wrapping around except 40 is too far away.

'0 8 16 24 32 40 48 56
'1 9 17 25 33 41 49 57
'2 10 18 26 34 42 50 58
'3 11 19 27 35 43 51 59
'4 12 20 28 36 44 52 60
'5 13 21 29 37 45 53 61
'6 14 22 30 38 46 54 62
'7 15 23 31 39 47 55 63

led var bit [64]
counter var byte
population var byte ' <<number of neighbours

FOR counter = 0 TO 63
population = 0
IF led [counter-1] = 1 AND counter > 0 THEN
population = population + 1
ENDIF
IF led [counter+1] = 1 AND counter < 63 THEN
population = population + 1
ENDIF
IF counter > 7 THEN
IF led [counter-8] = 1 THEN
population = population + 1
ENDIF
IF led [counter-9] = 1 THEN
population = population + 1
ENDIF
IF led [counter-7] = 1 THEN
population = population + 1
ENDIF
ENDIF
IF counter < 56 THEN
IF led [counter+8] = 1 THEN
population = population + 1
ENDIF
IF led [counter+9] = 1 THEN
population = population + 1
ENDIF
IF led [counter+7] = 1 THEN
population = population + 1
ENDIF
ENDIF
IF led [counter] = 1 THEN
IF population > 3 OR population < 2 THEN
led [counter] = 0
ENDIF
ENDIF
IF led [counter] = 0 THEN
IF population = 3 THEN
led [counter] = 1
ENDIF
ENDIF
NEXT

4. Well, 40 could be valid because (like for example the old Atari Asteroids game) you can wrap vertically as well as horizontally... if an Asteroid went off the top, it appeared at the bottom, and likewise when it went off one side, then it appeared on the other.

have come up with this:

i ended up allowing it to wrap vertically only which does keep the sequence of life going a bit longer..

6. I think you'll need to create 2 arrays.
One for the current generation, and one for the Next generation.

The way it is now, you scan across each location and determine whether it's alive or dead and immediately change it's state.

Then when you check the next location, it's making a decision based on the bit you just changed, which can't be considered until the next generation.

As you scan 1 generation, place the results in a holding array. Once the entire board has been scanned for a single generation, update the LED's, and use that array as the "current generation", or copy it back to the first array.

hth,

7. here is the code for it, using 2 arrays for the led data.

Code:
```' 8X8 LED MATRIX -- GAME OF LIFE --
' PIC16F872 External 4MHz Xtal Osc
' LED Matrix columns are conected to PORTC via ULN2004AN to 0v.
' RC0 - 1st column on left of display
' LED Matrix rows conected to PORTB via 100 ohm resistors (Resistor value dependant on LEDs used)
' RB0 - top row
' MCLR (pin1) connected via 4K7 to +5v supply.
' Push buttons conected to PORTA 3 and 4 with pull up resistors to +5v rail.
' By: DJW 20 June 2009
' Compiled with PicBasicPro
'************************************************************************************************

TRISA = %00011000 :TRISB = %00000000 :TRISC = %00000000

SYMBOL pushA	=	PORTA.3		'change pattern
SYMBOL pushB	=	PORTA.4		'start/stop game

leddata var byte [8] :led var bit [64] :lednew var bit [64]
population var byte :topedge var bit :botedge var bit :lefedge var bit :rigedge var	bit
alive var byte :temp var word :ledA var byte :ledB var byte :ledD var byte :ledC var byte
ledE var byte :ledF var byte :ledG var byte :ledH var byte :counter var byte :scan var byte

start:
RANDOM temp
leddata [0] = temp.lowbyte
leddata [1] = temp.highbyte
RANDOM temp
leddata [2] = temp.lowbyte
leddata [3] = temp.highbyte
RANDOM temp
leddata [4] = temp.lowbyte
leddata [5] = temp.highbyte
RANDOM temp
leddata [6] = temp.lowbyte
leddata [7] = temp.highbyte
loop:

FOR temp = 0 TO 1500
IF pushA = 0 THEN
PAUSE 200
GOTO START
ENDIF
IF pushB = 0 THEN
PAUSE 200
GOTO game
ENDIF
GOSUB display
NEXT
GOTO game

'-------------------------- DISPLAY LOOP ROUTINE -------------------------------------------------
display:
PORTC = 1
FOR counter = 0 TO 7
PORTB = leddata [counter]
PAUSE 1
PORTB = 0
PORTC = PORTC * 2
NEXT
RETURN

'------------------------ Read Cell data from display and store data bits in led array --------------------
GAME:
ledA = leddata[0] : ledB = leddata[1] : ledC = leddata[2] : ledD = leddata[3]
ledE = leddata[4] : ledF = leddata[5] : ledG = leddata[6] : ledH = leddata[7]
led [0] = ledA.0 :led [1] = ledA.1 :led [2] = ledA.2 :led [3] = ledA.3 :led [4] = ledA.4
led [5] = ledA.5 :led [6] = ledA.6 :led [7] = ledA.7 :led [8] = ledB.0 :led [9] = ledB.1
led [10] = ledB.2 :led [11] = ledB.3 :led [12] = ledB.4 :led [13] = ledB.5 :led [14] = ledB.6
led [15] = ledB.7 :led [16] = ledC.0 :led [17] = ledC.1 :led [18] = ledC.2 :led [19] = ledC.3
led [20] = ledC.4 :led [21] = ledC.5 :led [22] = ledC.6 :led [23] = ledC.7 :led [24] = ledD.0
led [25] = ledD.1 :led [26] = ledD.2 :led [27] = ledD.3 :led [28] = ledD.4 :led [29] = ledD.5
led [30] = ledD.6 :led [31] = ledD.7 :led [32] = ledE.0 :led [33] = ledE.1 :led [34] = ledE.2
led [35] = ledE.3 :led [36] = ledE.4 :led [37] = ledE.5 :led [38] = ledE.6 :led [39] = ledE.7
led [40] = ledF.0 :led [41] = ledF.1 :led [42] = ledF.2 :led [43] = ledF.3 :led [44] = ledF.4
led [45] = ledF.5 :led [46] = ledF.6 :led [47] = ledF.7 :led [48] = ledG.0 :led [49] = ledG.1
led [50] = ledG.2 :led [51] = ledG.3 :led [52] = ledG.4 :led [53] = ledG.5 :led [54] = ledG.6
led [55] = ledG.7 :led [56] = ledH.0 :led [57] = ledH.1 :led [58] = ledH.2 :led [59] = ledH.3
led [60] = ledH.4 :led [61] = ledH.5 :led [62] = ledH.6 :led [63] = ledH.7
temp = 0
'------------------------- Resets after 500 evolutions ---------------------------------------------------
gamestart:
temp = temp + 1
IF temp > 500 THEN
GOTO start
ENDIF
'------------------------ Checking each cells neighbours, counting neighbours in population ---------------
'----------------------- Also creating a newled data array to be displayed on next generation -------------
alive = 0
FOR counter = 0 TO 63
population = 0 :topedge	= 0 :botedge = 0 :lefedge = 0 :rigedge = 0
IF counter < 8 THEN
lefedge = 1
ENDIF
IF counter > 55 THEN
rigedge = 1
ENDIF
IF counter = 0 OR counter = 8 OR counter = 16 OR counter = 24 OR counter = 32 OR counter = 40 OR counter = 48 OR counter = 56 THEN
topedge = 1
ENDIF
IF counter = 7 OR counter = 15 OR counter = 23 OR counter = 31 OR counter = 39 OR counter = 47 OR counter = 55 OR counter = 63 THEN
botedge = 1
ENDIF
IF led [counter-1] = 1 AND counter > 0 THEN
population = population + 1
ENDIF
IF led [counter+1] = 1 AND counter < 63 THEN
population = population + 1
ENDIF
IF lefedge = 0 THEN
IF led [counter-8] = 1 THEN
population = population + 1
ENDIF
IF led [counter-9] = 1 AND topedge = 0 THEN
population = population + 1
ENDIF
IF led [counter-7] = 1 THEN
population = population + 1
ENDIF
ENDIF
IF rigedge = 0 THEN
IF led [counter+8] = 1 THEN
population = population + 1
ENDIF
IF led [counter+9] = 1 AND botedge = 0 THEN
population = population + 1
ENDIF
IF led [counter+7] = 1 THEN
population = population + 1
ENDIF
ENDIF
lednew [counter] = led [counter]
IF led [counter] = 1 THEN
IF population > 3 OR population < 2 THEN
lednew [counter] = 0
ENDIF
ENDIF
IF led [counter] = 0 THEN
IF population = 3 THEN
lednew [counter] = 1
ENDIF
ENDIF
NEXT
'-------------------------- Reloads led array with new generation data -----------------------------------
FOR counter = 0 TO 63
led [counter] = lednew [counter]
IF led [counter] = 1 THEN
alive = alive + 1
ENDIF
NEXT
'------------------------------ IF display blank, all cells dead then reset ------------------------------
IF alive = 0 THEN
GOTO start
ENDIF
'------------------------------ Covert led array bits into display column bytes -------------------------
'---------------------------------------- and send data to display --------------------------------------
ledA.0 = led [0] :ledA.1 = led [1] :ledA.2 = led [2] :ledA.3 = led [3] :ledA.4 = led [4] :ledA.5 = led [5]
ledA.6 = led [6] :ledA.7 = led [7] :ledB.0 = led [8] :ledB.1 = led [9] :ledB.2 = led [10] :ledB.3 = led [11]
ledB.4 = led [12] :ledB.5 = led [13] :ledB.6 = led [14] :ledB.7 = led [15] :ledC.0 = led [16]
ledC.1 = led [17] :ledC.2 = led [18] :ledC.3 = led [19] :ledC.4 = led [20] :ledC.5 = led [21]
ledC.6 = led [22] :ledC.7 = led [23] :ledD.0 = led [24] :ledD.1 = led [25] :ledD.2 = led [26]
ledD.3 = led [27] :ledD.4 = led [28] :ledD.5 = led [29] :ledD.6 = led [30] :ledD.7 = led [31]
ledE.0 = led [32] :ledE.1 = led [33] :ledE.2 = led [34] :ledE.3 = led [35] :ledE.4 = led [36]
ledE.5 = led [37] :ledE.6 = led [38] :ledE.7 = led [39] :ledF.0 = led [40] :ledF.1 = led [41]
ledF.2 = led [42] :ledF.3 = led [43] :ledF.4 = led [44] :ledF.5 = led [45] :ledF.6 = led [46]
ledF.7 = led [47] :ledG.0 = led [48] :ledG.1 = led [49] :ledG.2 = led [50] :ledG.3 = led [51]
ledG.4 = led [52] :ledG.5 = led [53] :ledG.6 = led [54] :ledG.7 = led [55] :ledH.0 = led [56]
ledH.1 = led [57] :ledH.2 = led [58] :ledH.3 = led [59] :ledH.4 = led [60] :ledH.5 = led [61]
ledH.6 = led [62] :ledH.7 = led [63]
leddata [0] = ledA :leddata [1] = ledB :leddata [2] = ledC :leddata [3] = ledD
leddata [4] = ledE :leddata [5] = ledF :leddata [6] = ledG :leddata [7] = ledH
FOR scan = 0 TO 20
IF pushB = 0 THEN
PAUSE 200
GOTO start
ENDIF
GOSUB display
NEXT
GOTO gamestart
END```
Last edited by wellyboot; - 21st June 2009 at 20:44.

8. That was fast.

Did it make a significant difference?
With it wrapping at the edges, I would imagine things stay "alive" much longer.
<br>

9. maybe too fast, ive noticed a mistake!

i didnt try it without the wrap around effect, as i do believe it would die a lot quicker.

but i did for example stop checking cell 40 as a neighbour to cell 31 as it over a column away from each other.

so for cell 31, i only check 30,22,23,38,39 and 24,32 (not cell+9 = 40)

and here is the mistake: I should check cell 16 (cell - 15)

'0 8 16 24 32 40 48 56
'1 9 17 25 33 41 49 57
'2 10 18 26 34 42 50 58
'3 11 19 27 35 43 51 59
'4 12 20 28 36 44 52 60
'5 13 21 29 37 45 53 61
'6 14 22 30 38 46 54 62
'7 15 23 31 39 47 55 63

but checking cell 40 wouldnt be such a bad thing as it would be a slightly diagonal wrapping around effect.

10. ## Re: Conway's Game Of Life NeoPixel

I'm working on this using a sequential 256 led neopixel string which is laid out in a prebuilt 16x16 matrix panel.

The neopixel string works fine but is like a snakes and ladder board in that starting from bottom left corner you go along the bottom up at the end of the row then back along then up a row and along etc etc. (Back and forth)

This arrangement is of course different to the actual LIFE array in PIC memory which is arranged as per the diagram.

So I want to transfer data from the Life byte array into the NeoPixel byte array adjusting the NeoPixel(address) when necessary.

The diagram might make it easier to see what i mean..

Code:
```'Life Array 16x16 in memory.     'Life Array 16x16 Neopixel Matrix String.

'         Top                                  Top
'240 -------------- 255             '255 -------------- 240
'224 -------------- 239             '224 -------------- 239
'208 -------------- 223             '223 -------------- 208
'192 -------------- 207             '192 -------------- 207
'176 -------------- 191             '191 -------------- 176
'160 --x----------- 175             '160 --x----------- 175
'144 ---x---------- 159             '159 ----------x--- 144
'128 -xxx---------- 143             '128 -xxx---------- 143
'112 -------------- 127             '127 -------------- 112
'96  -------------- 111              '96  -------------- 111
'80  -------------- 95               '95  -------------- 80
'64  -------------- 79               '64  -------------- 79
'48  -------------- 63               '63  -------------- 48
'32  -------------- 47               '32  -------------- 47
'16  -------------- 31               '31  -------------- 16
'0   -------------- 15                '0   -------------- 15
'        Bottom                              Bottom```
Hopefully you see the problem, I can't see an efficient way to transfer the data from the LIFE to the NEOPIXEL array whilst correcting the address on the alternate lines..

A simple Pixel(A) = Life(A) works for 0-15, 32-47 etc etc but not for 16-31, or 48-63 etc etc as the data ends up on the wrong part of the screen..

Any brilliant ideas.

You can see the problem on 144-159 with test data, it ends up on the wrong part of the screen.
Last edited by retepsnikrep; - 15th May 2020 at 10:41.

11. ## Re: Conway's Game Of Life

Here's an idea, untested, don't know if it compiles.
Code:
```InPtr VAR BYTE
OutPtr VAR BYTE

Row VAR BYTE
Col VAR BYTE

Even VAR BIT

Translate:
InPtr = 0

FOR Row = 0 to 15			' Cycle thru 16 rows
FOR Col = 0 to 15			' of 16 pixels each
IF Row.0 = 0 THEN		' If the row number is even
OutPtr = (Row*16) + Col        ' Output pixels in true order
ELSE
OutPtr = (Row*16) + (15-Col)   ' Output pixels in reversed order
ENDIF
NeoArray[OutPtr] = LifeArray[InPtr]
NEXT
NEXT
InPtr = InPtr + 1
RETURN```

12. ## Re: Conway's Game Of Life

Thanks Henrik that was just the kick start I needed.

Now to get the rest sorted..

Last edited by retepsnikrep; - 15th May 2020 at 13:06.

13. ## Re: Conway's Game Of Life

Still working on this.

Thanks to help with example code on this and other NeoPixel threads I now have a 1024 led.

Driving 1024 leds with (PIC 18F26K80) at just over 3hz

Need to work on optimizing the code, adding colour and generally enhancing the experience.

The four 8x32 leds strip are connected in series and fixed on the backboard of this nice neat white deep photo frame using double sided adhesive sheet.

The LEDS are a perfect fit in this \$10 ebay frame so highly recommended for similar projects.

White Shadow Box Photo Frame with Deep Mount 32 X 32cm

14. ## 1024 led Code optimisation: Conway's Game Of Life

This is progressing very nicely and I now have 1024 leds in colour.

In order to conserve RAM I got rid of two of the colour arrays for the NeoPixels and just kept a single array with RGB info in bits 5,6,7 and brightness info in bit 0-4.

So optimising code is my next priority.

The actual WS2812B led driving code is limited by strict timing protocols and is already in assembler so we will ignore that for now.

Evaluation of the 1024 grid life matrix must take some time so perhaps you can have a look at the code and if any glaring time sucking stuff leaps out make suggestions?

This part evaluates the primary 32 x 32 matrix and poulates a secondary 32 x 32 matrix with the updated information based on 'life' standard rules.

Code:
```'----------------------- Also creating a newled data array to be displayed on next generation -------------

FOR counter = 0 TO 1023

population = 0 :topedge = 0 :botedge = 0 :lefedge = 0 :rigedge = 0

'Grid Edge Detection

IF counter < 32 THEN botedge = 1

IF counter > 991 THEN topedge = 1

IF counter = 0 OR counter = 32 OR counter = 64 OR counter = 96 OR counter = 128 OR counter = 160 OR counter = 192 OR counter = 224_
or counter = 256 OR counter = 288 OR counter = 320 OR counter = 352 OR counter = 384 OR counter = 416 OR counter = 448 OR counter = 480_
or counter = 512 OR counter = 544 OR counter = 576 OR counter = 608 OR counter = 640 OR counter = 672 OR counter = 704 OR counter = 736_
or counter = 768 OR counter = 800 OR counter = 832 OR counter = 864 OR counter = 896 OR counter = 928 OR counter = 960 OR counter = 992_
THEN
lefedge = 1
ENDIF

IF counter = 31 OR counter = 63 OR counter = 95 OR counter = 127 OR counter = 159 OR counter = 191 OR counter = 223_
or counter = 255 OR counter = 287 OR counter = 319 OR counter = 351 OR counter = 383 OR counter = 415 OR counter = 447 OR counter = 479_
or counter = 511 OR counter = 543 OR counter = 575 OR counter = 607 OR counter = 639 OR counter = 671 OR counter = 703 OR counter = 735_
or counter = 767 OR counter = 799 OR counter = 831 OR counter = 863 OR counter = 895 OR counter = 927 OR counter = 959 OR counter = 991_
THEN
rigedge = 1
ENDIF

'Grid Evaluation

IF led [counter-1] > 0 AND counter > 0 THEN
Colour[population] = led[counter-1]
population = population + 1
ENDIF

IF led [counter+1] > 0 AND counter < 1023 THEN
Colour[population] = led[counter+1]
population = population + 1
ENDIF

IF botedge = 0 THEN
IF led [counter-31] > 0 THEN
Colour[population] = led[counter-31]
population = population + 1
ENDIF
IF led [counter-32] > 0 THEN
Colour[population] = led[counter-32]
population = population + 1
ENDIF
IF  rigedge = 0 and led [counter-33] > 0 THEN
Colour[population] = led[counter-33]
population = population + 1
ENDIF
ENDIF

IF topedge = 0 THEN
IF led [counter+31] > 0 THEN
Colour[population] = led[counter+31]
population = population + 1
ENDIF
IF led [counter+32] > 0 THEN
Colour[population] = led[counter+32]
population = population + 1
ENDIF
IF  rigedge = 0 and led [counter+33] > 0 THEN
Colour[population] = led[counter+33]
population = population + 1
ENDIF
ENDIF

lednew[counter] = led[counter]

IF led[counter] > 0 THEN
IF population > 3 OR population < 2 THEN
lednew[counter] = 0
ENDIF
ENDIF

IF led[counter] = 0 THEN
IF population = 3 THEN

if Colour[0] = Colour[1] then
lednew[counter] = Colour[0]

elseif Colour[0] = Colour[2] then
lednew[counter] = Colour[0]

elseif Colour[1] = Colour[2] then
lednew[counter] = Colour[1]

else

lednew[counter] = led[counter]     'White LED

endif

ENDIF
ENDIF
NEXT counter```

The second section moves data from the led matrix into the NeoPixel led array for display.
I previously posted about this due to the led matrix and NeoPixel matrix having a different layout.

It all works well at about 3hz but i'm looking for speed increases if possible.

Code:
```   	alive = 0	            'Clears alive accumulator

FOR Row = 0 to 31			' Cycle thru 32 rows

FOR Col = 0 to 31			' of 32 pixels each
InPtr = (Row * 32) + Col   '
led[InPtr] = lednew[InPtr]
IF Row.0 = 0 THEN	' If the row number is even
OutPtr =  InPtr        ' Output pixels in true order
ELSE
OutPtr = (Row * 32) + (31-Col)   ' Output pixels in reversed order
ENDIF

IF led[InPtr] > 0 THEN
NeoLed(OutPtr) = Led[InPtr]
alive = alive + 1
else
NeoLed(OutPtr) = 0
ENDIF

NEXT
NEXT```

The current colour code can be seen running in this short video.

15. ## Re: Conway's Game Of Life

Hi,
It might very well be that I don't quite understand what you're doing in the code but replacing all that OR logic with some math increases the performance in that particulat section of the code by a factor of 8 or so (won't help if it doesn't do what you want but by all means do try it):
Code:
```'----------------------- Also creating a newled data array to be displayed on next generation -------------

FOR counter = 0 TO 1023

population = 0 :topedge = 0 :botedge = 0 :lefedge = 0 :rigedge = 0

'Grid Edge Detection

Temp = Counter // 32

If Temp = 0 THEN
lefedge = 1
ENDIF

IF Temp = 31 THEN
rigedge = 1
ENDIF

'Grid Evaluation```
There's likely some cycles to squeze here and there but try the above for starters.

/Henrik.

16. ## Re: Conway's Game Of Life

would this work too ?

Temp = Counter & 65504
If Temp = 0 THEN
lefedge = 1
ENDIF

IF Temp = 31 THEN
rigedge = 1
ENDIF

17. ## Re: Conway's Game Of Life

Here's another tiny tweak to the array transformation routine that makes quite a difference:
Code:
```  FOR Row = 0 to 31			' Cycle thru 32 rows

TempW = ROW * 32       ' Precalculate this instead of doing it every time thru the loop

FOR Col = 0 to 31			' of 32 pixels each
InPtr = (TempW) + Col   '
led[InPtr] = lednew[InPtr]
IF Row.0 = 0 THEN	' If the row number is even
OutPtr =  InPtr        ' Output pixels in true order
ELSE
OutPtr = (TempW) + (31-Col)   ' Output pixels in reversed order
ENDIF

IF led[InPtr] > 0 THEN
NeoLed(OutPtr) = Led[InPtr]
alive = alive + 1
else
NeoLed(OutPtr) = 0
ENDIF

NEXT
NEXT```

18. ## Re: Conway's Game Of Life

What size are all the different arrays?

19. ## Re: Conway's Game Of Life

In the Grid Evalutaion section, precalculating the Array index values and replacing the AND-logic with nested IF/THEN saves Another bunch of cycles
Code:
```'Grid Evaluation

CntPlus33 VAR WORD
CntPlus32 VAR WORD
CntPlus31 VAR WORD
CntPlus1  VAR WORD

CntMinus33 VAR WORD
CntMinus32 VAR WORD
CntMinus31 VAR WORD
CntMinus1  VAR WORD

CntPlus33 = Counter + 33
CntPlus32 = Counter + 32
CntPlus31 = Counter + 31
CntPlus1 = Counter +1

CntMinus33 = Counter - 33
CntMinus32 = Counter - 32
CntMinus31 = Counter - 31
CntMinus1 = Counter - 1

IF led[CntMinus1] > 0 THEN
IF counter > 0 THEN
Colour[population] = led[CntMinus1]
population = population + 1
ENDIF
ENDIF

IF led[CntPlus1] > 0 THEN
IF counter < 1023 THEN
Colour[population] = led[CntPlus1]
population = population + 1
ENDIF
ENDIF

IF botedge = 0 THEN
IF led [CntMinus33] > 0 THEN
Colour[population] = led[CntMinus33]
population = population + 1
ENDIF
IF led [CntMinus32] > 0 THEN
Colour[population] = led[CntMinus32]
population = population + 1
ENDIF
IF  rigedge = 0 and led [CntMinus33] > 0 THEN
Colour[population] = led[CntMinus33]
population = population + 1
ENDIF
ENDIF

IF topedge = 0 THEN
IF led [CntPlus31] > 0 THEN
Colour[population] = led[CntPlus31]
population = population + 1
ENDIF
IF led [CntPlus32] > 0 THEN
Colour[population] = led[CntPlus32]
population = population + 1
ENDIF
IF  rigedge = 0 and led [CntPlus33] > 0 THEN
Colour[population] = led[CntPlus33]
population = population + 1
ENDIF
ENDIF```
It's not nearly as elegant but it does increase the performance a bit. All in all that 1024 iteration FOR/NEXT loop took 265ms to execute on my test board, now it's 67. Obviously I don't know if it still WORKS so it might all be for nothing :-)

/Henrik.

20. ## Re: Conway's Game Of Life

I'm very grateful for all these interesting replies. Thank you.

There are three basic 1024 element byte arrays.

Led var byte[1024] used to hold the current generation of cells

LedNew var byte [1024] used to to hold the next generation of cells (This is copied into the Led array after evaluation is completed)

NeoLed var byte [1024] used to hold the NeoPixel led data.

This third array is required because the layout of the NeoPixels grid is one continuous string of 1024 leds arranged like a snakes and ladders board.

This is different to the other two arrays which are a conventional X/Y grid layout, so the Led data has to be parsed and re-organised to display correctly on the neopixel grid.

How are people timing the loops etc.
I would be interested in that code so I can see what difference changes make.

21. ## Re: Conway's Game Of Life

There's also an array called colour, how large is that?

For this I just toggle an output and measure it with the scope but for more precise measurements I use one of the onboard timers. Reset it, start it, execute code, stop it, output its value.
Doing that it's important to have SOME idea about what you're measuring in order to set up the timer with proper prescaling value to make sure you don't overflow, giving you false readings.

22. ## Re: Conway's Game Of Life

I incorporated all those ideas and it is now running at over 13hz v 3hz before. Well done Team!

The Colour Array is only 8 elements and holds the colour of any adjacent cells to the one being tested.

Which of these two is technically quickest? Both seem to work well but I haven't got timing set up yet.

Code:
```  Temp = Counter // 32

If Temp = 0 THEN
lefedge = 1
ENDIF

IF Temp = 31 THEN
rigedge = 1
ENDIF```
or

Code:
```Temp = Counter & 65504
If Temp = 0 THEN
lefedge = 1
ENDIF

IF Temp = 31 THEN
rigedge = 1
ENDIF```

Here we have it at 13hz..

Last edited by retepsnikrep; - 23rd May 2020 at 13:48.

23. ## Re: Conway's Game Of Life

hmm i think i got that the wrong way round
try Temp = Counter & 31

the bitwise and is faster than a // which uses a divide

i wonder about led/LedNew arrays as byte . a cell is either dead or not dead a bit can store that info

24. ## Re: Conway's Game Of Life

Great that it all still works!
I timed it and Richards is a quite a bit quicker. On my test setup it went from 67 to 48ms which is not surprising since, generally speaking, anything involving division is a killer.
I also found that I had missed one AND statement, replaced that with nested IFs and I'm now measuring 44.7ms

25. ## Re: Conway's Game Of Life

That all works and I changed the AND statements.
Maybe 15hz now but I need to do some proper timing.

I wonder about led/LedNew arrays as byte . a cell is either dead or not dead a bit can store that info
The arrays also store LED RGB colour and brightness information so one bit is not sufficient.
The colour of a new cell is dependent on the adjacent three populated cells that spawn it.

26. ## Re: Conway's Game Of Life

From 3 to 15 frames per second in a couple of hours, I call that improvement.
At one place (at least) you first do IF LED[Counter] = 0 and then a couple of lines further down you do IF LED[Counter] > 0 which seems a bit of a wate since you already know if it IS 0 and if it's not it's got to be > 0 (since it can't be negative in case you're not using LONGs). There's also Population = Population + 1 in 8 places, can you move that outside each of the IF/THEN statements and only have ONE of them? That likely won't increase performance but will save space (if that matter at all).

We're probably talking microseconds here but since it all executes 1024 times per frame it does add up.

Anyhow, nice job and keep those updates and videos coming!

27. ## Re: Conway's Game Of Life

Originally Posted by HenrikOlsson
From 3 to 15 frames per second in a couple of hours, I call that improvement!
Thanks to all who have contributed so far.

I will post the complete code and circuit schematic etc when I have it finished and we can't eek out any more speed.

I tweaked if LED[Counter] = 0 and that gives another HZ I think.

Code space is not an issue. RAM Might be later.
Last edited by retepsnikrep; - 23rd May 2020 at 15:16.

28. ## Re: Conway's Game Of Life

last time i played with "life" i never found a way to detect a stable repetitive cycling pattern.
are you determining if boring stuck patterns ensue ?

29. ## Re: Conway's Game Of Life

For the big evaluation routine we currently have this giving about 15hz

Code:
```'----------------------- Also creating a newled data array to be displayed on next generation -------------

FOR counter = 0 TO 1023

population = 0 :topedge	= 0 :botedge = 0 :lefedge = 0 :rigedge = 0

'Grid Edge Detection

IF counter < 32 THEN botedge = 1

IF counter > 991 THEN topedge = 1

'*******************************************************************************

TempCount = Counter & 31
If TempCount = 0 THEN
lefedge = 1
ENDIF

IF TempCount = 31 THEN
rigedge = 1
ENDIF

'*******************************************************************************

'Grid Evaluation

CntPlus33 = Counter + 33
CntPlus32 = Counter + 32
CntPlus31 = Counter + 31
CntPlus1 = Counter +1

CntMinus33 = Counter - 33
CntMinus32 = Counter - 32
CntMinus31 = Counter - 31
CntMinus1 = Counter - 1

IF led[CntMinus1] > 0 THEN
IF counter > 0 THEN
Colour[population] = led[CntMinus1]
population = population + 1
ENDIF
ENDIF

IF led[CntPlus1] > 0 THEN
IF counter < 1023 THEN
Colour[population] = led[CntPlus1]
population = population + 1
ENDIF
ENDIF

IF botedge = 0 THEN
IF led [CntMinus31] > 0 THEN
Colour[population] = led[CntMinus31]
population = population + 1
ENDIF
IF led [CntMinus32] > 0 THEN
Colour[population] = led[CntMinus32]
population = population + 1
ENDIF
IF  rigedge = 0 then
if led [CntMinus33] > 0 THEN
Colour[population] = led[CntMinus33]
population = population + 1
endif
ENDIF
ENDIF

IF topedge = 0 THEN
IF led [CntPlus31] > 0 THEN
Colour[population] = led[CntPlus31]
population = population + 1
ENDIF
IF led [CntPlus32] > 0 THEN
Colour[population] = led[CntPlus32]
population = population + 1
ENDIF
IF  rigedge = 0 then
if led [CntPlus33] > 0 THEN
Colour[population] = led[CntPlus33]
population = population + 1
endif
ENDIF
ENDIF

lednew[counter] = led[counter]

IF led[counter] = 0 THEN
IF population = 3 THEN

if Colour[0] = Colour[1] then
lednew[counter] = Colour[0]

elseif Colour[0] = Colour[2] then
lednew[counter] = Colour[0]

elseif Colour[1] = Colour[2] then
lednew[counter] = Colour[1]

endif

ENDIF
else
IF population > 3 OR population < 2 THEN
lednew[counter] = 0
ENDIF

ENDIF

NEXT counter```
Last edited by retepsnikrep; - 23rd May 2020 at 15:20.

30. ## Re: Conway's Game Of Life

This shaved another 4ms off here, instead of:
Code:
```IF population > 3 OR population < 2 THEN
lednew[counter] = 0
ENDIF```
Do:
Code:
```IF Population > 3 THEN LEDNew[Counter] = 0
IF Population < 2 THEN LEDNew[Counter] = 0```

31. ## Re: Conway's Game Of Life

Thanks. All good stuff. I think we are getting near the limit.

The actual output to the WS2812B 1024 NeoPixel array is handled by the large mixed basic/assembler subroutine below.

I made a couple of small mods so it could work with 1024 leds and one data array holding the LED colour info encoded in bits 5,6,7 and brightness from 0-31 in bits 0-4.
I found brightness of 31 was really bright enough for daytime use and kept power supply requirements within reasonable wall wart limits.

So once the NeoLed array is loaded with the data this routine is called and loops until all 1024 led data has been output.

Code:
```NeoPixelASM64:'------------- subroutine call name ----------------
POINTER = NEO_NUM - 1	'THIS SCHEME USED TO ELIMINATE USING "< or >" COMPARE STATEMENTS
SCRATCH = NEO_NUM - 1	'THIS SCHEME USED TO ELIMINATE USING "< or >" COMPARE STATEMENTS

DOGREEN:
NeoPixel = SCRATCH - POINTER	'PUSH PIXELS FROM LOWEST to HIGHEST! DON'T ASK ME WHY?

NeoPixValue = NeoLed(NeoPixel)	'First, the Green array

'Colours %000 10000   (Bits 0-4 Intensity 32 steps 0-31 Default 31)  Bits 5-6-7 (001 Red D32) (010 Green D64) (100 Blue D128)

If NeoPixValue.6 = 1 then
NeoPixValue = NeopixValue & Brightness    'Clear Colour bits & set Green Intensity
else
NeoPixValue = 0                           'Turn LED Off
endif

NEOPIN = 1
ASM
btfsc   _NeoPixValue, 007h
Bra doneg70
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneg71
doneg70
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneg71
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 006h
Bra doneg60
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneg61
doneg60
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneg61
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 005h
Bra doneg50
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneg51
doneg50
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneg51
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 004h
Bra doneg40
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneg41
doneg40
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneg41
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 003h
Bra doneg30
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneg31
doneg30
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneg31
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 002h
Bra doneg20
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneg21
doneg20
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneg21
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 001h
Bra doneg10
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneg11
doneg10
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneg11
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 000h
Bra doneg00
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneg01
doneg00
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneg01
endasm

NeoPixValue = NeoLed(NeoPixel)     'Second, the Red array

'Colours %000 10000   (Bits 0-4 Intensity 32 steps 0-31 Default 31)  Bits 5-6-7 (001 Red D32) (010 Green D64) (100 Blue D128)

If NeoPixValue.5 = 1 then
NeoPixValue = NeoPixValue & Brightness        'Clear Colour bits & set Red Intensity
else
NeoPixValue = 0                           'Turn LED Off
endif

NEOPIN = 1
ASM
btfsc   _NeoPixValue, 007h
Bra doneb70
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneb71
doneb70
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneb71
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 006h
Bra doneb60
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneb61
doneb60
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneb61
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 005h
Bra doneb50
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneb51
doneb50
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneb51
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 004h
Bra doneb40
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneb41
doneb40
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneb41
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 003h
Bra doneb30
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneb31
doneb30
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneb31
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 002h
Bra doneb20
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneb21
doneb20
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneb21
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 001h
Bra doneb10
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneb11
doneb10
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneb11
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 000h
Bra doneb00
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doneb01
doneb00
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doneb01
endasm

NeoPixValue = NeoLed(NeoPixel)        'Lastly, the Blue array

'Colours %000 10000   (Bits 0-4 Intensity 32 steps 0-31 Default 31)  Bits 5-6-7 (001 Red D32) (010 Green D64) (100 Blue D128)

If NeoPixValue.7 = 1 then
NeoPixValue = NeoPixValue & Brightness    'Clear Colour bits & set Blue Intensity
else
NeoPixValue = 0                           'Turn LED Off
endif

NEOPIN = 1
ASM
btfsc   _NeoPixValue, 007h
Bra doner70
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doner71
doner70
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doner71
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 006h
Bra doner60
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doner61
doner60
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doner61
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 005h
Bra doner50
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doner51
doner50
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doner51
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 004h
Bra doner40
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doner41
doner40
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
;		Bcf LATA,3
NOP
NOP
NOP
NOP
NOP
NOP
doner41
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 003h
Bra doner30
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doner31
doner30
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doner31
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 002h
Bra doner20
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doner21
doner20
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doner21
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 001h
Bra doner10
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doner11
doner10
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doner11
ENDASM
NEOPIN = 1
ASM
btfsc   _NeoPixValue, 000h
Bra doner00
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
bra doner01
doner00
NOP
NOP
NOP
NOP
NOP
NOP
NOP
ENDASM
NEOPIN = 0
ASM
NOP
NOP
NOP
NOP
NOP
NOP
doner01
endasm
POINTER = POINTER - 1	'next pixel in the string
IF POINTER.15 = 0 THEN DOGREEN' < NEO_NUM THEN DOGREEN

return		'get back to main program.........```

32. ## Evaluate the Neopixel array directly

So a final effort to save 1024 bytes of RAM, one complete array, and perhaps give some increase in speed would be to be able to directly evaluate the odd neopixel array layout.

As I mentioned the Neopixel array is a physical snakes and ladders arrangement of 1024 series connected leds, starting 0 bottom left and ending 1023 top left of the grid.

The two life arrays are in the conventional x/y layout, starting 0 bottom left and finishing 1023 top right.

Currently once the Life array evaluation is completed it then has to be parsed and converted to fit the neopixel LED array layout.

If I could evaluate the Neopixel array directly we would save 1024 bytes and eliminate the parsing and conversion routine below, although I don't know how long that actually takes to execute.

Of course the evaluation routine would become more complicated, so the trade off speed benefits may be minimal or non existent. However even if speed worked out the same it would save the 1024 bytes of ram.

Code:
```   	alive = 0	            'Clears alive accumulator

FOR Row = 0 to 31			' Cycle thru 32 rows

TempW = ROW * 32       ' Precalculate this instead of doing it every time thru the loop

FOR Col = 0 to 31			' of 32 pixels each
InPtr = (TempW) + Col   '
led[InPtr] = lednew[InPtr]
IF Row.0 = 0 THEN	' If the row number is even
OutPtr =  InPtr        ' Output pixels in true order
ELSE
OutPtr = (TempW) + (31-Col)   ' Output pixels in reversed order
ENDIF

IF led[InPtr] > 0 THEN
NeoLed(OutPtr) = Led[InPtr]
alive = alive + 1
else
NeoLed(OutPtr) = 0
ENDIF

NEXT
NEXT```

33. ## Re: Conway's Game Of Life

i had a bit of a "google" for stagnant life pattern detection . the answer was obvious CRC
i resurrected my old code , added crc16 stored the last 8 crc's in a ring buffer. i then go on to check every new generation's
crc for existence in the buffer, more than two counts and i call it a repeat and begin a new pattern
works like a charm.

34. ## Re: Conway's Game Of Life

The array transform routine, as posted above executes in 4.66ms on my test hardware (18F46K42 @64MHz).
It's a small improvement but I managed to reduce that to 4.28ms by changing it into two FOR/NEXT loops, one for odd, one for even rows.
Code:
```    FOR Col = 0 To 30 Step 2
InPtr = (TempW + Col)
led[InPtr] = lednew[InPtr]
OutPtr = InPtr

IF led[InPtr] > 0 THEN
NeoLed(OutPtr) = Led[InPtr]
alive = alive + 1
ELSE
NeoLED(OutPtr) = 0
ENDIF
NEXT

FOR Col = 1 To 31 Step 2    ' Odd rows
InPtr = (TempW + Col)
led[InPtr] = lednew[InPtr]
OutPtr = (TempW) + (31-Col)   'Reversed order

IF led[InPtr] > 0 THEN
NeoLed(OutPtr) = Led[InPtr]
alive = alive + 1
ELSE
NeoLED(OutPtr) = 0
ENDIF
NEXT```
I must point out though that I don't have the arrays populated with anything so their values are always zero which obviously will have an effect.

35. ## Re: Conway's Game Of Life

Originally Posted by richard
last time i played with "life" i never found a way to detect a stable repetitive cycling pattern.
are you determining if boring stuck patterns ensue ?
Currently i'm using three things.

1) A simple maximum number of generations reset limit (500). That catches everything.

2) A simple live cell counter. If it's zero then it resets.

3) A pseudo checksum which seem to work quite well.

A word variable to which the address of every populated cell is added, it may overflow many times, and after all 1024 cells have been generated/examined you end up with a number.
It also calculates the checksum for the next generation and if it matches the previous generation then it probably means we have a stuck pattern and resets.

I've been testing this for thousands of patterns and generations now and it works well.
It only falls back on the hard generation limit with huge repeating patterns that cycle over several generations.
It detects small oscillators and stuck patterns etc quite well.

I appreciate it is possible for two patterns to have the same checksum but the odds must be very very small.

Cross post with Richard LOL!! Basically what I'm doing but I'm not quite as clever as the 'Life' experts.
Last edited by retepsnikrep; - 24th May 2020 at 11:24.

36. ## Re: Conway's Game Of Life

Thanks Henrick..

If the array transform only takes call it ~5ms per generation then at 15hz it's using 75ms in a second.
Roughly equivalent to one extra generation per second. Getting close to not much return for our efforts..

Do we think we can directly evaluate the Neopixel array with it's weird layout.. ?

I'm going to set my display up with some timing pins today and have a fiddle about.

Thanks for all the interesting replies.

37. ## Re: Conway's Game Of Life

Could I have a look at your Life CRC16 code please Richard?

38. ## Re: Conway's Game Of Life

To expand a little more on Henrick's last post, this gets it down to 3.51ms:
Code:
```tLED VAR BYTE

FOR Row = 0 to 31         ' Cycle thru 32 rows

TempW = ROW * 32       ' Precalculate this instead of doing it every time thru the loop

InPtr = TempW
FOR Col = 0 To 30 Step 2
tLED = lednew[InPtr]
led[InPtr] = tLED
OutPtr = InPtr
IF tLED > 0 THEN
NeoLed(OutPtr) = tLED
alive = alive + 1
ELSE
NeoLED(OutPtr) = 0
ENDIF
InPtr = InPtr + 2
NEXT

InPtr = TempW + 1
FOR Col = 1 To 31 Step 2    ' Odd rows
tLED = lednew[InPtr]
led[InPtr] = tLED
OutPtr = (TempW) + (31-Col)   'Reversed order
IF tLED > 0 THEN
NeoLed(OutPtr) = tLED
alive = alive + 1
ELSE
NeoLED(OutPtr) = 0
ENDIF
InPtr = InPtr + 2
NEXT
NEXT```
You could get similar reductions in the other sections of code by eliminating multiple evaluations of things like 'led[CntMinus1]'.
Every time it sees an array access using a variable it has to recompute the value of where it's pointing to.

If you assign the array value to a temp byte
Code:
`tLED = led[CntMinus1]`
and use that it saves a bunch of code/time. Obviously that only works for the RHS of an equation or a test, not the LHS.

39. ## Re: Conway's Game Of Life

this is my ccitt16 crc code , i feed every byte in the cell array into it and store result in ring buffer after first testing to see if the new crc exists more than once in the buffer buffer, if its there more than once [or twice if you like] thats it game over.

Code:
```this is a ccit 16 crc routine

crc var word
crc_in var byte
j var byte

to use   set crc  to \$ffff

then set crc_in to each value to be crc'ed
and gosub crc16

when finished crc hold the crc value

don't forget to reset crc to \$ffff for next time

crc16:
crc= crc ^  crc_in
for j=0 TO 7
if (crc&1)  THEN
crc= ((crc>>1) ^ \$a001 )   ;
else
crc= crc>>1;
ENDIF
NEXT
RETURN```
Last edited by richard; - 24th May 2020 at 12:10.

40. ## 256 Led Matrix running on 12F1840 Pic.

As video.

Colour 'Life' on tiny 12F1840.

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts