random output selection only once

Hello everyone,

I'm trying to make a program that, after a button starts the program, randomley activates an output foor a few seconds and then goes to a next one. But when an outpur has been activated it should not be selected again.

i've made a code that randomly selects an output, but the same output can be selected several times.

I als can't get the button to work

I would really appreciate any help with this

//void setup() {

int pushButton = 13;   // choose the input pin (for a pushbutton)
int val = 0;     // variable for reading the pin status

int catch_a_stick = 0;
int a = 40000; //tthis sets the time before the next stick will fall
int b = 8000
int stick1 = 5; //this makes stick 1 fall
int stick2 = 6; //this makes stick 2 fall
int stick3 = 7; //this makes stick 3 fall
int stick4 = 8; //this makes stick 4 fall
int stick5 = 9; //this makes stick 5 fall
int stick6 = 10; //this makes stick 6 fall
int stick7 = 11; //this makes stick 7 fall
int stick8 = 12; //this makes stick 8 fall

void setup() { //this sets the output pins

  pinMode(pushButton, INPUT);    // declare pushbutton as input

  pinMode(stick1, OUTPUT);  // declare to be an output
  pinMode(stick2, OUTPUT);  // declare to be an output
  pinMode(stick3, OUTPUT);  // declare to be an output
  pinMode(stick4, OUTPUT);  // declare to be an output
  pinMode(stick5, OUTPUT);  // declare to be an output
  pinMode(stick6, OUTPUT);  // declare to be an output
  pinMode(stick7, OUTPUT);  // declare to be an output
  pinMode(stick8, OUTPUT);  // declare to be an output
}

void loop()  {
  
    if (pushButton == HIGH) // Check for the opposite of what your button will normally be
    
      int catch_a_stick = random(8); //this randomly selects a number between 0 and 7
delay(b);
      switch (catch_a_stick) {
        case 0: //if catch_a_stick equals 0 then the stick1 will be released, stick 1 will fall
          analogWrite(stick1, HIGH);
          delay(a);
          analogWrite(stick1, LOW);
          break;
        case 1: //if catch_a_stick equals 1 then the stick2 will be released, stick 2 will fall
          digitalWrite(stick2, HIGH);
          delay(a);
          digitalWrite(stick2, LOW);
          break;
        case 2: //if catch_a_stick equals 2 then the stick3 will be released, stick 3 will fall
          digitalWrite(stick3, HIGH);
          delay(a);
          digitalWrite(stick3, LOW);
          break;
        case 3: //if catch_a_stick equals 3 then the stick4 will be released, stick 4 will fall
          digitalWrite(stick4, HIGH);
          delay(a);
          digitalWrite(stick4, LOW);
          break;
        case 4: //if catch_a_stick equals 4 then the stick5 will be released, stick 5 will fall
          analogWrite(stick5, HIGH);
          delay(a);
          analogWrite(stick5, LOW);
          break;
        case 5: //if catch_a_stick equals 5 then the stick6 will be released, stick 6 will fall
          digitalWrite(stick6, HIGH);
          delay(a);
          digitalWrite(stick6, LOW);
          break;
        case 6: //if catch_a_stick equals 6 then the stick7 will be released, stick 7 will fall
          digitalWrite(stick7, HIGH);
          delay(a);
          digitalWrite(stick7, LOW);
          break;
        case 7: //if catch_a_stick equals 7 then the stick8 will be released, stick 8 will fall
          digitalWrite(stick8, HIGH);
          delay(a);
          digitalWrite(stick8, LOW);
          break;
      }

    }

I would really appreciate any help with this

Search for "card shuffling algorithm". You want to do something similar, where the pins to set high are in an array that gets shuffled (randomly). Then, you simply toggle the pins in the array in the shuffled order.

int b = 8000

You can't say that code that does not compile works, or not.

  pinMode(pushButton, INPUT);    // declare pushbutton as input

