/* +---------------------------------------------+
   | Idea by HelioxLab                           |
   | https://www.youtube.com/watch?v=8joLK039fjk |
   |                                             |
   | Code optimised by me (RR)                   |
   | - showValue function
   | - randomSeed with added micros for better   |
   |   randomization                             |
   | - randomSeed every new dice roll            |
   | - shorter 'hold' time where dice can be     |
   |   rolled beovre 'disp' time runs out        |
   +---------------------------------------------+
*/
// LEDs
int pinLeds1 = 0; 
int pinLeds2 = 1;
int pinLeds3 = 2;
int pinLed4  = 3; 

// Neigungssensors / Mercury-Switch
int buttonPin = 4; 

// Zustand des Neiguingssensors / state of Mercury-Switch
int buttonState;

// Variabel für Animationsrandom / variable for animation random value
long rndAnim;

// Variable für den Random des Endergebnisses / variable for result random value
long rndValue;

// Es gab noch keinen Würfelstart / no last dice value
int lastValue = 0;

// Zeit, die der Würfel angezeigt bleibt 1000 ms = 1 Sekunde / display time of result 1000 ms = 1 second
int dispTime = 7000;
int holdTime = 4000;
unsigned long startTime;
unsigned long currentTimne;

// Deklariere Unterprogramme / declare subprograms
void rollDice();
void showValue(int diceValue);

void setup() {
  // put your setup code here, to run once:

  // LEDs sind Ausgänge / LEDs are outputs
  pinMode (pinLeds1, OUTPUT);
  pinMode (pinLeds2, OUTPUT);
  pinMode (pinLeds3, OUTPUT);
  pinMode (pinLed4,  OUTPUT);

  // Neigungssensor ist ein Eingang / Mercury-Switch is input
  pinMode (buttonPin, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:

  buttonState = digitalRead(buttonPin);
  if (buttonState == LOW) { // Wenn der Würfel bewegt wird / Dice has been moved
    rollDice(); 
// Zufallswert für Endergebnis / randum value for dice result
    rndValue = random(1, 7); 
    showValue(rndValue);
/*
    delay(dispTime); // dispTime ist die Variable, die den Wert 7000 hat, also wird das Ergebnis 7 Sekunden lang angezeigt
                     // variable dispTime has the value 7000 which means, the dice result will remain for 7 seconds
*/
    delay(holdTime);
    startTime = millis();
    while (true) {
      buttonState = digitalRead(buttonPin);
      if (buttonState == LOW) {
        break;
      }
      currentTimne = millis();
      if (currentTimne - startTime >= dispTime - holdTime) {
        break;
      }
    }
  }
  showValue(0);
}

void rollDice() {
  randomSeed(analogRead(0) + micros()); // Random initialisieren (RR micros() ergänzt, damit Start zufälliger wird und bei jedem Würfeln neu setzen)
                                        // initialise random (RR micros() added, start value is more random and set at each dice rolling)
  for (int i=0; i <= 7; i++){ // Animation für 8 Würfelanzeigen mit 200 ms zwischen den einzelnen Anzeigen
                              // animation for 8 dice displays with 200 ms between values
    rndAnim = random(1, 7); // Random für jede Anzeige / random, value for each display
    while (rndAnim == lastValue){ // überprüfen, ob zwei aufeinanderfolgende Anzeigen nicht gleich sind / check if 2 consecutive values are not identical
      rndAnim = random(1, 7); // Ansonsten eine neue Zufalls-Zahl / otherwise generate a new random value
    }
    lastValue = rndAnim; // Speichern der Zahl, um zu verhindern, dass während der Animation zwei gleiche Würfelwerte angezeigt werden
                         // save value to prevent identical dice values during animation
    showValue(rndAnim);
    delay(200); // Pause zwischen der Anzeige der Animation: 200ms LED aus / delay between dice animation
    showValue(0);
    delay(50);
  }
}

void showValue(int diceValue) {
  switch (diceValue) {
  case 0:
    digitalWrite (pinLeds1, LOW);
    digitalWrite (pinLeds2, LOW);
    digitalWrite (pinLeds3, LOW);
    digitalWrite (pinLed4,  LOW);
    break;
  case 1:
    digitalWrite (pinLed4, HIGH);
    break;
  case 2:
    digitalWrite (pinLeds1, HIGH);
    break;
  case 3:
    digitalWrite (pinLeds3, HIGH);
    digitalWrite (pinLed4,  HIGH);
    break;
  case 4:
    digitalWrite (pinLeds1, HIGH);
    digitalWrite (pinLeds3, HIGH);
    break;
  case 5:
    digitalWrite (pinLeds1, HIGH);
    digitalWrite (pinLeds3, HIGH);
    digitalWrite (pinLed4,  HIGH);
    break;
  case 6:
    digitalWrite (pinLeds1, HIGH);
    digitalWrite (pinLeds2, HIGH);
    digitalWrite (pinLeds3, HIGH);
    break;
  }
}
ATTINY8520PU