Randomize voids

Hi!

For a game I need some help. I recently started this project, so code below is a bit minimal since I just started.
I have 8 light circles in a table, it's simply a LED strip WS2812 with FastLED library.
Once the game is started the light circles should randomize for a while between the color RED and the color WHITE, all circles separate, like a very wild disco.. :).
After a while the flashing effect should stop and the circles should be on red or white random.
Then after X-seconds(to be determined) the lights should turn off

The idea of the game is:
The player should put white balls on each white dot before the lights turn off..
The flashing in the beginning is to build tension.

So my main question is: (How) can I randomize these functions?

 #include <FastLED.h>

#define LED_PIN     6
#define NUM_LEDS    62
#define BRIGHTNESS  255
#define LED_TYPE    WS2812
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

#define UPDATES_PER_SECOND 100

int buttonSwitch = 2;
int state = 0;

void setup(){ 
    Serial.begin(9600);
    delay(500);
    Serial.println("Booting...");

    pinMode(buttonSwitch, INPUT_PULLUP);
    delay( 3000 ); // power-up safety delay
    FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
    FastLED.setBrightness(  BRIGHTNESS );

    FastLED.clear(true);
    
    Serial.println("Booting is  done!");

}

void loop() {
  int buttonState = digitalRead(buttonSwitch);


    if(buttonState == LOW && state == 0){
      state = 1;
      startGame();
    }
}

void startGame(){

  //LOOP RANDOM THROUGH ALL FUNCTIONS, BUT MAKE SURE EACH CIRCLE IS ONE COLOR

  //TIMER SHOULD RUN 

  //IF TIMER DONE, LEAVE THE SOLID RANDOM COLORS ON FOR X-SECONDS
}


void circle1Red(){
    for(int pixel = 0; pixel < 6; pixel++){
    leds[pixel] = CRGB(255,0,0);
    FastLED.show();
  }
}
void circle1White(){
    for(int pixel = 0; pixel < 6; pixel++){
    leds[pixel] = CRGB(255,255,255);
    FastLED.show();
  }
}
void circle2Red(){
    for(int pixel = 8; pixel < 14; pixel++){
    leds[pixel] = CRGB(255,0,0);
    FastLED.show();
  }
}
void circle2White(){
    for(int pixel = 8; pixel < 14; pixel++){
    leds[pixel] = CRGB(255,255,255);
    FastLED.show();
  }
}
void circle3Red(){
    for(int pixel = 16; pixel < 22; pixel++){
    leds[pixel] = CRGB(255,0,0);
    FastLED.show();
  }
}
void circle3White(){
    for(int pixel = 16; pixel < 22; pixel++){
    leds[pixel] = CRGB(255,255,255);
    FastLED.show();
  }
}
void circle4Red(){
    for(int pixel = 24; pixel < 30; pixel++){
    leds[pixel] = CRGB(255,0,0);
    FastLED.show();
  }
}
void circle4White(){
    for(int pixel = 24; pixel < 30; pixel++){
    leds[pixel] = CRGB(255,255,255);
    FastLED.show();
  }
}
void circle5Red(){
    for(int pixel = 32; pixel < 38; pixel++){
    leds[pixel] = CRGB(255,0,0);
    FastLED.show();
  }
}
void circle5White(){
    for(int pixel = 32; pixel < 38; pixel++){
    leds[pixel] = CRGB(255,255,255);
    FastLED.show();
  }
}
void circle6Red(){
    for(int pixel = 40; pixel < 46; pixel++){
    leds[pixel] = CRGB(255,0,0);
    FastLED.show();
  }
}
void circle6White(){
    for(int pixel = 40; pixel < 46; pixel++){
    leds[pixel] = CRGB(255,255,255);
    FastLED.show();
  }
}
void circle7Red(){
    for(int pixel = 48; pixel < 54; pixel++){
    leds[pixel] = CRGB(255,0,0);
    FastLED.show();
  }
}
void circle7White(){
    for(int pixel = 48; pixel < 54; pixel++){
    leds[pixel] = CRGB(255,255,255);
    FastLED.show();
  }
}
void circle8Red(){
    for(int pixel = 56; pixel < 62; pixel++){
    leds[pixel] = CRGB(255,0,0);
    FastLED.show();
  }
}
void circle8White(){
    for(int pixel = 56; pixel < 62; pixel++){
    leds[pixel] = CRGB(255,255,255);
    FastLED.show();
  }
}

The easiest way is probably an array of function pointers.

Use a random number to select an element in the array to execute.

Not behind a PC for the next two or three weeks so can't help with the exact details.

If you use the random() function and a little math you will not need all of those functions. You are displaying LEDs in multiples of 8. Get a random number between 0 and 7, multiply by 8, and that is the starting point in your LED strip.

