//source: https://editor.soulmatelights.com/gallery/560-sand-automata
#include "FastLED.h"
#define DATA_PIN 2
#define BRIGHTNESS 255
#define NUM_LEDS 256
#define LED_COLS 16
#define LED_ROWS 16
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
//#define FRAMES_PER_SECOND 60
const uint8_t kMatrixWidth = 16;
const uint8_t kMatrixHeight = 16;
const bool kMatrixSerpentineLayout = false;
#define hue 30
void randomdot() {
byte a = LED_COLS / 2; //random8(LED_COLS/4)+LED_COLS*3/8; //
if (!random8(4)) leds[XY(a, LED_ROWS - 1)].setHue(random8(hue, hue + 45)); // 0 or 1
}
void updatesand() {
int index, indexXadd1Y, indexXsub1Y, indexXYadd1;
for (int y = 0; y < LED_ROWS - 1; y++) {
for (int x = 1; x < LED_COLS - 1; x++) {
index = XY(x, y); indexXadd1Y = XY(x + 1, y); indexXsub1Y = XY(x - 1, y); indexXYadd1 = XY(x, y + 1);
if (!leds[index] && !leds[indexXYadd1]) continue;
if (!leds[index] && leds[indexXYadd1]) {leds[index] = leds[indexXYadd1]; leds[indexXYadd1] = 0;}
else if (leds[index] && leds[indexXYadd1] && !leds[indexXsub1Y] && !leds[indexXadd1Y])
if (random8(2)) {leds[indexXsub1Y] = leds[indexXYadd1]; leds[indexXYadd1] = 0;} else {leds[indexXadd1Y] = leds[indexXYadd1]; leds[indexXYadd1] = 0;}
else if (leds[index] && leds[indexXYadd1] && !leds[indexXsub1Y] && leds[indexXadd1Y]) {leds[indexXsub1Y] = leds[indexXYadd1]; leds[indexXYadd1] = 0;}
else if (leds[index] && leds[indexXYadd1] && leds[indexXsub1Y] && !leds[indexXadd1Y]) {leds[indexXadd1Y] = leds[indexXYadd1]; leds[indexXYadd1] = 0;}
}
}
}
void randomdel() {
for (int i = 0; i < NUM_LEDS; i++) {
if (!random8(3)) leds[i] = 0;
}
}
void falldown() {
for (int y = 0; y < LED_ROWS - 1; y++) {
for (int x = 0; x < LED_COLS; x++) {
if (!leds[XY(x, y)] && leds[XY(x, y + 1)]) {leds[XY(x, y)] = leds[XY(x, y + 1)]; leds[XY(x, y + 1)] = 0;}
}
}
}
void countSand() {
uint16_t totalSand = 0;
for (uint16_t i = 0; i < NUM_LEDS; i++) {
if (leds[i]) {
totalSand++;
if (totalSand >= NUM_LEDS / 3 + random8(30)) {randomdel(); falldown(); falldown(); falldown(); break;} //N_LEDS/3 this how many sands on screen? maybe time to delete some?
}
}
}
void setup() {
FastLED.addLeds<LED_TYPE,DATA_PIN,COLOR_ORDER>(leds, NUM_LEDS); //setCorrection(TypicalLEDStrip);
//FastLED.addLeds<LED_TYPE,DATA_PIN,CLK_PIN,COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(BRIGHTNESS);
//Serial.begin(115200);
}
void loop()
{
EVERY_N_MILLISECONDS(30) {// 80 is speed of effect
updatesand();
randomdot();}
countSand();
FastLED.show();
}
uint16_t XY( uint8_t x, uint8_t y)
{
uint16_t i;
if( kMatrixSerpentineLayout == false) {
i = (y * kMatrixWidth) + x;
}
if( kMatrixSerpentineLayout == true) {
if( y & 0x01) {
// Odd rows run backwards
uint8_t reverseX = (kMatrixWidth - 1) - x;
i = (y * kMatrixWidth) + reverseX;
} else {
// Even rows run forwards
i = (y * kMatrixWidth) + x;
}
}
return i;
}