This assumes that the switch is wired with an external pullup or pulldown resistor. Is yours? Which kind? Why? Using the internal pullup resistor makes wiring so much simpler.

void loop()  {
 
    if (pushButton == HIGH)

You could avoid stupid mistakes like this bu using pin in the name of variables that hold pin numbers and state in the names of variables that hold state.

Obviously, 13 does not equal HIGH. But, the state read from the pin might. It pays to actually read the state.

When you select a random number you need to know whether it has already been chosen. One of many ways to accomplish what you want is to create an array with 8 slots that represent the numbers 0-7.

When the program begins each slot is set to false to show the number represented by it has not been chosen. Each time you need a new random number, keep generating new ones until you find one with its slot set to false, then mark it as chosen.

The random number generator creates a pseudo-random sequence, so you'll get the same sequence every time unless you call randomSeed().

Below is some demo code that will get a sequence of 8 random numbers and print them to the serial monitor. It only runs once but could easily be changed to keep going after the first sequence.

const int stickCount = 8;
boolean selected[stickCount];  // true => stick has been selected

void setup()
{
  Serial.begin(9600);
  randomSeed(analogRead(0));

  // set all selected to false
  for(int i=0; i < stickCount; i++)
  {
    selected[i] = false;
  }

}

void loop()
{

  int catch_a_stick;  
  int rnd;

  // if there are sticks that are not chosen
  if( sticksChosen() < stickCount )
  {
    while( true )
    {
      // choose a possible stick
      rnd = random(stickCount); 

      // if it has not been selected
      if( selected[rnd] == false )
      {
        catch_a_stick = rnd;            // set as chosen
        selected[rnd] = true;           // mark that it has been selected
        Serial.println(catch_a_stick);
        break;                          // done looking
      } // if

    } // while

  } // if
}

// return # of sticks that have been chosen
//
int sticksChosen()
{
  int retVal=0;

  // look at all sticks
  for(int i=0; i < stickCount; i++)
  {
    // increment count if this one has been selected
    if( selected[i] == true ) retVal++;

  } // for

  return retVal;

}

One of many ways to accomplish what you want is to create an array with 8 slots that represent the numbers 0-7.

Another way is to use two arrays. Select a number from 0 to 7. Copy the selected element from one array to the end of the other. Then, move the rest of the elements of the first array up, effectively deleting the chosen element. Repeat with a number from 0 to 6, then 0 to 5, until only one element remains. Copy it, and you have an array with no duplicates.

The best way to do this, IMO, is the Fisher–Yates algorithm.

Essentially:

  • Load all numbers in sequence into an array (so a simple for loop from, say, 0 to N).
  • Have a cursor to the beginning of the array.
  • Each time you want a random number, you ask for a random number between the cursor and N.
  • Swap the element at the random index by the number at the cursor.
  • Return the element at the cursor.
  • Increment the cursor.

Edit: A better explanation here: algorithm - Unique (non-repeating) random numbers in O(1)? - Stack Overflow

Thanks for all the replies. I still don't see how I should use this in my code (newbie).

I need the sequence to run once after the pushbutton has been activated.

So push the button. All 8 outputs will randomly be activated and the seguence stops. Then push the button again to start all over.

Can anyone help me out with this?

Thanks in advance

@ twan74:

Hi man,

first off heres my take on your question, I think you would find it applicable for your project requirement,
to used the code i had included you need to download Bounce2 library first. Located on the top are the variable you could change depending on what you want to do, Just a heads up this only display random value from 0 to value of numberOfChoice - 1 on the serial Monitor but I do think much of the leg work had been done, Now its your turn to add the Output part into the coding.

#include <Bounce2.h>

const byte switchPin = 2;
const byte numberOfChoice = 8;
const unsigned long interval = 500;


boolean Choice[numberOfChoice] ;

Bounce Sw = Bounce ( );



void setup() {
  // put your setup code here, to run once:
  Serial.begin ( 9600 ) ;
  randomSeed ( analogRead ( A0 ) );
  pinMode ( switchPin, INPUT );
  digitalWrite ( switchPin, HIGH);
  Sw .attach ( switchPin );
  Sw .interval ( 5 ) ;
  resetChoice();
}

void loop() {
  // put your main code here, to run repeatedly:
  Sw. update();
  unsigned long timeNow = millis();
  static unsigned long timePrev = 0;
  static boolean randomActive = false;
  if ( Sw. fell() )
  {
    timePrev = timeNow;
    randomActive = true;
  }
  if ( Sw. rose() )
  {
    randomActive = false;
    resetChoice();
  }
  if ( randomActive )
  {
    if ( timeNow - timePrev >= interval )
    {
      unsigned long randNumber = random ( numberOfChoice );
      if ( !Choice[randNumber] ) 
      {
        Choice[randNumber] = true;
        timePrev = timeNow; 
        Serial.println ( randNumber + 1) ;
      }
      if ( checkAlltrue() ) randomActive = false;
    }
  }
}

void resetChoice ()
{
  for ( int i = 0; i < numberOfChoice; i++)
  {
    Choice[i] = false;
    /*Serial.print ( " Choice[ " );
    Serial.print ( i );
    Serial.print ( " ] = " );
    Serial.print ( Choice[i] );
    Serial.print ( " \n" );*/
  }
}

void displayChoice()
{
  for ( int i = 0; i < numberOfChoice; i++)
  {
    Serial.print ( " Choice[ " );
    Serial.print ( i + 1 );
    Serial.print ( " ] = " );
    Serial.print ( Choice[i] );
    Serial.print ( " \n" );
  }
}

boolean checkAlltrue() 
{
  for ( int i = 0; i < numberOfChoice; i++)
  {
    if ( !Choice[ i ] ) return false;
  }
  return true;
}

Thanks I will try this when i'm home tomorrow

Here's my code mixed with yours and tested working. I changed the switch pin to digital 3, since 13 has a resistor on it. The switch is active LOW, so you could test the program by connecting a wire from pin 3 to Ground to simulate a button press.

In your code you had the delay values declared as int but they should be unsigned long. I advise you to set the delays to a smaller value and watch the serial monitor while testing.

const int stickCount = 8;
boolean selected[stickCount];  // true => stick has been selected
boolean inSequence = false;    // true => button has been pressed and sequences are running

int pushButton = 3;   // choose the input pin (for a pushbutton)
int val = 0;     // variable for reading the pin status

int catch_a_stick = 0;
unsigned long a = 40000UL; //tthis sets the time before the next stick will fall
unsigned long b = 8000UL;
int stick1 = 5; //this makes stick 1 fall
int stick2 = 6; //this makes stick 2 fall
int stick3 = 7; //this makes stick 3 fall
int stick4 = 8; //this makes stick 4 fall
int stick5 = 9; //this makes stick 5 fall
int stick6 = 10; //this makes stick 6 fall
int stick7 = 11; //this makes stick 7 fall
int stick8 = 12; //this makes stick 8 fall

void setup() { //this sets the output pins


  Serial.begin(9600);
  randomSeed(analogRead(0));
  Serial.println("Ready ...");

  // set all selected to false
  clearSelected();


  pinMode(pushButton, INPUT_PULLUP);    // declare pushbutton as input

  pinMode(stick1, OUTPUT);  // declare to be an output
  pinMode(stick2, OUTPUT);  // declare to be an output
  pinMode(stick3, OUTPUT);  // declare to be an output
  pinMode(stick4, OUTPUT);  // declare to be an output
  pinMode(stick5, OUTPUT);  // declare to be an output
  pinMode(stick6, OUTPUT);  // declare to be an output
  pinMode(stick7, OUTPUT);  // declare to be an output
  pinMode(stick8, OUTPUT);  // declare to be an output
}

// call before slecting random sequence
void clearSelected()
{
  for (int i = 0; i < stickCount; i++)
  {
    selected[i] = false;
  }
  Serial.println("Sticks cleared.");
}

void loop()  {

  int catch_a_stick;
  int rnd;

  // if button is pressed and not running the sequence
  if ( (inSequence == false) && (digitalRead(pushButton) == LOW) )
  {
    inSequence = true;    // set flag
    clearSelected();      // mark all sticks as available

  }

  // if we are running the sequence
  if ( inSequence == true )
  {

    // if there are sticks that are not chosen
    if ( sticksChosen() < stickCount )
    {
      while ( true )
      {
        // choose a possible stick
        rnd = random(stickCount);

        // if it has not been selected
        if ( selected[rnd] == false )
        {
          catch_a_stick = rnd;            // set as chosen
          selected[rnd] = true;           // mark that it has been selected
          Serial.print("Stick:  "); Serial.println(catch_a_stick);
          break;                          // done looking
        } // if

      } // while

      // run selected sequence
      Serial.println("  Begin Delay ");
      delay(b);
      Serial.println("   End Delay ");
      switch (catch_a_stick) {
        case 0: //if catch_a_stick equals 0 then the stick1 will be released, stick 1 will fall
          analogWrite(stick1, HIGH);
          Serial.println("  Begin Delay 2");
          delay(a);
          Serial.println("   End Delay 2");
          analogWrite(stick1, LOW);
          break;
        case 1: //if catch_a_stick equals 1 then the stick2 will be released, stick 2 will fall
          digitalWrite(stick2, HIGH);
          Serial.println("  Begin Delay 2");
          delay(a);
          Serial.println("   End Delay 2");
          digitalWrite(stick2, LOW);
          break;
        case 2: //if catch_a_stick equals 2 then the stick3 will be released, stick 3 will fall
          digitalWrite(stick3, HIGH);
          Serial.println("  Begin Delay 2");
          delay(a);
          Serial.println("   End Delay 2");
          digitalWrite(stick3, LOW);
          break;
        case 3: //if catch_a_stick equals 3 then the stick4 will be released, stick 4 will fall
          digitalWrite(stick4, HIGH);
          Serial.println("  Begin Delay 2");
          delay(a);
          Serial.println("   End Delay 2");
          digitalWrite(stick4, LOW);
          break;
        case 4: //if catch_a_stick equals 4 then the stick5 will be released, stick 5 will fall
          analogWrite(stick5, HIGH);
          Serial.println("  Begin Delay 2");
          delay(a);
          Serial.println("   End Delay 2");
          analogWrite(stick5, LOW);
          break;
        case 5: //if catch_a_stick equals 5 then the stick6 will be released, stick 6 will fall
          digitalWrite(stick6, HIGH);
          Serial.println("  Begin Delay 2");
          delay(a);
          Serial.println("   End Delay 2");
          digitalWrite(stick6, LOW);
          break;
        case 6: //if catch_a_stick equals 6 then the stick7 will be released, stick 7 will fall
          digitalWrite(stick7, HIGH);
          delay(a);
          digitalWrite(stick7, LOW);
          break;
        case 7: //if catch_a_stick equals 7 then the stick8 will be released, stick 8 will fall
          digitalWrite(stick8, HIGH);
          Serial.println("  Begin Delay 2");
          delay(a);
          Serial.println("   End Delay 2");
          digitalWrite(stick8, LOW);
          break;

        default:
          break;
      }

    } else {

      // all completed, clear flag
      inSequence = false;

    } // else


  } // if



}


// return # of sticks that have been chosen
//
int sticksChosen()
{
  int retVal = 0;

  // look at all sticks
  for (int i = 0; i < stickCount; i++)
  {
    // increment count if this one has been selected
    if ( selected[i] == true ) retVal++;

  } // for

  return retVal;

}

Thank you very much. I will try this tonight

Works great. Thnks

Hey... I know its like Im asking something thats self fulfilling... But which code works great?

The code blue eyes postes works great. I only ajusted the timing.