// Derby Race game Nano feasibiity per
// https://forum.arduino.cc/t/help-with-race-car-derby-racing-game-with-addressable-leds/1248176/10
// https://wokwi.com/projects/395283077096057857

// more complicated button-handling within pinball machines could
// be done with a separate controllers for each pinball machine
//  confidureg to deliver pulses to this display controller
// See https://wokwi.com/projects/395389818314203137 for an example.

#include <FastLED.h>

const size_t numSections = 16;
const size_t ledsPerSection = 27;
const size_t ledCount = numSections * ledsPerSection;
const uint8_t ledPin = 2;
const byte InPins[numSections] = {3, 4, 5, 6, 7, 8, 10, 11, 12, 13, A0, A1, A2, A3, A4, A5};
byte lastPinState[numSections] = {};
uint32_t lastPinMs[numSections] = {};
byte position[numSections] = {};
const int ACTIVE = LOW;
uint32_t now = 0;

// hat tip https://forum.arduino.cc/t/multiple-animation-zones-on-1-pixel-strip-with-fastled/1073391/16
CRGB leds[ledCount];
// See https://fastled.io/docs/class_c_pixel_view.html
CPixelView<CRGB> sections[numSections] = {
  CPixelView<CRGB>(leds, 0 * ledsPerSection, 1 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 1 * ledsPerSection, 2 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 2 * ledsPerSection, 3 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 3 * ledsPerSection, 4 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 4 * ledsPerSection, 5 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 5 * ledsPerSection, 6 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 6 * ledsPerSection, 7 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 7 * ledsPerSection, 8 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 8 * ledsPerSection, 9 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 9 * ledsPerSection, 10 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 10 * ledsPerSection, 11 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 11 * ledsPerSection, 12 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 12 * ledsPerSection, 13 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 13 * ledsPerSection, 14 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 14 * ledsPerSection, 15 * ledsPerSection - 1),
  CPixelView<CRGB>(leds, 15 * ledsPerSection, 16 * ledsPerSection - 1)
};

void setup() {
  Serial.begin(115200);
  FastLED.addLeds<WS2812B, ledPin, GRB>(leds, ledCount);

  lampTest();
  randomRainbowTest();

  for (auto &pin : InPins ) {
    pinMode(pin, INPUT_PULLUP);
  }

  Serial.println("Ready. Set. Ding!");
}

void loop() {
  now = millis();

  scanButtons();

  //swapColors();
}


void scanButtons(void) {
  for (int ii = 0; ii < numSections; ++ii) {
    int buttonState = digitalRead(InPins[ii]);
    if (buttonState != lastPinState[ii] && now - lastPinMs[ii] > 100) {
      lastPinState[ii] = buttonState;
      lastPinMs[ii] = now;
      Serial.print(ii); Serial.print(" ");
      if (buttonState == ACTIVE) {
        sections[ii][position[ii]] = CRGB::Black;
        ++position[ii];
        if (position[ii] > ledsPerSection - 1) { // winner
          Serial.print("Winner!");
          position[ii] = ledsPerSection - 1;
        }
        sections[ii][position[ii]] = CRGB::CRGB::Yellow;
        FastLED.show();
      }
    }
  }
}

void swapColors(void) {
  static uint32_t last = 0;
  static int flip = 1;
  if (millis() - last < 1000) return;
  last = millis();
  for (int idx = 0; idx < ledCount; ++idx) {
    leds[idx] = (idx + flip) & 0b1 ? CRGB(74, 126, 54) : CRGB::Coral ;
  }
  flip = flip > 0 ? 0 : 1;
  Serial.print(".");
  FastLED.show();
}

void lampTest(void) {
  // test leds
  Serial.print("test all the leds in leds()...");
  for (int idx = 0; idx < ledCount; ++idx) {
    leds[idx] = idx & 0b1 ? CRGB::Aqua : CRGB::Coral ;
  }
  FastLED.show();
  Serial.println("done.");
  delay(2000);
}
void randomRainbowTest(void) {
  Serial.println("test each strand in sections[]...");
  for (int ii ; ii < numSections; ++ii) {
    Serial.print("sections[");
    Serial.print(ii);
    Serial.print("].size()=");
    Serial.print(sections[ii].size());
    Serial.print(" ");
    randomSeed(random() + analogRead(A7) + micros());
    sections[ii].fill_rainbow(random(255), 3);
    FastLED.show();
    delay(377);
  }
  Serial.println("...done.");
  delay(1000);
}
Derby Race -- Hit the buttons to advance the lights.