#include <Adafruit_NeoPixel.h>
#include <TM1637.h>


#define NUM_RINGS 4
#define RESET_BTN 12

//display pins
#define DISPLAY_CLK   A3
#define DISPLAY_DIO   A4
TM1637 display;

//leds per ring
#define RING1 8
#define RING2 16
#define RING3 24
#define RING4 32
#define LED_PIN    A5
#define LED_COUNT RING1+RING2+RING3+RING4
Adafruit_NeoPixel rings(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);

const byte buttonPins[NUM_RINGS] = {2, 3, 4, 5};
const byte pointValues[NUM_RINGS] = {100, 50, 25, 10};

unsigned long buttonTimes[NUM_RINGS];
const unsigned long intervalDebounce = 50ul;
unsigned long ringTimes[NUM_RINGS];
const unsigned long intervalLedOn = 1000ul;
byte buttonStates[NUM_RINGS] = {1, 1, 1, 1};
byte ringStates[NUM_RINGS] = {1, 1, 1, 1};

volatile uint32_t totalPoints;

unsigned long lastReset;
byte stateReset = 1;


void setup()
{
  Serial.begin(115200);
  //init detection buttons
  for (int i = 0; i < NUM_RINGS; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
  }
  //init reset button
  pinMode(RESET_BTN, INPUT_PULLUP);
  //init the rings
  rings.begin();
  rings.show();
  rings.setBrightness(255);
  //light up rings..
  int i;
  for (i = 0; i < 8; i++) {
    rings.setPixelColor(i, rings.Color(255, 0, 0));
  }
  rings.show();
  delay(500);
  for (i = 8; i < 24; i++) {
    rings.setPixelColor(i, rings.Color(0, 255, 0));
  }
  rings.show();
  delay(500);
  for (i = 24; i < 48; i++) {
    rings.setPixelColor(i, rings.Color(0, 0, 255));
  }
  rings.show();
  delay(500);
  for (i = 48; i < 80; i++) {
    rings.setPixelColor(i, rings.Color(255, 255, 0));
  }
  rings.show();

  //init scoreboard display
  display.begin(DISPLAY_CLK, DISPLAY_DIO, 4);
  display.displayClear();
  display.displayInt(0);
  delay(500);

}

void loop()
{

  unsigned long now = millis();

  for (int i = 0; i < NUM_RINGS; i++) {
    if (now - buttonTimes[i] >= intervalDebounce) {
      byte val = digitalRead(buttonPins[i]);
      if (val != buttonStates[i]) {
        buttonTimes[i] = now;//start debouncing..
        buttonStates[i] = val;
        if (val == LOW) {
          totalPoints += pointValues[i];//add the points based on preset values
          Serial.print("Hit Button: "); Serial.println(i + 1);
          Serial.print("Total Points: "); Serial.println(totalPoints);
          switch (i) {
            case 0: {
                for (int i = 0; i < 8; i++) {
                  rings.setPixelColor(i, rings.Color(255, 0, 0));
                }
                rings.show();
              } break;
            case 1: {
                for (int i = 8; i < 24; i++) {
                  rings.setPixelColor(i, rings.Color(0, 255, 0));
                }
                rings.show();
              } break;
            case 2: {
                for (int i = 24; i < 48; i++) {
                  rings.setPixelColor(i, rings.Color(0, 0, 255));
                }
                rings.show();
              } break;
            case 3: {
                for (int i = 48; i < 80; i++) {
                  rings.setPixelColor(i, rings.Color(255, 255, 0));
                }
                rings.show();
              } break;
          }
          ringTimes[i] = now; //start led timer
          ringStates[i] = 1;
          display.displayInt(totalPoints);
        }
      }
    }
    //see if it's time to turn off a ring
    if (now - ringTimes[i] >= intervalLedOn && ringStates[i] == 1) {
      ringStates[i] = 0;
      switch (i) {
        case 0: {
            for (int i = 0; i < 8; i++) {
              rings.setPixelColor(i, rings.Color(0, 0, 0));
            }
            rings.show();
          } break;
        case 1: {
            for (int i = 8; i < 24; i++) {
              rings.setPixelColor(i, rings.Color(0, 0, 0));
            }
            rings.show();
          } break;
        case 2: {
            for (int i = 24; i < 48; i++) {
              rings.setPixelColor(i, rings.Color(0, 0, 0));
            }
            rings.show();
          } break;
        case 3: {
            for (int i = 48; i < 80; i++) {
              rings.setPixelColor(i, rings.Color(0, 0, 0));
            }
            rings.show();
          } break;
      }
    }
  }


  //handle reset button
  if (now - lastReset >= intervalDebounce) {
    byte r = digitalRead(RESET_BTN);
    if (r != stateReset) {
      lastReset = now;
      stateReset = r;
      if (stateReset == LOW) {
        totalPoints = 0;
        display.displayInt(0);
      }
    }
  }

}
4-Digit Display