Help with 8x8 LED matrix and MAX7219 code Conway's Game of Life (almost done)

Hello. I'm about half done with a project of making a 8x8 LED matrix and controlling it with a MAX7219 IC. I want it to run Conway's Game of Life and I'll make it into a wall hanging. I have tinkered with some code I found and got it mostly working. Can someone look over the code and tell me if (and how) it can be improved. I noticed that (in my video) the lower left LED if on, stays on till it starts over, when it looks as if it should be blinking with the others, and I don't know why. So I'm just looking for some advice. Much thanks. Here is my code and a link to a short video.

//Game of Life with MAX7219

/*

     * dataPin		pin on the Arduino where data gets shifted out
     * clockPin		pin for the clock
     * csPin		pin for selecting the device 
     * numDevices	maximum number of devices that can be controled
LedControl(int dataPin, int clkPin, int csPin, int numDevices=1);
*/
/*******************************************************************************/

#include "LedControl.h"     //Imports the library

LedControl lc=LedControl(12,11,10,1);

#define SIZEX 8             //Sets the X axis size
#define SIZEY 8             //Sets the Y axis size
#define reseedrate 30       //Sets the rate the world is re-seeded
#define brightness 15       //Values from 1 to 15 to set the brightness
long density = 35;          //Sets density % during seeding
unsigned long delaytime=150;  //Sets the time each generation is shown
int generation = 0;         //Counter for re-seeding
int analogPin = 0;          //analogPin for the random seed data
int world1[8][8] = {{0, 0, 0, 1, 0, 0, 0, 0},
                    {0, 0, 1, 0, 1, 0, 0, 0},
                    {0, 1, 0, 1, 1, 0, 0, 0},
                    {1, 0, 1, 0, 0, 1, 1, 0},
                    {0, 1, 1, 0, 0, 1, 0, 1},
                    {0, 0, 0, 1, 1, 0, 1, 0},
                    {0, 0, 0, 1, 0, 1, 0, 0},
                    {0, 0, 0, 0, 1, 0, 0, 0}};
int world2[8][8];

/*******************************************************************************/
/* display cells */

void display_cells(int world1[8][8])
{
  int i,j;
  for(i=0;i<SIZEX;i++)
  {
    for(j=0;j<SIZEY;j++)
    {
      lc.setLed(0,i,j,world1[i][j]);

    }
  }
}

/*******************************************************************************/
/* compute previous generation*/

void previous_generation(int world1[8][8],int world2[8][8])
{
  int i,j;

  for(i=0;i<SIZEX;i++)
  {
    for(j=0;j<SIZEY;j++)
    {
      world2[i][j]=world1[i][j];
    }
  }
}

/*******************************************************************************/
/* compute next generation */

void next_generation(int world1[8][8],int world2[8][8])
{
  int i,j;

  for(i=0;i<SIZEX;i++)
  {
    for(j=0;j<SIZEY;j++)
    {
      world1[i][j]=world2[i][j];
    }
  }
}

/*******************************************************************************/
/* compute neighborough cells */
#
void neighbours(int world1[8][8],int world2[8][8])
{
  int i,j,a;

  for(i=0;i<SIZEX;i++)
  {
    for(j=0;j<SIZEY;j++)
    {
      if((i==0)&&(j==0))
      {
        a=world1[i][j+1]+world1[i+1][j]+world1[i+1][j+1]+world1[i][69]+world1[i+1][69]+world1[19][j]+world1[19][j+1]+world1[19][69];
      }

      if((i!=0)&&(j!=0)&&(i!=(SIZEX-1))&&(j!=(SIZEY-1)))
      {
        a=world1[i-1][j-1]+world1[i-1][j]+world1[i-1][j+1]+world1[i][j+1]+world1[i+1][j+1]+world1[i+1][j]+world1[i+1][j-1]+world1[i][j-1];
      }
      
      if((i==0)&&(j!=0)&&(j!=(SIZEY-1)))
      {
        a=world1[i][j-1]+world1[i+1][j-1]+world1[i+1][j]+world1[i+1][j+1]+world1[i][j+1]+world1[19][j-1]+world1[19][j]+world1[19][j+1];
      }

      if((i==0)&&(j==(SIZEY-1)))
      {
        a=world1[i][j-1]+world1[i+1][j-1]+world1[i+1][j]+world1[i][0]+world1[i+1][0]+world1[19][0]+world1[19][j]+world1[19][j-1];
      }
      
      if((i==(SIZEX-1))&&(j==0))
      {
        a=world1[i-1][j]+world1[i-1][j+1]+world1[i][j+1]+world1[i][69]+world1[i-1][69]+world1[0][j]+world1[0][j+1]+world1[0][69];
      }
      
      if((i==(SIZEX-1))&&(j!=0)&&(j!=(SIZEY-1)))
      {
        a=world1[i][j-1]+world1[i][j+1]+world1[i-1][j-1]+world1[i-1][j]+world1[i-1][j+1]+world1[0][j]+world1[0][j-1]+world1[0][j+1];
      }
      
      if((i==(SIZEX-1))&&(j==(SIZEY-1)))
      {
        a=world1[i][j-1]+world1[i-1][j-1]+world1[i-1][j]+world1[0][j]+world1[0][j-1]+world1[i][0]+world1[i-1][0]+world1[0][0];
      }

      if((i!=0)&&(i!=(SIZEX-1))&&(j==0))
      {
        a=world1[i-1][j]+world1[i-1][j+1]+world1[i][j+1]+world1[i+1][j+1]+world1[i+1][j]+world1[i][69]+world1[i-1][69]+world1[i+1][69];
      }

      if((i!=0)&&(i!=(SIZEX-1))&&(j==(SIZEY-1)))
      {
        a=world1[i-1][j]+world1[i-1][j-1]+world1[i][j-1]+world1[i+1][j-1]+world1[i+1][j]+world1[i][0]+world1[i-1][0]+world1[i+1][0];
      }

      if((world1[i][j]==0)&&(a==3)){world2[i][j]=1;}
      if((world1[i][j]==1)&&((a==2)||(a==3))){world2[i][j]=1;}
      if((world1[i][j]==1)&&((a==1)||(a==0)||(a>3))){world2[i][j]=0;}
    }
  }
}

