Using a random integer in an array[]

Greetings,

I have this problem I cant seen to fix with my arduino.. I want to make a little game where randomly 1 out of 7 LEDS blinks and then the 7 leds start to blink from left to right. the purpose of the game is to press the button when the random led that blinked at the beginning is lit. if you can do so a sound plays, if you fail another sound plays..

the problem is that the integer i save my random value for the led in cant be read in the
if(statusknop == HIGH && leds[randomnummer] == HIGH){
as i can never win the game. ive been trying for a while now but cant seen to find a solution. the rest of the code is working properly

see my code below. im sorry that most of my stuff is in dutch :confused:

i am sorry for the bad english :confused:

greetz,
an arduino noob

int leds[7] = {2,3,4,5,6,7,8};
int buzzer = 13;
int knop = 9;
int potv;
int randomnummer;
unsigned long currentMillis = millis();
boolean statusknop;

void setup() {
Serial.begin(9600);
Serial.println("Het spel start op");
pinMode(leds[0], OUTPUT);
pinMode(leds[1], OUTPUT);
pinMode(leds[2], OUTPUT);
pinMode(leds[3], OUTPUT);
pinMode(leds[4], OUTPUT);
pinMode(leds[5], OUTPUT);
pinMode(leds[6], OUTPUT);
pinMode(buzzer, OUTPUT);
pinMode(knop, INPUT_PULLUP);
pinMode(potv, INPUT);
randomSeed (analogRead(1));
}

void loop() {
  
  
  Serial.println("huidige snelheid van het spel: " + String(potv) + " ms per LED");
  randomnummer = random(0, 6);
  randomled();

  while(statusknop == LOW){
  digitalWrite(leds[0], 1);
  wachten();
  controle();
  digitalWrite(leds[0], 0);
 


  digitalWrite(leds[1], 1);
  wachten();
  controle();
  digitalWrite(leds[1], 0);



  digitalWrite(leds[2], 1);
  wachten();
  controle();
  digitalWrite(leds[2], 0);
  


  digitalWrite(leds[3], 1);
  wachten();
  controle();
  digitalWrite(leds[3], 0);
  


  digitalWrite(leds[4], 1);
  wachten();
  controle();
  digitalWrite(leds[4], 0);



  digitalWrite(leds[5], 1);
  wachten();
  controle();
  digitalWrite(leds[5], 0);
 

  digitalWrite(leds[6], 1);
  wachten();
  controle();
  digitalWrite(leds[6], 0);
  }
}


void randomled(){
  digitalWrite(leds[randomnummer], 1);
  delay(2000);
  digitalWrite(leds[randomnummer], 0);
}


void controle(){
   potv = analogRead(A0);
   if(statusknop == HIGH && leds[randomnummer] == HIGH){
      gewonnen();
    }else if(statusknop == HIGH){
      verloren();
    }
}

void gewonnen(){
      Serial.println("gewonnen!!");
      for (int i=0; i <= 8; i++){
      digitalWrite(leds[3], HIGH);
      digitalWrite(buzzer, HIGH);
      delay(95);
      digitalWrite(buzzer, LOW);
      digitalWrite(leds[3], LOW);
      delay(95);
      }
      delay(1500);
}

void verloren(){
      Serial.println("verloren probeer opnieuw..");
      for (int i=0; i <= 1; i++){
      digitalWrite(buzzer, HIGH);
      digitalWrite(leds[0], 1);
      digitalWrite(leds[1], 1);
      digitalWrite(leds[2], 1);
      digitalWrite(leds[3], 1);
      digitalWrite(leds[4], 1);
      digitalWrite(leds[5], 1);
      digitalWrite(leds[6], 1);
      delay(500);
      digitalWrite(buzzer, LOW);
      digitalWrite(leds[0], 0);
      digitalWrite(leds[1], 0);
      digitalWrite(leds[2], 0);
      digitalWrite(leds[3], 0);
      digitalWrite(leds[4], 0);
      digitalWrite(leds[5], 0);
      digitalWrite(leds[6], 0);
      delay(500);
      }
}

void wachten(){
  unsigned long int huidige_tijd = millis();
  while(millis() - huidige_tijd < potv){
    statusknop = digitalRead(knop);
  }
  return statusknop;
}

You declared the function wachten as void, but you want it to return a value! void means nothing is returned so it's normal that the value cannot be used elsewhere:

boolean wachten(){  // <-- make it boolean here
  unsigned long int huidige_tijd = millis();
  while(millis() - huidige_tijd < potv){
    statusknop = digitalRead(knop);
  }
  return statusknop;
}

Also, be aware that this line returns random numbers from 0 to 5 (i.e. 0, 1, 2, 3, 4 or 5) but never 6:

randomnummer = random(0, 6);

Finally, you should use for loops to simplify your code:

      digitalWrite(buzzer, HIGH);
      digitalWrite(leds[0], 1);
      digitalWrite(leds[1], 1);
      digitalWrite(leds[2], 1);
      digitalWrite(leds[3], 1);
      digitalWrite(leds[4], 1);
      digitalWrite(leds[5], 1);
      digitalWrite(leds[6], 1);

can be changed to

for (int i=0; i<7; i++) digitalWrite(leds[i], 1);

The following groups of lines can also be changed to a for loop :

  digitalWrite(leds[0], 1);
  wachten();
  controle();
  digitalWrite(leds[0], 0);

...

Can be changed to

for (int i=0; i<7; i++) {
  digitalWrite(leds[i], 1);
  wachten();
  controle();
  digitalWrite(leds[i], 0);
}

Hope this helps...

Thanks for the response!

yes, my code is alot smaller and cleaner now but now it seems like the first LED that should be a "random" one now always is the first one, ive tried about 15 times and it is the first one everytime.. I tried to randomseed a diffrent Analog port but that did not seem to help..

int leds[7] = {2,3,4,5,6,7,8};
int buzzer = 13;
int knop = 9;
int potv;
int randomnummer;
unsigned long currentMillis = millis();
boolean statusknop;

void setup() {
Serial.begin(9600);
Serial.println("Het spel start op");
pinMode(leds[0], OUTPUT);
pinMode(leds[1], OUTPUT);
pinMode(leds[2], OUTPUT);
pinMode(leds[3], OUTPUT);
pinMode(leds[4], OUTPUT);
pinMode(leds[5], OUTPUT);
pinMode(leds[6], OUTPUT);
pinMode(buzzer, OUTPUT);
pinMode(knop, INPUT_PULLUP);
pinMode(potv, INPUT);
randomSeed (analogRead(A2));
}

void loop() {
  Serial.println("huidige snelheid van het spel: " + String(potv) + " ms per LED");
  randomnummer = random(0, 7);
  randomled();

  while(statusknop == LOW){
    for (int i=0; i<7; i++) {
      digitalWrite(leds[i], 1);
      wachten();
      controle();
      digitalWrite(leds[i], 0);
    }
  }
}


void randomled(){
  digitalWrite(leds[randomnummer], 1);
  delay(2000);
  digitalWrite(leds[randomnummer], 0);
}


void controle(){
   potv = analogRead(A0);
   if(statusknop == HIGH && leds[randomnummer] == HIGH){
      gewonnen();
    }else if(statusknop == HIGH){
      verloren();
    }
}

void gewonnen(){
      Serial.println("gewonnen!!");
      for (int i=0; i <= 8; i++){
      digitalWrite(leds[3], HIGH);
      digitalWrite(buzzer, HIGH);
      delay(95);
      digitalWrite(buzzer, LOW);
      digitalWrite(leds[3], LOW);
      delay(95);
      }
      delay(1500);
}

void verloren(){
      Serial.println("verloren probeer opnieuw..");
      for (int i=0; i <= 1; i++){
        for (int i=0; i<7; i++){
          digitalWrite(buzzer, HIGH);
          digitalWrite(leds[i], 1);
        }
      delay(500);
        for (int i=0; i<7; i++){
          digitalWrite(buzzer, LOW);
          digitalWrite(leds[i], 0);
        }
      delay(500);
      }
}

boolean wachten(){
  unsigned long int huidige_tijd = millis();
  while(millis() - huidige_tijd < potv){
    statusknop = digitalRead(knop);
  }
  return statusknop;
}

Even if the function returned a value it is ignored by the calling program and statusknop is global anyway so does not need to be returned

You're right, I should have suggested the other way : keep the function as void and remove the return...
Sorry about that.

You still can simplify your code by the way:

Use a for loop to define your pins:

for (int i=0; i<7; i++) pinMode(leds[i], OUTPUT);

and this

   if(statusknop == HIGH && leds[randomnummer] == HIGH){
      gewonnen();
    }else if(statusknop == HIGH){
      verloren();
    }

can be simplified to

   if(statusknop == HIGH) {
    if (leds[randomnummer] == HIGH) gewonnen();
    else verloren();
  }

About your random problem, try this code:

void setup() {
  Serial.begin(115200);
  randomSeed(analogRead(A0));  // <-- A0 or 0 indifferently
}

void loop() {
  Serial.println(random(0, 7));
  delay(2000);
}

Try it several times and see it it provides different sets of values. For me on a Nano, I get different sets, but they all begin with 0. If this is the same for you, just ignore the first random value (by calling random in the setup)

When I try to run your small code i also always get 0 for the first one but after its random, altough when i use this trick in my code the second value is always the same... i have also tried multiple times..

also if i change

if(statusknop == HIGH && leds[randomnummer] == HIGH){
      gewonnen();
   }else if(statusknop == HIGH){
      verloren();
    }

to the code you provided my whole program goes crazy :slight_smile:

heres my whole code again:

int leds[7] = {2,3,4,5,6,7,8};
int buzzer = 13;
int knop = 9;
int potv;
int randomnummer;
unsigned long currentMillis = millis();
boolean statusknop;

void setup() {
  Serial.begin(9600);
  Serial.println("Het spel start op");
  randomSeed(analogRead(A2));
  Serial.println(random(0, 7));
  pinMode(buzzer, OUTPUT);
  pinMode(knop, INPUT_PULLUP);
  pinMode(potv, INPUT);
  for (int i=0; i<7; i++){
    pinMode(leds[i], OUTPUT);
  }
}

void loop() {
  Serial.println("huidige snelheid van het spel: " + String(potv) + " ms per LED");
  randomnummer = random(0, 7);
  Serial.println(randomnummer);
  randomled();

  while(statusknop == LOW){
    for (int i=0; i<7; i++) {
      digitalWrite(leds[i], 1);
      wachten();
      controle();
      digitalWrite(leds[i], 0);
    }
  }
}

void randomled(){
  digitalWrite(leds[randomnummer], 1);
  delay(2000);
  digitalWrite(leds[randomnummer], 0);
}

void controle(){
   potv = analogRead(A0);
   if(statusknop == HIGH && leds[randomnummer] == HIGH){
      gewonnen();
   }else if(statusknop == HIGH){
      verloren();
    }
}

void gewonnen(){
      Serial.println("gewonnen!!");
      for (int i=0; i <= 8; i++){
      digitalWrite(leds[randomnummer], HIGH);
      digitalWrite(buzzer, HIGH);
      delay(95);
      digitalWrite(buzzer, LOW);
      digitalWrite(leds[randomnummer], LOW);
      delay(95);
      }
      delay(1500);
}

void verloren(){
      Serial.println("verloren probeer opnieuw..");
      for (int i=0; i <= 1; i++){
        for (int i=0; i<7; i++){
          digitalWrite(leds[i], 1);
          digitalWrite(buzzer, HIGH);
        }
      delay(500);
        for (int i=0; i<7; i++){
          digitalWrite(leds[i], 0);
          digitalWrite(buzzer, LOW);
        }
      delay(500);
      }
}

void wachten(){
  unsigned long int huidige_tijd = millis();
  while(millis() - huidige_tijd < potv){
    statusknop = digitalRead(knop);
  }
}

it seems to be that now its always the first or last led that lights at the beginning

You can't do this :
pinMode(potv, INPUT);because potv is the value read from the analog input A0

Also, this line is useless:

unsigned long currentMillis = millis();

Remove both lines...

removed both lines but "random" led is still the same everytime

Please post the code as it is now

Full code atm:

int leds[7] = {2,3,4,5,6,7,8};
int buzzer = 13;
int knop = 9;
int potv;
int randomnummer;
boolean statusknop;

void setup() {
  Serial.begin(9600);
  Serial.println("Het spel start op");
  randomSeed(analogRead(A1));
  random();
  pinMode(buzzer, OUTPUT);
  pinMode(knop, INPUT_PULLUP);
  for (int i=0; i<7; i++){
    pinMode(leds[i], OUTPUT);
  }
}

void loop() {
  Serial.println("huidige snelheid van het spel: " + String(potv) + " ms per LED");
  randomnummer = random(0, 7);
  randomled();

  while(statusknop == LOW){
    for (int i=0; i<7; i++) {
      digitalWrite(leds[i], 1);
      wachten();
      controle();
      digitalWrite(leds[i], 0);
    }
  }
}

void randomled(){
  digitalWrite(leds[randomnummer], 1);
  delay(2000);
  digitalWrite(leds[randomnummer], 0);
}

void controle(){
   potv = analogRead(A0);
   if(statusknop == HIGH && leds[randomnummer] == HIGH){
      gewonnen();
   }else if(statusknop == HIGH){
      verloren();
    }
}

void gewonnen(){
      Serial.println("gewonnen!!");
      for (int i=0; i <= 8; i++){
      digitalWrite(leds[randomnummer], HIGH);
      digitalWrite(buzzer, HIGH);
      delay(95);
      digitalWrite(buzzer, LOW);
      digitalWrite(leds[randomnummer], LOW);
      delay(95);
      }
      delay(1500);
}

void verloren(){
      Serial.println("verloren probeer opnieuw..");
      for (int i=0; i <= 1; i++){
        for (int i=0; i<7; i++){
          digitalWrite(leds[i], 1);
          digitalWrite(buzzer, HIGH);
        }
      delay(500);
        for (int i=0; i<7; i++){
          digitalWrite(leds[i], 0);
          digitalWrite(buzzer, LOW);
        }
      delay(500);
      }
}

void wachten(){
  unsigned long int huidige_tijd = millis();
  while(millis() - huidige_tijd < potv){
    statusknop = digitalRead(knop);
  }
}

In 'verloren', the lines of the buzzer can be put outside the for loops, before the delay for instance

          digitalWrite(buzzer, HIGH);
...
          digitalWrite(buzzer, LOW);

Can you Serial.println the value of randomnummer and check it's consistent with the led lit?

Actually, you have some quite long delays (2000 in randomled function) which may prevent to catch a button push, but I don't think your problem is there.

the big delay in randomled() shouldnt be a problem for the buttonpush i think because the button only needs to be pressed when inside the while loop.

I printed the randomnummer value in the serial monitor and it was the same as the LED thats lit

What value for randomnummer do you get if you use an explicit value in randomSeed() ?

One technique that I have seen suggested to randomise a program is to prompt the user to press a button to start the program and to use the value of millis() at that time as the randomSeed() value

I see this in your code

 random();

What are you trying to do ?

if I do this: randomSeed(7);
I always get 0 as output
the random(); is there because of the previous test of lesept with following code:

  void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A2));  // <-- A0 or 0 indifferently
  random(0, 7);
}

