Je suis sur un petit projet très simple : Allumer aléatoirement 3 LED différentes parmi 9 LED NeoPixel.
Jusque là rien de bien compliqué. Sauf que dans ma version (cf code ci dessous), l'arduino allume parfois 2 Led parfois 3. Cela est du au fait je pense que deux variables peuvent prendre la même valeur...
Comment donc exclure une valeur dans la fonction random ? Est-ce possible ?
Où la meilleure solution serait de faire des boucles : si la valeur est égal à une précédente, relancer le dé jusqu'à ce que cette dernière soit différentes des autres ?
Merci par avance pour votre aide
Guillaume
c++
/*Le projet Trobar est réalisé dans le cadre du marathon créatif paserelle.infini eyant eu lieu à la paserelle à Brest le 9 et 10 mars 2023.
Il est le programme du second prototype réalisé au moyen d'une Arduino Nano
Ce code alume 9 led à la pression d'un bouton poussoir et choisis au hasard une des 9 cases qu'il allumera en blanc*/
#include <Adafruit_NeoPixel.h> //Nécessite de préinstaller dans votre IDE la librairie Adafruit_NeoPixel.h
#ifdef __AVR__
#include <avr/power.h>
#endif
// Défini le numéro de broche où sera connecté le fil de datas du ruban LED
#define PIN 3
// Combien de DEL y a t-il sur votre trobar ?
#define NUMPIXELS 9
Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
//Défini le numéro de broche où sera connecté le bouton poussoir
int bouton=2;
//Défini une variable qui servira à choisir un nombre aléatoire. Ne pas modifier cette variable.
int nbreAleatoire1=0;
int nbreAleatoire2=0;
int nbreAleatoire3=0;
void setup(){
pinMode(bouton, INPUT_PULLUP);
strip.begin(); // Initialise le ruban LED
}
void loop(){
if(!digitalRead(bouton)){
strip.clear();
depart(50);
delay(1000);
strip.clear();
nbreAleatoire1 = random(0, 8);
nbreAleatoire2 = random(0, 8);
nbreAleatoire3 = random(0, 8);
strip.setPixelColor(nbreAleatoire1, strip.Color(150, 150, 150));
strip.setPixelColor(nbreAleatoire2, strip.Color(150, 150, 150));
strip.setPixelColor(nbreAleatoire3, strip.Color(150, 150, 150));
strip.show();
}
}
void depart(int wait){
int firstPixelHue = 0; // Premier pixel démarre sur rouge
for(int a=0; a<60; a++) { // Répète 60 fois
for(int b=0; b<3; b++) {
strip.clear();
for(int c=b; c<strip.numPixels(); c += 3) {
int hue = firstPixelHue + c * 65536L / strip.numPixels();
uint32_t color = strip.gamma32(strip.ColorHSV(hue));
strip.setPixelColor(c, color);
}
strip.show();
delay(wait);
firstPixelHue += 65536 / 90;
}
}
}
Ce n'est pas une mauvaise solution et c'est la plus simple à programmer (si on joue de malchance, ça peut durer très longtemps)....
Pour éviter de jouer de malchance (quelqu'un qui ne tirerait que des "six" pendant un temps fou)
, l'algorithme https://www.irem.univ-mrs.fr/IMG/pdf/tirage_sans_remise-2.pdf s'effectue à temps constant et est un peu plus difficile à programmer que votre solution (nécessite un petit tableau en plus)...
Peut être avec un tableau de booléens qui indique si le chiffre est déjà tiré:
const byte hasMaximum = 9; // Valeur maximum
const byte hasNombre = 3; // Nombre de chiffres au hasard
boolean hasChiffreTire[hasMaximum]; // Marquage des chiffres tirés
void setup()
{
Serial.begin(115200);
}
void loop()
{
hasardTirage();
hasardTirageAffichage();
delay(1000);
}
void hasardTirageAffichage()
{
Serial.print(F("LED a allumer\t"));
for (byte t = 0; t < hasMaximum; t ++) // Lister tout le tirage
{
if (hasChiffreTire[t]) // Si le chiffrre a été tiré
{
Serial.print(String(t) + "-");
}
}
Serial.println("");
}
void hasardTirage()
{
for (byte t = 0; t < hasMaximum; t ++) // Mettre le tableau tout à false
{
hasChiffreTire[t] = false;
}
for (byte t = 0; t < hasNombre; t ++)
{
while (1) // Boucle infinie
{
byte tirage = random(0, hasMaximum); // Tirage aléatoire
if (!hasChiffreTire[tirage]) // Si pas encore tiré
{
hasChiffreTire[tirage] = true; // Tirage enregistré
break; // On quitte la boucle
}
}
}
}
Bonjour jphbricole
Votre hazardTirage a un temps d'execution potentiellement infini (que se passe-t-il si random devient très bègue? elle prendra un temps fou... (ça fait partie de sa nature aleatoire)
Une solution (mange 8 bytes de plus) qui évite de jouer de malchance (testée sur PC; a adapter) est:
// adapté de https://en.wikipedia.org/wiki/Random_permutation
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
uint8_t uniform(uint8_t maxi) { // emule grossièrement random(0, maxi) de Arduino
return (uint8_t) (rand() % maxi);
}
// fin des initialisations specifiques au PC
void initialize_and_permute(uint8_t permutation[], uint8_t n) {
uint8_t aux;
for (uint8_t i = 0; i <= n - 2; i++) {
uint8_t j = i + uniform(n - i); /* A random integer such that i ≤ j < n */
aux = permutation[i];
permutation[i] = permutation[j];
permutation[j] = aux;
}
}
/* specifique au PC
sur arduino a_permuter[ ] = {0,1,2,3,4,5,6,7};
initialize_and_permute( a_permuter, 8);
puis nbreAleatoire1 = apermuter[0];
... nbreAleatoire3 = a_permuter[2]:
*/
int main() {
uint8_t a_permuter[ ] = {10,24,3,4,5,6,7,8};
initialize_and_permute( a_permuter, 8);
for (uint8_t i =0; i < 8; i ++ ) printf("%d \n", a_permuter[i]);
}
Bonjour à toustes,
Merci pour vos réponses. J'ai opté pour la solution de boucle.
Voilà mon code :
c++
/*Le projet Trobar est réalisé dans le cadre du marathon créatif paserelle.infini eyant eu lieu à la paserelle à Brest le 9 et 10 mars 2023.
Il est le programme du second prototype réalisé au moyen d'une Arduino Nano
Ce code alume 9 led à la pression d'un bouton poussoir et choisis au hasard une des 9 cases qu'il allumera en blanc*/
#include <Adafruit_NeoPixel.h> //Nécessite de préinstaller dans votre IDE la librairie Adafruit_NeoPixel.h
#ifdef __AVR__
#include <avr/power.h>
#endif
// Défini le numéro de broche où sera connecté le fil de datas du ruban LED
#define PIN 3
// Combien de DEL y a t-il sur votre trobar ?
#define NUMPIXELS 9
Adafruit_NeoPixel strip(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
//Défini le numéro de broche où sera connecté le bouton poussoir
int bouton=2;
//Défini une variable qui servira à choisir un nombre aléatoire. Ne pas modifier cette variable.
int nbreAleatoire1=0;
int nbreAleatoire2=0;
int nbreAleatoire3=0;
void setup(){
Serial.begin(9600);
pinMode(bouton, INPUT_PULLUP);
strip.begin(); // Initialise le ruban LED
}
void loop(){
if(!digitalRead(bouton)){
strip.clear();
depart(50);
delay(1);
strip.clear();
nbreAleatoire1 = random(0, 8);
nbreAleatoire2 = random(0, 8);
nbreAleatoire3 = random(0, 8);
while (nbreAleatoire2 == nbreAleatoire1){
nbreAleatoire2 = random(0, 8);
}
while (nbreAleatoire3 == nbreAleatoire1 || nbreAleatoire3 == nbreAleatoire2) {
nbreAleatoire3 = random(0, 8);
}
strip.setPixelColor(nbreAleatoire1, strip.Color(150, 0, 0));
strip.setPixelColor(nbreAleatoire2, strip.Color(0, 0, 150));
strip.setPixelColor(nbreAleatoire3, strip.Color(0, 150, 0));
strip.show();
Serial.println(nbreAleatoire1);
Serial.println(nbreAleatoire2);
Serial.println(nbreAleatoire3);
}
}
void depart(int wait){
int firstPixelHue = 0; // Premier pixel démarre sur rouge
for(int a=0; a<60; a++) { // Répète 60 fois
for(int b=0; b<3; b++) {
strip.clear();
for(int c=b; c<strip.numPixels(); c += 3) {
int hue = firstPixelHue + c * 65536L / strip.numPixels();
uint32_t color = strip.gamma32(strip.ColorHSV(hue));
strip.setPixelColor(c, color);
}
strip.show();
delay(wait);
firstPixelHue += 65536 / 90;
}
}
}