Maybe something like (compiles, not tested...):

#include <FastLED.h>

#define LED_PIN     6
#define NUM_LEDS    62
#define BRIGHTNESS  255
#define LED_TYPE    WS2812
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];

//#define UPDATES_PER_SECOND 100

void circle1Red();
void circle1White();
void circle2Red();
void circle2White();
void circle3Red();
void circle3White();
void circle4Red();
void circle4White();
void circle5Red();
void circle5White();
void circle6Red();
void circle6White();
void circle7Red();
void circle7White();
void circle8Red();
void circle8White();

const uint32_t KRANDOM_TIME_MIN = 2000ul;
const uint32_t KRANDOM_TIME_MAX = 6000ul;
const uint32_t KDECAY_WAIT = 100ul;
const uint32_t KHOLD_DELAY = 2000ul;

#define NUM_CIRCLES     8
#define NUM_RANDFUNCS   2

typedef void (*pfnFunc_t)(void);

pfnFunc_t grpFuncs[NUM_CIRCLES][NUM_RANDFUNCS] = 
{
    {
        &circle1Red,
        &circle1White
    },
    {
        &circle2Red,
        &circle2White
    },
    {
        &circle3Red,
        &circle3White
    },
    {
        &circle4Red,
        &circle4White
    },
    {
        &circle5Red,
        &circle5White
    },
    {
        &circle6Red,
        &circle6White
    },
    {
        &circle7Red,
        &circle7White
    },
    {
        &circle8Red,
        &circle8White
    }
    
};

int buttonSwitch = 2;
int state = 0;

void setup()
{   
    Serial.begin(9600);    
    delay(500);
    Serial.println("Booting...");

    randomSeed( analogRead(A0) );

    pinMode(buttonSwitch, INPUT_PULLUP);
    delay( 3000 ); // power-up safety delay
    FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
    FastLED.setBrightness(  BRIGHTNESS );

    FastLED.clear(true);
   
    Serial.println("Booting is  done!");

}

void loop() 
{
    int buttonState = digitalRead(buttonSwitch);
    
    if(buttonState == LOW && state == 0)
    {
        state = 1;
        startGame();
        while( digitalRead(buttonSwitch) == LOW );
        state = 0;
        
    }
}

void startGame()
{
    uint32_t 
        randDelay;
    uint32_t
        timeRandomPattern = millis();

    randDelay = (uint32_t)random( KRANDOM_TIME_MIN, KRANDOM_TIME_MAX );    
    while( (millis() - timeRandomPattern) < randDelay )
    {
        for( uint8_t i=0; i< NUM_CIRCLES; i++ )
            grpFuncs[i][random( 0, NUM_RANDFUNCS )]();
        
        FastLED.show();
        delay( KDECAY_WAIT );
        
    }//while
    
    delay( KHOLD_DELAY );
    
    FastLED.clear();
    FastLED.show();
    
}//startGame


void circle1Red(){
    for(int pixel = 0; pixel < 6; pixel++){
    leds[pixel] = CRGB(255,0,0);
    
  }
}
void circle1White(){
    for(int pixel = 0; pixel < 6; pixel++){
    leds[pixel] = CRGB(255,255,255);
    
  }
}
void circle2Red(){
    for(int pixel = 8; pixel < 14; pixel++){
    leds[pixel] = CRGB(255,0,0);
    
  }
}
void circle2White(){
    for(int pixel = 8; pixel < 14; pixel++){
    leds[pixel] = CRGB(255,255,255);
    
  }
}
void circle3Red(){
    for(int pixel = 16; pixel < 22; pixel++){
    leds[pixel] = CRGB(255,0,0);
    
  }
}
void circle3White(){
    for(int pixel = 16; pixel < 22; pixel++){
    leds[pixel] = CRGB(255,255,255);
    
  }
}
void circle4Red(){
    for(int pixel = 24; pixel < 30; pixel++){
    leds[pixel] = CRGB(255,0,0);
    
  }
}
void circle4White(){
    for(int pixel = 24; pixel < 30; pixel++){
    leds[pixel] = CRGB(255,255,255);
    
  }
}
void circle5Red(){
    for(int pixel = 32; pixel < 38; pixel++){
    leds[pixel] = CRGB(255,0,0);
    
  }
}
void circle5White(){
    for(int pixel = 32; pixel < 38; pixel++){
    leds[pixel] = CRGB(255,255,255);
    
  }
}
void circle6Red(){
    for(int pixel = 40; pixel < 46; pixel++){
    leds[pixel] = CRGB(255,0,0);
    
  }
}
void circle6White(){
    for(int pixel = 40; pixel < 46; pixel++){
    leds[pixel] = CRGB(255,255,255);
    
  }
}
void circle7Red(){
    for(int pixel = 48; pixel < 54; pixel++){
    leds[pixel] = CRGB(255,0,0);
    
  }
}
void circle7White(){
    for(int pixel = 48; pixel < 54; pixel++){
    leds[pixel] = CRGB(255,255,255);
    
  }
}
void circle8Red(){
    for(int pixel = 56; pixel < 62; pixel++){
    leds[pixel] = CRGB(255,0,0);
    
  }
}
void circle8White(){
    for(int pixel = 56; pixel < 62; pixel++){
    leds[pixel] = CRGB(255,255,255);
    
  }
}

