diff --git a/src/config.h.sample b/src/config.h.sample index 8594eb23dd8b400069d91ae43a43ed86fe55a6a8..6bc7a599e147d7d2fb873ce75d211536c8c0c38f 100644 --- a/src/config.h.sample +++ b/src/config.h.sample @@ -1,3 +1,3 @@ #define WIFI_SSID "YourSSID" #define WIFI_PSK "YourPSK" -#define HOSTNAME "MatrixOfLife" \ No newline at end of file +#define HOSTNAME "MatrixOfLife" diff --git a/src/display.cpp b/src/display.cpp index fac11d2f637f78675213f8fbfd3d698553bf5591..c627dabc4fbcf9027fbc4d6daea0a280ad940ebb 100644 --- a/src/display.cpp +++ b/src/display.cpp @@ -2,16 +2,16 @@ #include "gameoflife.h" #include "display.h" -#define COLOR_DEPTH 24 // known working: 24, 48 - If the sketch uses type `rgb24` directly, COLOR_DEPTH must be 24 -const uint8_t kMatrixWidth = 64; // known working: 32, 64, 96, 128 -const uint8_t kMatrixHeight = 64; // known working: 16, 32, 48, 64 -const uint8_t kRefreshDepth = 24; // known working: 24, 36, 48 -const uint8_t kDmaBufferRows = 2; // known working: 2-4, use 2 to save memory, more to keep from dropping frames and automatically lowering refresh rate -const uint8_t kPanelType = SMARTMATRIX_HUB75_64ROW_MOD32SCAN; // use SMARTMATRIX_HUB75_16ROW_MOD8SCAN for common 16x32 panels -const uint8_t kMatrixOptions = (SMARTMATRIX_OPTIONS_NONE); // see http://docs.pixelmatix.com/SmartMatrix for options +#define COLOR_DEPTH 24 // known working: 24, 48 - If the sketch uses type `rgb24` directly, COLOR_DEPTH must be 24 +const uint8_t kMatrixWidth = 64; // known working: 32, 64, 96, 128 +const uint8_t kMatrixHeight = 64; // known working: 16, 32, 48, 64 +const uint8_t kRefreshDepth = 24; // known working: 24, 36, 48 +const uint8_t kDmaBufferRows = 2; // known working: 2-4, use 2 to save memory, more to keep from dropping frames and automatically lowering refresh rate +const uint8_t kPanelType = SMARTMATRIX_HUB75_64ROW_MOD32SCAN; // use SMARTMATRIX_HUB75_16ROW_MOD8SCAN for common 16x32 panels +const uint8_t kMatrixOptions = (SMARTMATRIX_OPTIONS_NONE); // see http://docs.pixelmatix.com/SmartMatrix for options const uint8_t kBackgroundLayerOptions = (SM_BACKGROUND_OPTIONS_NONE); -const int defaultBrightness = (10*255)/100; +const int defaultBrightness = (10 * 255) / 100; rgb24 colorWhite = {0xff, 0xff, 0xff}; rgb24 colorBlack = {0x00, 0x00, 0x00}; @@ -19,18 +19,22 @@ rgb24 colorBlack = {0x00, 0x00, 0x00}; SMARTMATRIX_ALLOCATE_BUFFERS(matrix, kMatrixWidth, kMatrixHeight, kRefreshDepth, kDmaBufferRows, kPanelType, kMatrixOptions); SMARTMATRIX_ALLOCATE_BACKGROUND_LAYER(backgroundLayer, kMatrixWidth, kMatrixHeight, COLOR_DEPTH, kBackgroundLayerOptions); -void setupDisplay() { - matrix.addLayer(&backgroundLayer); +void setupDisplay() +{ + matrix.addLayer(&backgroundLayer); matrix.begin(); matrix.setBrightness(defaultBrightness); backgroundLayer.enableColorCorrection(true); } -void displayLoop() { - if (runGame) { - gameOfLife(g); - for (int i = 0; i < SCREEN_HEIGHT; i++) { - for (int j = 0; j < SCREEN_WIDTH; j++) { +void displayLoop() +{ + if (runGame) + { + for (int i = 0; i < SCREEN_HEIGHT; i++) + { + for (int j = 0; j < SCREEN_WIDTH; j++) + { backgroundLayer.drawPixel(j, i, g[i][j] ? colorWhite : colorBlack); } } @@ -38,7 +42,8 @@ void displayLoop() { } } -void clearDisplay() { - backgroundLayer.fillScreen({0,0,0}); +void clearDisplay() +{ + backgroundLayer.fillScreen({0, 0, 0}); backgroundLayer.swapBuffers(); } diff --git a/src/display.h b/src/display.h index 9bfdd38295606fdc40d6744a752781c0d328b79b..777b26da8b5c5bc6adcc379f174aac5b57658d9b 100644 --- a/src/display.h +++ b/src/display.h @@ -1,14 +1,14 @@ #ifndef DISPLAY_H - #define DISPLAY_H +#define DISPLAY_H - #include <Arduino.h> - #include <MatrixHardware_ESP32_V0.h> - #include <SmartMatrix.h> +#include <Arduino.h> +#include <MatrixHardware_ESP32_V0.h> +#include <SmartMatrix.h> - extern bool runGame; +extern bool runGame; - void setupDisplay(); - void displayLoop(); - void clearDisplay(); +void setupDisplay(); +void displayLoop(); +void clearDisplay(); #endif diff --git a/src/gameoflife.cpp b/src/gameoflife.cpp index acb23efd8a431e52ea7c885aea43c2865713299e..a5da2560fd35c648a7b178275e09e71664d84328 100644 --- a/src/gameoflife.cpp +++ b/src/gameoflife.cpp @@ -7,62 +7,114 @@ int g[SCREEN_HEIGHT][SCREEN_WIDTH]; int arrayCopy[SCREEN_HEIGHT][SCREEN_WIDTH]; -void setupGameOfLife() { - randomSeed(analogRead(34)); - createRandomMatrix(g); - for (int i = 0; i < 10; i++) - addGlider(random(SCREEN_HEIGHT), random(SCREEN_WIDTH), g); - clearDisplay(); +bool runGame = true; + +int currentTick = 0; +int cellsAliveBefore = 0; +int cellsAliveNow = 0; +int noEvolutionTicks = 0; + +void setupGameOfLife() +{ + randomSeed(analogRead(34)); + createRandomMatrix(g); + for (int i = 0; i < 10; i++) + addGlider(random(SCREEN_HEIGHT), random(SCREEN_WIDTH), g); + clearDisplay(); + currentTick = 0; + cellsAliveBefore = 0; + noEvolutionTicks = 0; } -void createRandomMatrix(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]) { - for (int i = 0; i < SCREEN_HEIGHT; i++) { - for (int j = 0; j < SCREEN_WIDTH; j++) { - a[i][j] = random(100) < 25 ? 1 : 0; - } +void createRandomMatrix(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]) +{ + for (int i = 0; i < SCREEN_HEIGHT; i++) + { + for (int j = 0; j < SCREEN_WIDTH; j++) + { + a[i][j] = random(100) < 25 ? 1 : 0; } + } } -void gameOfLife(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]) { - for (int i = 0; i < SCREEN_HEIGHT; i++) { - for (int j = 0; j < SCREEN_WIDTH; j++) { - arrayCopy[i][j] = a[i][j]; - } +void gameOfLife(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]) +{ + currentTick++; + cellsAliveBefore = cellsAliveNow; + cellsAliveNow = 0; + for (int i = 0; i < SCREEN_HEIGHT; i++) + { + for (int j = 0; j < SCREEN_WIDTH; j++) + { + arrayCopy[i][j] = a[i][j]; } + } - for (int i = 0; i < SCREEN_HEIGHT; i++) { - for (int j = 0; j < SCREEN_WIDTH; j++) { - int total = (a[i][(j - 1) % SCREEN_WIDTH] + a[i][(j + 1) % SCREEN_WIDTH] + a[(i - 1) % SCREEN_HEIGHT][j] + - a[(i + 1) % SCREEN_HEIGHT][j] + a[(i - 1) % SCREEN_HEIGHT][(j - 1) % SCREEN_WIDTH] + - a[(i - 1) % SCREEN_HEIGHT][(j + 1) % SCREEN_WIDTH] + - a[(i + 1) % SCREEN_HEIGHT][(j - 1) % SCREEN_WIDTH] + - a[(i + 1) % SCREEN_HEIGHT][(j + 1) % SCREEN_WIDTH]); + for (int i = 0; i < SCREEN_HEIGHT; i++) + { + for (int j = 0; j < SCREEN_WIDTH; j++) + { + int total = (a[i][(j - 1) % SCREEN_WIDTH] + a[i][(j + 1) % SCREEN_WIDTH] + a[(i - 1) % SCREEN_HEIGHT][j] + + a[(i + 1) % SCREEN_HEIGHT][j] + a[(i - 1) % SCREEN_HEIGHT][(j - 1) % SCREEN_WIDTH] + + a[(i - 1) % SCREEN_HEIGHT][(j + 1) % SCREEN_WIDTH] + + a[(i + 1) % SCREEN_HEIGHT][(j - 1) % SCREEN_WIDTH] + + a[(i + 1) % SCREEN_HEIGHT][(j + 1) % SCREEN_WIDTH]); - if (a[i][j] == 1) { - if (total < 2 || total > 3) { - arrayCopy[i][j] = 0; - } - } else if (total == 3) { - arrayCopy[i][j] = 1; - } + if (a[i][j] == 1) + { + if (total < 2 || total > 3) + { + arrayCopy[i][j] = 0; } + } + else if (total == 3) + { + arrayCopy[i][j] = 1; + cellsAliveNow++; + } } + } - for (int i = 0; i < SCREEN_HEIGHT; i++) { - for (int j = 0; j < SCREEN_WIDTH; j++) { - a[i][j] = arrayCopy[i][j]; - } + for (int i = 0; i < SCREEN_HEIGHT; i++) + { + for (int j = 0; j < SCREEN_WIDTH; j++) + { + a[i][j] = arrayCopy[i][j]; } + } + + if (cellsAliveNow == cellsAliveBefore) + { + noEvolutionTicks++; + } + else + { + noEvolutionTicks = 0; + } + + if (noEvolutionTicks > noEvolutionTicksLimit) + { + setupGameOfLife(); + } } -void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]) { - // 010 - // 001 - // 111 - int glider[3][3] = {{0, 0, 1}, {1, 0, 1}, {0, 1, 1}}; - for (int i = 0; i < 3; i++) { - for (int j = 0; j < 3; j++) { - a[i1 + i][j1 + j] = glider[i][j]; - } +void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]) +{ + // 010 + // 001 + // 111 + int glider[3][3] = {{0, 0, 1}, {1, 0, 1}, {0, 1, 1}}; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + a[i1 + i][j1 + j] = glider[i][j]; } + } +} + +void gameLoop() +{ + if (runGame) + gameOfLife(g); } diff --git a/src/gameoflife.h b/src/gameoflife.h index af7a0dda21c4a88a91e564a07e984d2fe65fbab8..3b84e7642b9bd1e35c3c7937361630fe947ef8c4 100644 --- a/src/gameoflife.h +++ b/src/gameoflife.h @@ -1,17 +1,21 @@ #ifndef GAMEOFLIFE_H - #define GAMEOFLIFE_H +#define GAMEOFLIFE_H - #include <Arduino.h> +#include <Arduino.h> - #define SCREEN_WIDTH 64 - #define SCREEN_HEIGHT 64 +#define SCREEN_WIDTH 64 +#define SCREEN_HEIGHT 64 - extern int g[SCREEN_HEIGHT][SCREEN_WIDTH]; - extern int arrayCopy[SCREEN_HEIGHT][SCREEN_WIDTH]; - - void setupGameOfLife(); - void createRandomMatrix(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]); - void gameOfLife(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]); - void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]); +extern int g[SCREEN_HEIGHT][SCREEN_WIDTH]; +extern int arrayCopy[SCREEN_HEIGHT][SCREEN_WIDTH]; + +extern bool runGame; +extern int noEvolutionTicksLimit; + +void setupGameOfLife(); +void createRandomMatrix(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]); +void gameOfLife(int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]); +void addGlider(int i1, int j1, int (&a)[SCREEN_HEIGHT][SCREEN_WIDTH]); +void gameLoop(); #endif diff --git a/src/main.cpp b/src/main.cpp index f54fa708d5b7c99ca2f6ef945803e577b865132e..d30ed7a22ecec9c20b22594387b655729f372ef8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,20 +1,23 @@ #include <Arduino.h> #include "utils.h" #include "network.h" -#include "gameoflife.h" #include "display.h" +#include "gameoflife.h" -bool runGame = true; +int noEvolutionTicksLimit = 100; -void setup() { +void setup() +{ Serial.begin(115200); - logLine("", true); + logLine("", true); setupNetwork(); setupDisplay(); setupGameOfLife(); } -void loop() { +void loop() +{ networkLoop(); + gameLoop(); displayLoop(); } diff --git a/src/network.cpp b/src/network.cpp index 1ac9cd0c2a813c139131873549be763eacc19114..50440d9e0e5ab9303a0375981ad0c7d7ab17dc29 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -6,58 +6,69 @@ AsyncWebServer server(80); MDNSResponder mdns; -void setupNetwork() { - setupWifi(); - setupMDNS(); - setupOTA(); +void setupNetwork() +{ + setupWifi(); + setupMDNS(); + setupOTA(); } -void setupWifi() { - ESPConnect.autoConnect(HOSTNAME); - if(ESPConnect.begin(&server)){ - logLine("Connected to WiFi: ", false); - logLine(WiFi.localIP().toString()); - }else{ - logLine("Failed to connect to WiFi"); - } +void setupWifi() +{ + ESPConnect.autoConnect(HOSTNAME); + if (ESPConnect.begin(&server)) + { + logLine("Connected to WiFi: ", false); + logLine(WiFi.localIP().toString()); + } + else + { + logLine("Failed to connect to WiFi"); + } } -void setupMDNS() { - if (mdns.begin(HOSTNAME)) { +void setupMDNS() +{ + if (mdns.begin(HOSTNAME)) + { logLine("MDNS responder started"); mdns.addService("http", "tcp", 80); mdns.addService("ws", "tcp", 81); - } else { + } + else + { logLine("MDNS.begin failed"); } } -void setupOTA() { - ArduinoOTA.onStart([]() { +void setupOTA() +{ + ArduinoOTA.onStart([]() + { runGame = false; - logLine("OTA Update Start"); - }); - ArduinoOTA.onEnd([]() { + logLine("OTA Update Start"); }); + ArduinoOTA.onEnd([]() + { logLine("OTA Update End"); - runGame = true; - }); - ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { + runGame = true; }); + ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) + { char p[32]; sprintf(p, "Progress: %u%%\n", (progress/(total/100))); - logLine(p, false); - }); - ArduinoOTA.onError([](ota_error_t error) { + logLine(p, false); }); + ArduinoOTA.onError([](ota_error_t error) + { if(error == OTA_AUTH_ERROR) logLine("OTA Auth Failed"); else if(error == OTA_BEGIN_ERROR) logLine("OTA Begin Failed"); else if(error == OTA_CONNECT_ERROR) logLine("OTA Connect Failed"); else if(error == OTA_RECEIVE_ERROR) logLine("OTA Receive Failed"); else if(error == OTA_END_ERROR) logLine("OTA End Failed"); - runGame = true; - }); + runGame = true; }); ArduinoOTA.setHostname(HOSTNAME); ArduinoOTA.begin(); } -void networkLoop() { +void networkLoop() +{ ArduinoOTA.handle(); } diff --git a/src/network.h b/src/network.h index a760da45e17a9997f64b10ad60dee1a31132abd9..2475984e4e2908daf7c5c446e6f0d9e2d2d3cebf 100644 --- a/src/network.h +++ b/src/network.h @@ -1,21 +1,21 @@ #ifndef NETWORK_H - #define NETWORK_H +#define NETWORK_H - #include <Arduino.h> - #include <ArduinoOTA.h> - #include <ESPConnect.h> - #include <Wifi.h> - #include <ESPmDNS.h> - #include <AsyncTCP.h> - #include <ESPAsyncWebServer.h> +#include <Arduino.h> +#include <ArduinoOTA.h> +#include <ESPConnect.h> +#include <Wifi.h> +#include <ESPmDNS.h> +#include <AsyncTCP.h> +#include <ESPAsyncWebServer.h> - extern bool runGame; +extern bool runGame; - void setupNetwork(); - void setupMDNS(); - void setupWifi(); - void setupWebserver(); - void setupOTA(); - void networkLoop(); +void setupNetwork(); +void setupMDNS(); +void setupWifi(); +void setupWebserver(); +void setupOTA(); +void networkLoop(); #endif diff --git a/src/utils.cpp b/src/utils.cpp index 86db4f726cc478359cf5f57f670f9075d6ec1d63..469daaeb28c72444af7f87065805a5a6740fd3b0 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,9 +1,11 @@ #include <Arduino.h> #include "utils.h" -void logLine(String line, bool newline) { +void logLine(String line, bool newline) +{ Serial.print(line); - if(newline) { + if (newline) + { Serial.println(); } } diff --git a/src/utils.h b/src/utils.h index 074504f19d9a09c5c64653dd7873904c46a4e417..185eab8bcbc6295b0cc22081d82867d6cb4254a6 100644 --- a/src/utils.h +++ b/src/utils.h @@ -1,6 +1,7 @@ #ifndef UTILS_H - #define UTILS_H +#define UTILS_H + +#include <Arduino.h> +void logLine(String line, bool newline = true); - #include <Arduino.h> - void logLine(String line, bool newline = true); #endif