Conway's Game Of Life


+ Reply to Thread
Page 1 of 2 12 LastLast
Results 1 to 40 of 46
  1. #1
    Join Date
    Feb 2007
    Posts
    55

    Default 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. #2
    Join Date
    Jul 2003
    Posts
    2,358

    Default

    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!

  3. #3
    Join Date
    Feb 2007
    Posts
    55

    Default

    Thanks for your reply, this is roughly what i had in mind.

    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. #4
    Join Date
    Jul 2003
    Posts
    2,358

    Default

    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.

  5. #5
    Join Date
    Feb 2007
    Posts
    55

    Default

    Thanks for your reply

    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. #6
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959

    Default

    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,
    DT

  7. #7
    Join Date
    Feb 2007
    Posts
    55

    Default

    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
    '************************************************************************************************
    
    ADCON1 = %00000110	'all digital
    
    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. #8
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959

    Default

    That was fast.

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

  9. #9
    Join Date
    Feb 2007
    Posts
    55

    Default

    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. #10

    Default Re: Conway's Game Of Life NeoPixel

    Thread resurrection. Code help please.

    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. #11
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,235

    Default 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. #12

    Default 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. #13

    Default 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. #14

    Default 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
    	dead = 0                'Clears dead checksum 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
           dead = dead + InPtr
    	   else 
           NeoLed(OutPtr) = 0	
    	   ENDIF
          
         NEXT
      NEXT

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


  15. #15
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,235

    Default 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. #16
    Join Date
    May 2013
    Location
    australia
    Posts
    1,609

    Default 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
    This is more entertaining than Free to Air TV

  17. #17
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,235

    Default 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
           dead = dead + InPtr
    	   else 
           NeoLed(OutPtr) = 0	
    	   ENDIF
          
         NEXT
         NEXT

  18. #18
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,235

    Default Re: Conway's Game Of Life

    What size are all the different arrays?

  19. #19
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,235

    Default 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. #20

    Default 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. #21
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,235

    Default 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. #22

    Default 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. #23
    Join Date
    May 2013
    Location
    australia
    Posts
    1,609

    Default 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
    This is more entertaining than Free to Air TV

  24. #24
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,235

    Default 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. #25

    Default 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. #26
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,235

    Default 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. #27

    Default Re: Conway's Game Of Life

    Quote Originally Posted by HenrikOlsson View Post
    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. #28
    Join Date
    May 2013
    Location
    australia
    Posts
    1,609

    Default 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 ?
    This is more entertaining than Free to Air TV

  29. #29

    Default 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. #30
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,235

    Default 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
    We're trading readabillity for performance here...

  31. #31

    Default 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. #32

    Default 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
    	dead = 0                'Clears dead checksum 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
           dead = dead + InPtr
    	   else 
           NeoLed(OutPtr) = 0	
    	   ENDIF
          
         NEXT
         NEXT

  33. #33
    Join Date
    May 2013
    Location
    australia
    Posts
    1,609

    Default 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.
    This is more entertaining than Free to Air TV

  34. #34
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,235

    Default 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
               dead = dead + InPtr
            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
               dead = dead + InPtr
            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. #35

    Default Re: Conway's Game Of Life

    Quote Originally Posted by richard View Post
    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. #36

    Default 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. #37

    Default Re: Conway's Game Of Life

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

  38. #38

    Default 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
               dead = dead + InPtr
            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
               dead = dead + InPtr
            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. #39
    Join Date
    May 2013
    Location
    australia
    Posts
    1,609

    Default 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.
    This is more entertaining than Free to Air TV

  40. #40

    Default 256 Led Matrix running on 12F1840 Pic.

    As video.

    Colour 'Life' on tiny 12F1840.


Similar Threads

  1. programming jumping game
    By bokken in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 17th February 2012, 06:40
  2. Simon Game
    By flotulopex in forum Code Examples
    Replies: 1
    Last Post: - 4th November 2010, 06:25
  3. EEPROM life expectancy?
    By muddy0409 in forum General
    Replies: 3
    Last Post: - 1st May 2007, 12:44
  4. home brew game console W interface
    By PICMAN in forum General
    Replies: 1
    Last Post: - 15th March 2005, 22:25
  5. Game port to USB adaptor
    By Squibcakes in forum mel PIC BASIC Pro
    Replies: 0
    Last Post: - 24th September 2004, 03:16

Posting Permissions

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