Random Zahl auswählen und danach löschen

Hi Forum,

ich möchte mit dem ESP alle x Stunden random eine Zahl zwischen 1 und 30 auswählen und die Zahl dannach aus den "Pool" löschen, sodass diese nicht mehr ausgewählt werden kann. So möchte ich, dass zwar random die Zahlen ausgewählt werden, aber keine doppelt gewählt wird, bis alle zahlen von 1-30 durchgegangen sind. Dann das ganze wieder von vorne.

Hab leider so gar keine Ahnung, wie ich das anstellen soll.
Hat jemand eine idee?

Vielen Dank!

Mfg

Du machst dir ein Array[31] vom typ bool umd füllst es mit Nullen.

Dann schaust Du ob in dem Array die Position mit der gezogenen Zahl als Index = false (0) ist. Ist das der Fall, setzt du die Position auf true(1), was bedeutet, dass diese Zahl schon mal gezogen wurde. Ist diese Position bereits auf true, verwirfst du die Zahl und suchst nach einer neuen.

Das kann aber zum Ende hin lange dauern, bis eine Zahl kommt, die noch nicht gezogen wurde…..

Du nimmst dir einen beliebigen Container, füllst den mit den Zahlen,
Dann einen Auswählen, nutzen und löschen.

Als Container würde sich z.B. vector oder map anbieten.

Sie nehmen ein Array mit 30 Elementen, zunächst mit den Nummern 1 bis 30 in der Reihenfolge.

Sie mischen die Elemente der Tabelle (z. B. Fisher-Yates)

Anschließend wählt man nacheinander die Elemente von Index 0 bis Index 29 aus.

zu spät:
Array mit 1-30 befüllen
Der Reihe nach jedes Feld mit einer zufälligen Position swapen
Danach der Reihe nach von Index 0 - 29 ausgeben.

random link: Shuffle a deck of cards - GeeksforGeeks

const byte maxFeld = 30;
byte byteFeld[maxFeld]; 

void feldInitialisieren() {
  for (byte i = 0; i < maxFeld; i++) {
    byteFeld[i] = i + 1; 
  }
}

void feldMischen() {
  byte temp;
  int index;

  for (byte i = maxFeld-1; i > 0; i--) {
    index = random(i + 1);
    temp = byteFeld[i];
    byteFeld[i] = byteFeld[index];
    byteFeld[index] = temp;
  }
}

void feldAnzeigen() {
  Serial.println("Gemischtes Feld:");
  for (byte i = 0; i < maxFeld; i++) {
    Serial.print(byteFeld[i]);
    Serial.print(" ");
  }
  Serial.println(); 
}

void setup() {
  Serial.begin(115200);
  randomSeed(analogRead(0));
  feldInitialisieren();       // Initialisierung des Felds
  feldMischen();              // Mischen des Felds
  feldAnzeigen();             // Anzeigen des gemischten Felds
}

void loop() {}
1 Like

Wenn du keinen "beliebigen Container" kennst, aus dem du Elemente löschen kannst, nimmst du halt ein Array, das dir sagt, welche Indizes schon gewählt wurden.
Dann brauchst du eine Funktion, die dir sagt, welches das x-te Element ist, mit Überspringen und Mitzählen bereits gelieferter Werte.
Die rufst du jeweils mit x = random(Rest-Anzahl) auf

bool got[30]; // true = hatten wir schon

byte next(byte c) {
  byte i = random(c); // liefert einen Wert 0 .. c-1
  return get(i);
}

byte get(byte i) {
  // liefere i mit überspringen bereits gelieferter Werte 
  byte x;
  for (x = 0; x <= i; x++) 
      if (got[x]) i++;
  x--;
  got[x] = true;
  return x;
}

void setup() {
   Serial.begin(115200);
   //int i;  
   //while ((i=Serial.read()) == -1) {}  // Warte auf eine Eingabe als randomSeed
   //randomSeed(i);  // verschiedene, aber reproduzierbare Reihen
   byte count = sizeof (got);
   while (count) Serial.println(next(count--));
}
  
void loop() { }

Geht's noch kleiner ? :slight_smile:

Vielleicht.....
Da habe ich mal meine Libstdc++ Kenntnisse und Wühlkisteninhalte ausgegraben und auf einem ESP getestet.
Funktioniert mit array und vector gleich gut.
Andere nicht getestet


#include <algorithm>
#include <iterator>
#include <random>
#include <array>
#include <vector>

#include <Streaming.h> // die Lib findest du selber ;-)
Print &cout = Serial; // cout Emulation für "Arme"

//  std::array<int,10> values {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::vector<int> values {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

std::random_device rd;
std::mt19937 g(rd());


void setup()
{
  Serial.begin(9600);
  delay(5000);
  cout << F("Start: ") << F(__FILE__) << endl;
}

void loop()
{
  cout << F("shuffle ") << endl;
  std::shuffle(values.begin(), values.end(), g);
  for(auto &value : values) cout << value << endl;
  delay(5000);
}

Sehr schön, @combie. Klar sollte man im echten Leben Standard-Libraries benutzen, wo immer es geht.

Wenn man allerdings "klein" nach Arduino-Maßstäben misst, braucht man gegen mein

Der Sketch verwendet 2164 Bytes (6%) des Programmspeicherplatzes

mit einem ESP erst gar nicht erst anzufangen.

@JML's Code in #6 kommt (auch auf einem UNO) auf

Der Sketch verwendet 2306 Bytes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.