Arduino 8 Conway’s Game of Life

Arduino ProgrammingI tried to cover a ton in this tutorial. I’ll show how to use LCD Panels with Arduino. I then live code Conway’s Game of Life using an Arduino and a LCD Panel. Along the way we’ll create custom characters, convert from binary to base 10, generate random arrays, copy arrays and a whole lot more. I hope these functions will be useful in numerous personal projects you may have.

All of the code and a transcript follows the video below.

If you like videos like this, consider donating $1, or simply turn off Ad Blocking software. Either helps me pay for books and components I use to make these videos.

Code from the Video

// ----- DEMONSTRATES HOW LCD PANELS WORK -----
// Used to work with the LCD display
#include <LiquidCrystal.h>

// Setup the display by designating the pins used
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// Will draw a heart on the LCD display
// each number represents those leds lit on each row
// 00011 = 3 which means the last 2 leds are on 
byte heart[8] = {0, 10, 31, 31, 31, 14, 4, 0};

void setup() {
  Serial.begin(9600);
  // State that the display has 2 rows with 16 
  // characters per row
  lcd.begin(16, 2);

  // Create the heart character
  lcd.createChar(0, heart);

  // Move the cursor into position on the 1st line
  lcd.setCursor(0, 0);
  
  // Print to the LCD
  lcd.print("I ");

  // Print the heart
  lcd.write(byte(0));

  lcd.print(" LCDs");
}

void loop() {
  
}













#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

// Size we will use on the LCD panel
const int maxRows = 16;
const int maxCols = 20;

// Equals (maxCols/5) * 2
const int numOfChars = (maxCols/5) * 2;

/* Gameboard generated for 1 character looks like this
0 0 1 0 0
1 1 0 0 0
0 1 1 1 1
1 1 0 0 0
1 0 0 1 0
1 0 0 1 0
0 0 1 1 1
1 0 1 0 1
 */
bool gameBoard[maxRows][maxCols] = {};

/* To print a character to the LCD we pass a number
 *  that represents each row
 *  This represents the character above
4, 24, 15, 24, 18, 18, 7, 21
 */
byte golArray[numOfChars][8] = {};

// Will generate the values that go in the golArray
// by adding the values in the binary value while
// converting to base ten by multiplying versus
// these values 16, 8, 4, 2, 1
int GetLEDRowValue(byte ledRow, byte maxColumn){

  // Get the 1st columns index using the max as a guide
  int minColumn = maxColumn - 4;

  // Will hold the 5 digit value which represents which lights
  // to turn on for each row which makes up the character
  int ledValue = 0; 

  // Each time through multiply times 1, 2, 4, 8, 16 to convert
  // from binary
  int multiplier = 1;

  // Cycle through each binary value and convert to base 10
  for(int i = maxColumn; i >= minColumn; i--){
    ledValue += (gameBoard[ledRow][i] * multiplier);
    multiplier *= 2; 
  }
  return ledValue;
}

// Generate the 8 values that make up each character for each
// row that will be printed to the LCD display
void GenerateGolArray(){

  // The max column is 4 because the indexes go from 0 - 4
  // for each 5 digit line
  int maxCol = 4;
  for(int i = 0; i < numOfChars/2; i++){
    for(int j = 0; j < 8; j++){
      golArray[i][j] = GetLEDRowValue(j, maxCol);
    }

    // Jump to the next character to create
    maxCol += 5;
  }

  // Used for the 2nd row of characters to print 
  maxCol = 4;

  for(int i = (numOfChars/2); i < numOfChars; i++){ 
    for(int j = 0; j < 8; j++){

      golArray[i][j] = GetLEDRowValue(j+(numOfChars/2), maxCol);
      
    }
    maxCol += 5;
  }
}

// Create an array of 1s and 0s
void GenerateRandomArray(){
    randomSeed(analogRead(0));
    for(int a = 0; a < maxRows; a++){
        for(int b = 0; b < maxCols; b++){
            gameBoard[a][b] = random(0,2);
        }
    }
}

// Get the character data from the GOL array and print them
// on the LCD panel
void PrintChar(int charNum, int LCDCol, int LCDRow){

  // Get pointer to the array holding the character 
  // data array
  byte* temp = golArray[charNum];

  // Create character with the character number
  // and the character array data
  lcd.createChar(charNum, temp);

  // Put cursor in the right row and column and print
  lcd.setCursor(LCDCol,LCDRow);
  lcd.write(byte(charNum));

}

// Cycle through all characters to print on both rows of the LCD
// and print them with PrintChar()
void PrintToLCD(){
  
  int startCol = 0;
  for(int i = 0; i < (numOfChars/2); i++){

    // Print row 1 on LCD
    PrintChar(i, startCol, 0);

    // Print row 2 on LCD
    PrintChar(i + (numOfChars/2), startCol, 1);
    startCol++;
  }
}

// Make a copy of the array for updating the board
void CopyArray(bool gameBoard2[maxRows][maxCols]){
    for(int a =0; a < maxRows; a++)
    {
        for(int b = 0; b < maxCols; b++)
        {
          gameBoard2[a][b] = gameBoard[a][b];
        }
    }
}

// Any living cell with < 2 neighbores dies
// Any living cell with 2 or 3 neighbores lives
// Any living cell with > 3 neighbores dies
// A dead cell with exactly 3 neighbores is born
void UpdateBoard(){
    bool gameBoard2[maxRows][maxCols] = {};

    // Make a copy of the array
    CopyArray(gameBoard2);

    // Cycle through the columns of the array down
    for(int a = 0; a < maxRows; a++)
    {
        // Cycle through the rows of the array across
        for(int b = 0; b < maxCols; b++)
        {
            // We assume the cell is dead
            int numOfTrues = 0;

            // Used to check the value above and below the cell
            for(int c = -1; c < 2; c++)
            {
                // Used to check the value to the left and right of the cell
                for(int d = -1; d < 2; d++)
                {
                    // If we aren't checking the cell itself
                    if(!(c == 0 && d == 0))
                    {
                        // Each time their is a true on the top, bottom,
                        // right and left of the cell increment numOfTrues 
                        if(gameBoard2[a+c][b+d])
                        {
                          ++numOfTrues;
                        }
                    }
                }
            }

            // If their are less then 2 trues around the cell mark it as dead
            if(numOfTrues < 2){gameBoard[a][b] = false;}

            // If their is exactly 3 live cells mark it as alive
            else if(numOfTrues == 3){gameBoard[a][b] = true;}

            // If their are more then 3 live cells mark it as dead
            else if(numOfTrues > 3){gameBoard[a][b] = false;}
        }
    }
}

void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  GenerateRandomArray();
  GenerateGolArray();
  PrintToLCD();
}

void loop() {
  delay(500);
  UpdateBoard();
  GenerateGolArray();
  PrintToLCD();
}

Leave a Reply

Your email address will not be published. Required fields are marked *