Whoaaa Blackfin, this actually is quite good already.

I'll work a bit further on this code, but this was really helpful.
Yesterday I gave all the circles a value, and selected random numbers, which already worked a bit, but the speed wasn't really good. This is better.

Thanks!

darthvader072:
Whoaaa Blackfin, this actually is quite good already.

No offence to Blackfin, who was attempting to solve your problem in the way you stated it.

But this is not quite good, it is quite stupid.

Look at your 14 functions. They are duplicates of each other, apart from minor differences which could be given as parameters. Reduce 14 functions to 1 and give it randomised parameters. Less complex, less code, no need for arrays of pointers to functions.

A single function that can write any color into any of the 8 circles:

CRGB Colors[2]  {CRGB(255,0,0), CRGB(255,255,255)};


// index = 0 through 7 for the 8 circles
// color = Colors[0] for Red, Colors[1] for White
void circle(int index, CRGB color){
    for(int pixel = index * 8; pixel < (index * 8) + 6; pixel++){
    leds[pixel] = color;
    FastLED.show();
  }
}

I would start by changing the pattern rapidly, then slow down, then (at about 500 milliseconds between changes) go black for 500 milliseconds, then show the final pattern.

  for (unsigned stepDelay = 10; stepDelay < 500; stepDelay += 20)
  {
    RandomColors();  // Fill the 8 circles with Red or White
    delay(stepDelay);
  }

  for (int i=0; i < NUM_LEDS; i++)
    leds[i] = CRGB(0,0,0);
  FastLed.show();
  delay(500);

  RandomColors(); // This is the target pattern

PaulRB:
No offence to Blackfin, who was attempting to solve your problem in the way you stated it.

But this is not quite good, it is quite stupid.

Look at your 14 functions. They are duplicates of each other, apart from minor differences which could be given as parameters. Reduce 14 functions to 1 and give it randomised parameters. Less complex, less code, no need for arrays of pointers to functions.

As you note, my goal was to randomize his functions as requested, not re-write the entire thing for him. There is obviously room for consolidation and optimization.

FWIW, I don't really see the issue with the scary-sounding "arrays of pointers to functions." It would give more flexibility if he wanted to expand the number of rings, rings with different LED counts or the type of patterns sent during the random pattern period (or the addition of effects like rainbows, fading etc) by decoupling the display effect functions from the randomization loop itself.

@johnwasser's code is tight and elegant but if the OP wanted to add different effects or make other changes that code's super-focused architecture would make that hard to do.

YMMV.

After the lights turn off, how do you know if the player has put the balls in the right spot?

You want a button which, after the lights are off, will turn them on again so you can check the result. Short click to check the result, long click to re-randomize. Or just use two buttons - probably simpler.

PaulRB:
No offence to Blackfin,

But this is not quite good, it is quite stupid.

I am sorry but it does sound a little offensive. Blackfin helped me out amazingly and I think he has done so here as well.

I think you should read what you write and think about it before hitting the post button.

Blackfin:
@johnwasser's code is tight and elegant but if the OP wanted to add different effects or make other changes that code's super-focused architecture would make that hard to do.

I don't see how one function that can write any color to any circle is more restrictive than 16 separate functions that can each write one color to one circle. I think the limiting assumption was that an array of pointers to functions that took no arguments was a better solution than a function that takes arguments and an array of parameters. :slight_smile:

windoze_killa:
I am sorry but it does sound a little offensive. Blackfin helped me out amazingly and I think he has done so here as well.

I think you should read what you write and think about it before hitting the post button.

I'm sorry if you are upset, but I think it was quite clear that I was not criticising Blackfin at all, and I believe from Blackfin's response that he/she understood that.

My "stupid" reference was to the OP's code, where 1 function has been copied and pasted 14 times over with only minor amendments. Blackfin kindly fixed the OP's immediate problem, but I felt it important for the OP to understand that the method the OP attempted to use to deal with the original mistake (of the 14 near-identical functions) was not a "quite good" idea. Simpler is almost always better, and duplicated code is almost always a bad thing. Fix the original problem, rather than introducing more complexity to get around it.