// Credit to xdd (MIT MArch Year 3) for the setup of the pieces, over which I developed code.
// Thanks man, the LED Dots worked better than the LCD Screen!
#include <math.h> // For sqrtf
#define CLK 13
#define DIN 11
#define CS 10
#define X_SEGMENTS 4
#define Y_SEGMENTS 4
#define NUM_SEGMENTS (X_SEGMENTS * Y_SEGMENTS)
#define GRID_WIDTH 32 // 32x32 grid for 4 LED matrices (8x8 each)
#define GRID_HEIGHT 32
byte fb[8 * NUM_SEGMENTS]; // Framebuffer to hold LED matrix data
// Grids to store cell states for Game of Life
int grid[GRID_WIDTH][GRID_HEIGHT];
int nextGrid[GRID_WIDTH][GRID_HEIGHT];
// Function to shift data to all LED matrices
void shiftAll(byte send_to_address, byte send_this_data) {
digitalWrite(CS, LOW);
for (int i = 0; i < NUM_SEGMENTS; i++) {
shiftOut(DIN, CLK, MSBFIRST, send_to_address);
shiftOut(DIN, CLK, MSBFIRST, send_this_data);
}
digitalWrite(CS, HIGH);
}
void setup() {
Serial.begin(115200);
pinMode(CLK, OUTPUT);
pinMode(DIN, OUTPUT);
pinMode(CS, OUTPUT);
// Setup each MAX7219
shiftAll(0x0f, 0x00); // Display test register - test mode off
shiftAll(0x0b, 0x07); // Scan limit register - display digits 0 through 7
shiftAll(0x0c, 0x01); // Shutdown register - normal operation
shiftAll(0x0a, 0x0f); // Intensity register - max brightness
shiftAll(0x09, 0x00); // Decode mode register - no decode
// Initialize the grid with the R-pentomino pattern
initializeGrid();
// Clear the framebuffer before drawing
clear();
}
// Function to initialize the grid with the R-pentomino at the center
void initializeGrid() {
Serial.println(F("Initializing grid with the R-pentomino pattern"));
// Clear the entire grid first
for (int x = 0; x < GRID_WIDTH; x++) {
for (int y = 0; y < GRID_HEIGHT; y++) {
grid[x][y] = 0; // All cells dead initially
}
}
// Define the R-pentomino pattern
int centerX = GRID_WIDTH / 2;
int centerY = GRID_HEIGHT / 2;
// Coordinates of the R-pentomino (relative to center)
grid[centerX][centerY] = 1;
grid[centerX + 1][centerY] = 1;
grid[centerX - 1][centerY + 1] = 1;
grid[centerX][centerY + 1] = 1;
grid[centerX][centerY + 2] = 1;
}
// Function to count live neighbors for Game of Life
int countNeighbors(int x, int y) {
int sum = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
int col = (x + i + GRID_WIDTH) % GRID_WIDTH;
int row = (y + j + GRID_HEIGHT) % GRID_HEIGHT;
sum += grid[col][row];
}
}
sum -= grid[x][y]; // Subtract the cell itself
return sum;
}
// Function to update the grid according to Game of Life rules
void updateGrid() {
for (int x = 0; x < GRID_WIDTH; x++) {
for (int y = 0; y < GRID_HEIGHT; y++) {
int neighbors = countNeighbors(x, y);
// Apply the Game of Life rules
if (grid[x][y] == 1) {
// Cell dies if underpopulated or overpopulated
if (neighbors < 2 || neighbors > 3) {
nextGrid[x][y] = 0;
} else {
// Cell survives
nextGrid[x][y] = 1;
}
} else {
// Cell becomes alive if it has exactly 3 neighbors
if (neighbors == 3) {
nextGrid[x][y] = 1;
} else {
nextGrid[x][y] = 0;
}
}
}
}
// Copy nextGrid to grid
for (int x = 0; x < GRID_WIDTH; x++) {
for (int y = 0; y < GRID_HEIGHT; y++) {
grid[x][y] = nextGrid[x][y];
}
}
}
// Function to plot the grid on the LED matrix
void drawGrid() {
clear(); // Clear the framebuffer before drawing
for (int x = 0; x < GRID_WIDTH; x++) {
for (int y = 0; y < GRID_HEIGHT; y++) {
if (grid[x][y] == 1) {
// If the cell is alive, plot the pixel
safe_pixel(x, y, 1);
}
}
}
show(); // Update the LED matrix with the new framebuffer
}
// Main loop to draw the Game of Life and update generations
void loop() {
drawGrid(); // Draw the current grid state on the LED matrix
updateGrid(); // Update the grid according to the Game of Life rules
delay(100); // Add a delay for visual effect
}
// Function to set a pixel in the framebuffer
void set_pixel(uint8_t x, uint8_t y, uint8_t mode) {
byte *addr = &fb[x / 8 + y * X_SEGMENTS];
byte mask = 128 >> (x % 8);
switch (mode) {
case 0: // clear pixel
*addr &= ~mask;
break;
case 1: // plot pixel
*addr |= mask;
break;
case 2: // XOR pixel
*addr ^= mask;
break;
}
}
// Safely plot a pixel, ensuring it is within the grid bounds
void safe_pixel(uint8_t x, uint8_t y, uint8_t mode) {
if ((x >= X_SEGMENTS * 8) || (y >= Y_SEGMENTS * 8)) {
return;
}
set_pixel(x, y, mode);
}
// Clear all LEDs in the framebuffer
void clear() {
byte *addr = fb;
for (byte i = 0; i < 8 * NUM_SEGMENTS; i++) {
*addr++ = 0;
}
}
// Send the framebuffer to the LED matrix
void show() {
for (byte row = 0; row < 8; row++) {
digitalWrite(CS, LOW);
byte segment = NUM_SEGMENTS;
while (segment--) {
byte x = segment % X_SEGMENTS;
byte y = segment / X_SEGMENTS * 8;
byte addr = (row + y) * X_SEGMENTS;
if (segment & X_SEGMENTS) { // odd rows of segments
shiftOut(DIN, CLK, MSBFIRST, 8 - row);
shiftOut(DIN, CLK, LSBFIRST, fb[addr + x]);
} else { // even rows of segments
shiftOut(DIN, CLK, MSBFIRST, 1 + row);
shiftOut(DIN, CLK, MSBFIRST, fb[addr - x + X_SEGMENTS - 1]);
}
}
digitalWrite(CS, HIGH);
}
}
mega1:SCL
mega1:SDA
mega1:AREF
mega1:GND.1
mega1:13
mega1:12
mega1:11
mega1:10
mega1:9
mega1:8
mega1:7
mega1:6
mega1:5
mega1:4
mega1:3
mega1:2
mega1:1
mega1:0
mega1:14
mega1:15
mega1:16
mega1:17
mega1:18
mega1:19
mega1:20
mega1:21
mega1:5V.1
mega1:5V.2
mega1:22
mega1:23
mega1:24
mega1:25
mega1:26
mega1:27
mega1:28
mega1:29
mega1:30
mega1:31
mega1:32
mega1:33
mega1:34
mega1:35
mega1:36
mega1:37
mega1:38
mega1:39
mega1:40
mega1:41
mega1:42
mega1:43
mega1:44
mega1:45
mega1:46
mega1:47
mega1:48
mega1:49
mega1:50
mega1:51
mega1:52
mega1:53
mega1:GND.4
mega1:GND.5
mega1:IOREF
mega1:RESET
mega1:3.3V
mega1:5V
mega1:GND.2
mega1:GND.3
mega1:VIN
mega1:A0
mega1:A1
mega1:A2
mega1:A3
mega1:A4
mega1:A5
mega1:A6
mega1:A7
mega1:A8
mega1:A9
mega1:A10
mega1:A11
mega1:A12
mega1:A13
mega1:A14
mega1:A15
matrix1:V+
matrix1:GND
matrix1:DIN
matrix1:CS
matrix1:CLK
matrix1:V+.2
matrix1:GND.2
matrix1:DOUT
matrix1:CS.2
matrix1:CLK.2
matrix2:V+
matrix2:GND
matrix2:DIN
matrix2:CS
matrix2:CLK
matrix2:V+.2
matrix2:GND.2
matrix2:DOUT
matrix2:CS.2
matrix2:CLK.2
matrix3:V+
matrix3:GND
matrix3:DIN
matrix3:CS
matrix3:CLK
matrix3:V+.2
matrix3:GND.2
matrix3:DOUT
matrix3:CS.2
matrix3:CLK.2
matrix4:V+
matrix4:GND
matrix4:DIN
matrix4:CS
matrix4:CLK
matrix4:V+.2
matrix4:GND.2
matrix4:DOUT
matrix4:CS.2
matrix4:CLK.2