//F_lying fibonacci 256
//Fastled fibonacci 256 RGB leds demo
//Yaroslaw Turbin, 28.01.2020 
//https://vk.com/ldirko
//https://www.reddit.com/user/ldirko/ 

#include "FastLED.h"

// Matrix size
#define NUM_ROWS 20 
#define NUM_COLS 20
#define NUM_LEDS 400
// LEDs pin
#define DATA_PIN 3
// LED brightness
#define BRIGHTNESS 255

// Define the array of leds
CRGB leds[257];
CRGB ledsbuff[NUM_LEDS + 1];


void setup() {
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, 256);
  FastLED.setBrightness(BRIGHTNESS);
}

void loop()
{
  EVERY_N_MILLISECONDS(80) {updatesand(); randomdot();}    
  EVERY_N_MILLISECONDS(15000) {randomdel(); falldown(); falldown(); falldown();} 
  copyLeds();
  FastLED.show();
}

void SandMachine(){

}

void copyLeds(){
for (int y=0; y<NUM_COLS; y++) {
int indexY=y*20;
for (int x=0; x<NUM_COLS; x++) {
int indexFib = XY1(x,y);
if (indexFib!=256) leds [indexFib]=ledsbuff[indexY+x];
  }}
}
 
void randomdot(){
#define randomdothue 30
byte a= NUM_COLS/2-1; //random8(NUM_COLS/4)+NUM_COLS*3/8; //
if (!random8(4)) ledsbuff[XY(a,0)].setHue(random8(randomdothue,randomdothue+45));      
}
 
void updatesand (){
int index, indexXadd1Y, indexXsub1Y, indexXYadd1;  
for (int y=NUM_ROWS-1; y>0; y--) {
for (int x=1; x<NUM_COLS-1; x++) {
index = XY(x,y); indexXadd1Y = XY(x+1,y); indexXsub1Y = XY(x-1,y); indexXYadd1 = XY(x,y-1);
  if (!ledsbuff[index] && !ledsbuff[indexXYadd1]) continue;
  if (!ledsbuff[index] && ledsbuff[indexXYadd1]) {ledsbuff[index]=ledsbuff[indexXYadd1]; ledsbuff[indexXYadd1]=0;}
  if (ledsbuff[index] && ledsbuff[indexXYadd1] && !ledsbuff[indexXsub1Y] && !ledsbuff[indexXadd1Y])
      if (random8(2)) {ledsbuff[indexXsub1Y]=ledsbuff[indexXYadd1]; ledsbuff[indexXYadd1]=0;} 
        else {ledsbuff[indexXadd1Y]=ledsbuff[indexXYadd1]; ledsbuff[indexXYadd1]=0;} 
  if (ledsbuff[index] && ledsbuff[indexXYadd1] && !ledsbuff[indexXsub1Y] && ledsbuff[indexXadd1Y]) {ledsbuff[indexXsub1Y]=ledsbuff[indexXYadd1]; ledsbuff[indexXYadd1]=0;}
  if (ledsbuff[index] && ledsbuff[indexXYadd1] && ledsbuff[indexXsub1Y] && !ledsbuff[indexXadd1Y]) {ledsbuff[indexXadd1Y]=ledsbuff[indexXYadd1]; ledsbuff[indexXYadd1]=0;}
}} 
}
 
void randomdel(){
 for (int i=0; i<NUM_LEDS; i++) {
   if (!random8(3)) ledsbuff[i]=0; 
}
}
 
void falldown(){
int indexXYsub1, index;
for (int y=NUM_ROWS-1; y>0; y--) {
for (int x=0; x<NUM_COLS; x++) {
 indexXYsub1 =XY(x,y-1); index= XY(x,y);
  if (!ledsbuff[index] && ledsbuff[indexXYsub1]) {ledsbuff[index]=ledsbuff[indexXYsub1]; ledsbuff[indexXYsub1]=0;} 
}} 
}

uint16_t XY(byte x, byte y) { 
return (y*20+x);
}

uint16_t XY1(byte x, byte y) { 
static const uint16_t FibonPlanarTable[]={   // real wokwi prototype PCB layout
  256,256,256,256,256,256,256,256,36,39,38,37,256,256,256,256,256,256,256,256,256,256,256,256,256,13,34,35,40,
  256,58,59,60,61,256,256,256,256,256,256,256,256,256,256,14,33,256,41,56,57,68,67,66,65,64,63,256,256,256,256,
  256,256,256,12,15,32,42,55,256,69,256,79,80,81,82,83,62,256,256,256,256,256,11,16,31,256,43,54,70,77,78,94,
  93,92,91,90,84,85,256,256,256,255,10,17,30,44,53,71,76,256,95,256,101,102,103,104,89,88,256,256,256,254,9,18,
  29,45,52,72,75,96,256,100,120,119,118,117,105,106,87,256,256,253,8,19,28,46,256,51,73,97,99,121,124,125,126,
  256,116,256,107,86,232,252,7,20,256,27,47,256,50,74,122,123,145,144,256,127,256,115,256,108,233,251,6,256,21,
  256,26,48,49,256,98,146,147,148,143,256,128,256,114,109,231,234,250,5,256,22,23,25,24,0,195,171,170,169,149,
  142,256,129,113,110,230,235,256,249,4,3,2,1,244,243,256,194,172,256,168,150,141,130,112,256,256,229,236,256,
  248,247,246,245,242,220,219,196,193,173,167,151,140,131,111,256,256,208,228,237,238,239,240,241,256,221,218,
  197,192,174,166,152,139,132,256,256,256,256,209,227,226,256,256,256,222,256,217,198,191,175,165,153,138,133,
  256,256,256,256,207,210,211,225,224,223,215,216,199,256,190,176,164,154,137,134,256,256,256,256,256,206,205,
  212,213,214,201,200,256,189,177,163,256,155,136,256,256,256,256,256,256,256,256,204,203,202,256,187,188,178,
  162,256,156,135,256,256,256,256,256,256,256,256,256,183,184,185,186,180,179,161,256,157,256,256,256,256,256,
  256,256,256,256,256,256,256,256,182,181,159,160,256,158,256,256,256,256,256,256,256 
 };
return (FibonPlanarTable[y*20+x]);
}