Introduction: LED Matrix - Game of Life

This project will execute Conway's game of life on a 8x8 LED matrix.

It has 2 buttons, one for setting up a random field, the other to start or stop the iterations.

Step 1: Materials

  • An 8x8 LED matrix
  • 2x aprox. 1kOhm resistances
  • 2x buttons
  • cables
  • Arduino Mega 2560 (or similar)
  • Breadboard might be helpfull

Step 2: Connecting

Step 3: Code

//8x8 LED matrix row and column PINs
const int ROWS[8] = {52, 42, 53, 46, 39, 51, 41, 47};
const int COLUMNS[8] = {44, 43, 45, 50, 49, 48, 40, 38};
//button PINs
const int RANDOMIZE_BUTTON = 8;
const int START_BUTTON = 9;
//gloabal variables
bool started = false;
bool field[8][8] = {};
bool nextField[8][8] = {};
unsigned long lastMillis = 0;
void setup() {
  // setup all PINs
  for (int i = 0; i < 8; i++)
  {
    pinMode(ROWS[i], OUTPUT);
    pinMode(COLUMNS[i], OUTPUT);
  }
  pinMode(RANDOMIZE_BUTTON, INPUT);
  pinMode(START_BUTTON, INPUT);
}
void loop() {
  //read button states
  int randomizeButton = digitalRead(RANDOMIZE_BUTTON);
  int startButton = digitalRead(START_BUTTON);
  if (randomizeButton) {// stops and sets a random field
    started = false;
    for (int i = 0; i < 8; i++) {
      for (int j = 0; j < 8; j++) {
        field[i][j] = random(2);
      }
    }
    delay(200);
  } else if (startButton) {// starts or stops the iterations
    started = !started;
    delay(200);
  } else if (started) {
    //calculate next field
    if (millis() - 1000 > lastMillis) { //delay each iteration by 1000 milliseconds
      fillNextField();
      for (int y = 0; y < 8; y++) {
        for (int x = 0; x < 8; x++) {
          field[y][x] = nextField[y][x];
        }
      }
      lastMillis = millis();
    }
  }
  //refresh the 8x8 LED matrix
  refreshScreen();
}
//calculates the state of the next iteration
void fillNextField() {
  for (int y = 0; y < 8; y++) {
    for (int x = 0; x < 8; x++) {
      nextField[y][x] = getCellsNextState(x, y);
    }
  }
}
//returns the cell's next state, true if alive, false otherwise
bool getCellsNextState(int x, int y) {
  bool shouldBeAlive = false;
  shouldBeAlive |= (!field[y][x] && countAliveNeighbours(x, y) == 3);
  shouldBeAlive |= (field[y][x] && countAliveNeighbours(x, y) == 3);
  shouldBeAlive |= (field[y][x] && countAliveNeighbours(x, y) == 2);
  return shouldBeAlive;
}
// counts the alive neighbours this step
int countAliveNeighbours(int x, int y) {
  int retVal = 0;
  for (int row = y - 1; row <= y + 1; row++) {
    for (int col = x - 1; col <= x + 1; col++) {
      if ((row == y && col == x) || (row < 0) || (row > 7) || (col < 0) || (col > 7)) continue;
      if (field[row][col]) retVal++;
    }
  }
  return retVal;
}
//refreshes the 8x8 LED matrix
void refreshScreen() {
  // iterate over the rows (anodes):
  for (int row = 0; row < 8; row++) {
    // take the row pin (anode) high:
    digitalWrite(ROWS[row], HIGH);
    // iterate over the cols (cathodes):
    for (int col = 0; col < 8; col++) {
      // get the state of the current pixel;
      int thisPixel = field[row][col];
      // when the row is HIGH and the col is LOW,
      // the LED where they meet turns on:
      digitalWrite(COLUMNS[col], thisPixel ? LOW : HIGH);
      // turn the pixel off:
      if (thisPixel) {
        digitalWrite(COLUMNS[col], HIGH);
      }
    }
    // take the row pin low to turn off the whole row:
    digitalWrite(ROWS[row], LOW);
  }
}