void loop() {
  Serial.println(random(0, 7));
  delay(2000);
}

that the first number was always the same and the ones after would be random. So I tried to get rid of that first number like that

int leds[7] = {2,3,4,5,6,7,8};
if(statusknop == HIGH && leds[randomnummer] == HIGH){

Arduino uses #define HIGH 0x1 so the second statement can never be true. Does gewonen() ever get called?

Serial.println("huidige snelheid van het spel: " + String(potv) + " ms per LED");
  randomnummer = random(0, 7);
  randomled();
void randomled(){
  digitalWrite(leds[randomnummer], 1);
  delay(2000);
  digitalWrite(leds[randomnummer], 0);
}

Are you saying that these lines at the start of loop() always turn on the same led the first time?

One technique that I have seen suggested to randomise a program is to prompt the user to press a button to start the program and to use the value of millis() at that time as the randomSeed() value

Did you try this? Another idea might be to connect a pot to you random seed analogRead() pin and give it a turn before starting.

It should be

if(statusknop == HIGH && digitalRead(leds[randomnummer]) == HIGH){

In fact, your code shouldn't work. The loop is organized around the while loop:

  while(statusknop == LOW){
    for (int i=0; i<7; i++) {
      digitalWrite(leds[i], 1);
      wachten();
      controle();
      digitalWrite(leds[i], 0);
    }
  }

But statusknop is not initialized, so its initial value is random, either LOW or HIGH (0 or 1, false or true). If it's HIGH, then the while is not executed.

If it's LOW, then the wachten function is executed. It waits for potv milliseconds, but for the first time potv is not initialized (later it will be the value of the potentiometer), so it's random also and we don't know how long it will wait and read the button...

The button is INPUT_PULLUP so it sends LOW when pressed. This means it's connectd to GND on one side and the knop pin on the other (did you do that ?). The wachten function reads the button for a given time frame, equal to the value of the potentiometer in ms. So if you release before the end of this time frame, the value of statusknop will be HIGH again and the next time the loop is run the while will not be executed!

When the while is not executed, buttonknop cannot be changed and the button is useless.

Anyways that's my understandng of your code. So you sould think again of what you want to do and rethink of the architecture of your code...

Sorry for the late response..

I have implemented the changes that have been suggested and for right now i am able to call the function gewonnen again on the "random" led so basically everything works..

Only problem being that my led still is not random as it always is the first one.. I have tried using randomSeed(analogRead(A0)); and changed the value of my pot at every beginning but its still alwas the sme LED that goes lit.

Full Code:

int leds[7] = {2,3,4,5,6,7,8};
int buzzer = 13;
int knop = 9;
int potv;
int randomnummer;
boolean statusknop;

void setup() {
  Serial.begin(9600);
  Serial.println("Het spel start op");
  randomSeed(analogRead(A1));
  pinMode(buzzer, OUTPUT);
  pinMode(knop, INPUT_PULLUP);
  for (int i=0; i<7; i++){
    pinMode(leds[i], OUTPUT);
  }
}

void loop() {
  Serial.println("huidige snelheid van het spel: " + String(potv) + " ms per LED");
  randomnummer = random(0, 7);
  randomled();
  Serial.println(randomnummer);

  while(statusknop == LOW){
    for (int i=0; i<7; i++) {
      digitalWrite(leds[i], 1);
      wachten();
      controle();
      digitalWrite(leds[i], 0);
    }
  }
}

void randomled(){
  digitalWrite(leds[randomnummer], 1);
  delay(2000);
  digitalWrite(leds[randomnummer], 0);
}

void controle(){
   potv = analogRead(A0);
   if(statusknop == HIGH && digitalRead(leds[randomnummer]) == HIGH){
      gewonnen();
   }else if(statusknop == HIGH){
      verloren();
    }
}

void gewonnen(){
      Serial.println("gewonnen!!");
      for (int i=0; i <= 8; i++){
      digitalWrite(leds[randomnummer], HIGH);
      digitalWrite(buzzer, HIGH);
      delay(95);
      digitalWrite(buzzer, LOW);
      digitalWrite(leds[randomnummer], LOW);
      delay(95);
      }
      delay(1500);
}

void verloren(){
      Serial.println("verloren probeer opnieuw..");
      for (int i=0; i <= 1; i++){
        for (int i=0; i<7; i++){
          digitalWrite(leds[i], 1);
        }
      digitalWrite(buzzer, HIGH);
      delay(500);
        for (int i=0; i<7; i++){
          digitalWrite(leds[i], 0);
        }
      digitalWrite(buzzer, LOW);
      delay(500);
      }
}

void wachten(){
  unsigned long int huidige_tijd = millis();
  while(millis() - huidige_tijd < potv){
    statusknop = digitalRead(knop);
  }
}

Edit:
Noticed that if I comment the While() loop and just let the randomled() function roll it does in fact randomly light leds its just that the first led is always the same after that its quite random which one goes on.

Edit 2:
Seems that if i put randomnummer = random(0, 8 );
then all of the sudden its random!! and if i make it randomnummer = random(0, 7);
again the first one is always the same... I guess i found the solution but this does not make any sense to me..

Full "Working" Code:

int leds[7] = {2,3,4,5,6,7,8};
int buzzer = 13;
int knop = 9;
int potv;
int randomnummer;
boolean statusknop;

void setup() {
  Serial.begin(9600);
  Serial.println("Het spel start op");
  randomSeed(analogRead(A1));
  pinMode(buzzer, OUTPUT);
  pinMode(knop, INPUT_PULLUP);
  for (int i=0; i<7; i++){
    pinMode(leds[i], OUTPUT);
  }
}

void loop() {
  randomnummer = random(0, 8);
  randomled();
  Serial.println(randomnummer);

  while(statusknop == LOW){
    Serial.println("huidige snelheid van het spel: " + String(potv) + " ms per LED");
    for (int i=0; i<7; i++) {
      digitalWrite(leds[i], 1);
      wachten();
      controle();
      digitalWrite(leds[i], 0);
    }
  }
}

void randomled(){
  digitalWrite(leds[randomnummer], 1);
  delay(2000);
  digitalWrite(leds[randomnummer], 0);
}

void controle(){
   potv = analogRead(A0);
   if(statusknop == HIGH && digitalRead(leds[randomnummer]) == HIGH){
      gewonnen();
   }else if(statusknop == HIGH){
      verloren();
    }
}

void gewonnen(){
      Serial.println("gewonnen!!");
      for (int i=0; i <= 8; i++){
      digitalWrite(leds[randomnummer], HIGH);
      digitalWrite(buzzer, HIGH);
      delay(95);
      digitalWrite(buzzer, LOW);
      digitalWrite(leds[randomnummer], LOW);
      delay(95);
      }
      delay(1500);
}

void verloren(){
      Serial.println("verloren probeer opnieuw..");
      for (int i=0; i <= 1; i++){
        for (int i=0; i<7; i++){
          digitalWrite(leds[i], 1);
        }
      digitalWrite(buzzer, HIGH);
      delay(500);
        for (int i=0; i<7; i++){
          digitalWrite(leds[i], 0);
        }
      digitalWrite(buzzer, LOW);
      delay(500);
      }
}

void wachten(){
  unsigned long int huidige_tijd = millis();
  while(millis() - huidige_tijd < potv){
    statusknop = digitalRead(knop);
  }
}

Edit 2:
Seems that if i put randomnummer = random(0, 8 );
then all of the sudden its random!! and if i make it randomnummer = random(0, 7);
again the first one is always the same... I guess i found the solution but this does not make any sense to me..

I agree. I can't figure out the root cause, but it might have something to do with the math underlying the random() function.

Your solution has a problem in that you can have random(0,8) return 7 which is outside the range of your array.int leds[7] = {2,3,4,5,6,7,8};

Arrays are zero indexed, and leds[] is only valid for leds[0] to leds[6]. Anything else points to random values in memory locations you don't "own".

I think a better solution is to just call random(0,7) in startup() after the call to randomSeed() . This will clear the initial zero value, and return the random sequence for the calls in loop().

randomSeed(analogRead(A1));
  random(0,7);

When I need random number, I use the truerandom library, you should give it a try.

Just add this line at the beginning of your code:
#include <TrueRandom.h>and useTrueRandom.random(7)for numbers from 0 to 6 included.