/*******************************************************************************/
/* randomize */

void seedWorld(int world1[8][8])
{
  int i,j;
  randomSeed(analogRead(analogPin));
  for(i=0;i<SIZEX;i++)
  {
    for(j=0;j<SIZEY;j++)
    {
      if (random(100) < density); {
    world1[i][j]=random(2);
      }
  }
  }
}

/*******************************************************************************/

void setup() {
   lc.shutdown(0,false);
   lc.setIntensity(0,brightness);
   lc.clearDisplay(0);
   seedWorld(world1);
}

/*******************************************************************************/

void loop()
{ 

   if (generation++ > reseedrate)
   {
     seedWorld(world1);
     lc.clearDisplay(0);
     delay(300);
     generation=0;
   }
     
    previous_generation(world1,world2);
    neighbours(world1,world2);
    next_generation(world1,world2);
    display_cells(world1);
    delay(delaytime);
    
  
}

My first recommendation would be to use 'unsigned char' instead of 'int' for each element of the arrays:

unsigned char world1[8][8] = {{0, 0, 0, 1, 0, 0, 0, 0},
                    {0, 0, 1, 0, 1, 0, 0, 0},
                    {0, 1, 0, 1, 1, 0, 0, 0},
                    {1, 0, 1, 0, 0, 1, 1, 0},
                    {0, 1, 1, 0, 0, 1, 0, 1},
                    {0, 0, 0, 1, 1, 0, 1, 0},
                    {0, 0, 0, 1, 0, 1, 0, 0},
                    {0, 0, 0, 0, 1, 0, 0, 0}};
unsigned char world2[8][8];

This will save 50% of the memory space.

Thanks for the tip John. I appreciate it. I'll make the change.

Has anyone else written a Conway's Game of Life for 8x8 with MAX7219? If someone else has a MAX7219 with a 8x8 set up, can you try my code and let me know what you think? What should be changed. It's not a big deal but there is that one LED that doesn't seem to play by the same rules, and I don't know why. Dose someone else notice, or have the same issue? I think GOL is fun to watch and once it's working well I can post instructions for others. Thanks a bunch.
Matt

GeekGuyMJ:
It's not a big deal but there is that one LED that doesn't seem to play by the same rules, and I don't know why. Dose someone else notice, or have the same issue?

The corner LEDs have a special code all of their own. I suspect that's where the problem is.

Where do the numbers "19" and "69" come from in that code? Seems to me like that would read memory outside the array...

That is a good question. I don't know why the 19s and 69s are there. I got the code from the forum http://arduino.cc/forum/index.php/topic,7091.0.html. It was the only example code for GOL with max7219 I could find. I tried to rework it the best I could to make more sense, but that whole section with 19s and 69s i don't understand. I also tried to rework the GOL code on Arduino Playground - DirectDriveLEDMatrix to work with max7219 and the ledcontrol.h library but could not get it working. I'm fairly new to the more complicated part of coding but i'm trying. I would appreciate any tips or any help anyone can offer in doing this.
Much thanks,
Matt

You can greatly simplify the neighbor calculations using modulo math:

/*******************************************************************************/
/* compute neighboring cells */

void neighbours(int world1[8][8],int world2[8][8])
{
  int a = 0;

  for(int i=0;i<SIZEX;i++)
  {
  int above = (i+SIZEX-1)%SIZEX;
  int below = (i+1)%SIZEX;

    for(int j=0;j<SIZEY;j++)
    {
    int left = (j+SIZEY-1)%SIZEY;
    int right = (j+1)%SIZEY

      a += world1[above][left];
      a += world1[above][j];
      a += world1[above][right]; 
      a += world1[i][left];
      a += world1[i][right]; 
      a += world1[below][left];
      a += world1[below][j];
      a += world1[below][right]; 

      if((world1[i][j]==0)&&(a==3)){world2[i][j]=1;}
      if((world1[i][j]==1)&&((a==2)||(a==3))){world2[i][j]=1;}
      if((world1[i][j]==1)&&((a==1)||(a==0)||(a>3))){world2[i][j]=0;}
    }
  }
}

Wow, John that is awesome. I'll test it out when I get home tonight. Thank you so much for you help.
Matt

Hi JohnWasser. I changed the int to unsigned char and that made the display work better. The corner led is now working.

I tried your "neighboring cells" code in place of the one I had but only one row blinked a bit. So it must be missing something, but I appreciated your time in writing it.

If there are any more recommendations to make the code better I'd be happy to hear them. This will be a walling hanging so if you have an idea to add something that is cool to look at and runs autonomously I'd love to hear about it.
Thanks
Matt