Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@Electronza
Created December 13, 2019 09:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Electronza/f6f83daff7343482d6d8b9fa8280bb24 to your computer and use it in GitHub Desktop.
Save Electronza/f6f83daff7343482d6d8b9fa8280bb24 to your computer and use it in GitHub Desktop.
Arduino Game of Life
/*******************************************************************
____ __ ____ ___ ____ ____ __ __ _ ____ __
( __)( ) ( __)/ __)(_ _)( _ \ / \ ( ( \(__ ) / _\
) _) / (_/\ ) _)( (__ )( ) /( O )/ / / _/ / \
(____)\____/(____)\___) (__) (__\_) \__/ \_)__)(____)\_/\_/
Project name: Arduino: 16×8 game of life
Project page: https://electronza.com/arduino-16x8-game-of-life/
Description: Arduino Uno, Mikroe Arduino Uno click shield with two 8x8 B Click boards
********************************************************************/
#include <EEPROM.h>
#include "LedControl.h" // need the library
LedControl lc1=LedControl(11,13,9,1); //
LedControl lc2=LedControl(11,13,10,1); //
/** GAME OF LIFE
For an 16x8 LED matrix */
const int NUMROWS = 16;
const int NUMCOLS = 8;
/**
* Conditional compilation directives
*/
#define SHOW_STARTUP_SEQUENCE 1 // uncomment this line to enable the startup sequence
// The acorn
boolean gameBoard[NUMROWS][NUMCOLS] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 1, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
boolean newGameBoard[NUMROWS][NUMCOLS] = {
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0 },
};
/////////////////////////////////
void setup() {
Serial.begin(9600);
Serial.println("nBegin setup()");
lc1.shutdown(0,false);// turn off power saving, enables display
lc1.setIntensity(0,4);// sets brightness (0~15 possible values)
lc1.clearDisplay(0);// clear screen
lc2.shutdown(0,false);// turn off power saving, enables display
lc2.setIntensity(0,4);// sets brightness (0~15 possible values)
lc2.clearDisplay(0);// clear screen
delay(10000);
startupSequence();
lc1.clearDisplay(0);// clear screen
lc2.clearDisplay(0);// clear screen
delay(2000);
//setUpInitialBoard();
//newGameBoard=gameBoard;
Serial.println("End setup()n");
}
void loop() {
// Display the current game board for approx. 500ms
lc1.clearDisplay(0);// clear screen
lc2.clearDisplay(0);// clear screen
displayGameBoard();
delay(250);
// Calculate the next iteration
calculateNewGameBoard();
swapGameBoards();
}
/**
* Does a nice little animation to aid visual checks that all LEDs are correctly connected and operating.
* Lights every LED in each row, going back and forth across the rows, from top to bottom.
*/
void startupSequence() {
#ifdef SHOW_STARTUP_SEQUENCE
for (int row=0; row<8; row++) {
if (row%2 == 0) {
for (int col=0; col<NUMCOLS; col++) {
lc1.setLed(0,row,col,1);
delay(50);
lc1.setLed(0,row,col,0);
}
} else {
for (int col=NUMCOLS-1; col>=0; col--) {
lc1.setLed(0,row,col,1);
delay(50);
lc1.setLed(0,row,col,0);
}
}
}
for (int row=0; row<8; row++) {
if (row%2 == 0) {
for (int col=0; col<NUMCOLS; col++) {
lc2.setLed(0,row,col,1);
delay(50);
lc2.setLed(0,row,col,0);
}
} else {
for (int col=NUMCOLS-1; col>=0; col--) {
lc2.setLed(0,row,col,1);
delay(50);
lc2.setLed(0,row,col,0);
}
}
}
#endif // defined SHOW_STARTUP_SEQUENCE
}
/**
* Loops over all game board positions, and briefly turns on any LEDs for "on" positions.
*/
void displayGameBoard() {
for (byte row=0; row<NUMROWS; row++) {
for (byte col=0; col<NUMCOLS; col++) {
if (gameBoard[row][col]) {
if (row < 8){
lc1.setLed(0,row,col,1);}
else {
lc2.setLed(0,row-7,col,1);
}
}
}
}
}
/**
/**
* Counts the number of active cells surrounding the specified cell.
* Cells outside the board are considered "off"
* Returns a number in the range of 0 <= n < 9
*/
byte countNeighbors(byte row, byte col) {
byte count = 0;
for (char rowDelta=-1; rowDelta<=1; rowDelta++) {
for (char colDelta=-1; colDelta<=1; colDelta++) {
// skip the center cell
if (!(colDelta == 0 && rowDelta == 0)) {
if (isCellAlive(rowDelta+row, colDelta+col)) {
count++;
}
}
}
}
return count;
}
/**
* Returns whether or not the specified cell is on.
* If the cell specified is outside the game board, returns false.
*/
boolean isCellAlive(char row, char col) {
if (row < 0 || col < 0 || row >= NUMROWS || col >= NUMCOLS) {
return false;
}
return (gameBoard[row][col]== 1);
}
/**
* Encodes the core rules of Conway's Game Of Life, and generates the next iteration of the board.
* Rules taken from wikipedia.
*/
void calculateNewGameBoard() {
for (byte row=0; row<NUMROWS; row++) {
for (byte col=0; col<NUMCOLS; col++) {
byte numNeighbors = countNeighbors(row, col);
if (gameBoard[row][col]&& numNeighbors < 2) {
// Any live cell with fewer than two live neighbours dies, as if caused by under-population.
newGameBoard[row][col]= false;
} else if (gameBoard[row][col]&& (numNeighbors == 2 || numNeighbors == 3)) {
// Any live cell with two or three live neighbours lives on to the next generation.
newGameBoard[row][col]= true;
} else if (gameBoard[row][col]&& numNeighbors > 3) {
// Any live cell with more than three live neighbours dies, as if by overcrowding.
newGameBoard[row][col]= false;
} else if (!gameBoard[row][col]&& numNeighbors == 3) {
//} else if (gameBoard[row][col]&& numNeighbors == 3) {
// Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.
newGameBoard[row][col]= true;
} else {
// All other cells will remain off
newGameBoard[row][col]= false;
}
}
}
}
/**
* Copies the data from the new game board into the current game board array
*/
void swapGameBoards() {
for (byte row=0; row<NUMROWS; row++) {
for (byte col=0; col<NUMCOLS; col++) {
gameBoard[row][col]= newGameBoard[row][col];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment