In welchem Wertebereich soll das ganze den spielen und wie oft brauchst du eine Zahl "zufälliger" Größe?
Du könntest ja auch mit eine Kombination aus verschiedenen Berechnungsschritten spielen und dafür Größen verwenden die sich eh ständig ändern - z.b. die aktuellen millis() durch das heutige Datum teilen und dann quadrieren oder so...
Aus eigener Praxis:
Ich baue zu jedem Programm eine Art "Splash-Screen" mit "Weiter-Button" und messe die Zeit zwischen Start und 1. Tastendruck in Millis. Dieser Wert ist nicht reproduzierbar und kann optimal für RandomSeed genutzt werden.
LG, Rudi
Der Wertebereich beträgt 0 bis 6, diese Zahlen möchte ich generieren.
@Rudi:
Du erinnerst dich bestimmt noch an mein Tetris-Projekt, für das ist es, ich habe noch ein paar Kleinigkeiten geändert und nun kommen bei Beginn des Tetrisspiels immer die gleichen 2-3 Blöcke, wahrscheinlich noch mehr aber naja.
Dann ist das Problem mit dem analogen Eingang, dass du bei 12bit Auflösung 4096 Werte generieren kannst- du willst aber nur 6 . Es könnte besser klappen, wenn du den eigentlichen Bereich vergrößerst und dann durch einen Faktor teilst. z.b. 0 - 600 und dann durch 100 teilen...
Vernünftigen Pseudo-Zufall bekommst du wenn du den Jitter zwischen dem Watchdog-Timer und einem normalen Timer verwendest. Der WDT hat einen eigenen RC-Oszillator. Deshalb laufen die nicht gleich
Der Wertebereich beträgt 0 bis 6, diese Zahlen möchte ich generieren
Das ist völlig irrelevant.
Eine Pseudo-Random-Zahlenreihe hat (bei unseren 8-bit Arduinos) 65535 4294967296 Elemente, danach wiederholt sie sich. Ausserdem sollten, egal wie *) man diese Werte auf deine sieben (?) Ergebnisse abbildet, alle Ergebnisse gleich häufig vorkommen und auch andere Zufallskriterien möglichst gut zutreffen.
Das Haupt-Problem bei "noch mehr Zufall" ist, dass die Zahlenreihe immer reproduzierbar gleich abläuft, wenn man den Anfangswert immer gleich (oder gar nicht, d.h. auf 0) setzt.
Mit einem analogRead kann man theoretisch einen von 1024 möglichen zufälligen Messwerten erwischen.
In der Praxis misst man aber eher immer "fast" dasselbe und erhält so nur wenige verschiedene Startpunkte.
Serenifly's Link hat den Vorteil, dass keine zusätzliche externe Hardware (z.B. Manuell betätigter Taster ) erforderlich ist.
Bei deinem Tetris-Spiel wäre das Auswerten eines Start-Tasters (Zeit seit Reset und/oder Dauer) reichlich "mehr Zufall" für deine Erfordernisse.
*) "egal wie" macht die random - Funktion schon ganz ordentlich, da denkt MaHa76 in die falsche Richtung.
oder mal microsekunden/Millisekunden messen und nen Modulo auf 7 machen..
6 ist außerdem nicht viel.. vielleicht müsste man bei 6 schon einen 20-100 Samples Lookup machen um häufigkeiten auszugleichen.. damit könnte man Gleichmäßigen Häufigkeiten entgegenwirken aber auch ebenso zuviel verteilte Zufälligkeit wie 3mal X hintereinander stoppen.
Im Prinzip eine Array Element Analyse der letzten 20 Random/korrigierten Zahlen und mit einer kleinen eigenen "KI-Logik" Gegenspielen.
EDIT: oder 6 zusätzliche Variablen in denen man die verteilung abspeichert.. z.B. count0,...., count6
sollte ja im Prinzip auch gleichmäßig werden. Gerade bei Tetris müssste man vielleicht auch Häufigkeit steuern damit man vernünftig "Bauen" kann.
Du kannst eine RTC verwenden, so hast Du einen quasi nichtreproduzierbaren Wert.
Wenn es Dein Code erlaubt, kann man millis(); einbauen, dazu brauchst Du aber einen externen Trigger, sprich einen Taster (oder etwas ähnliches) der zum Beispiel als Programm Start dienen soll.
Ich hab auch schon gesehen das jemand einfach ein längeren Stück Draht (quasi als Antenne) an den Analog Pin angeschlossen hat, das erhöht den Zufall.
Du kannst auch einen Temperatur Sensor an A0 anschließen und den Wert mit analogRead(A1) multiplizieren (oder den Durchschnitt).
In diesem Thread wurden sehr viele Möglichkeiten, einen Zufall zu erzeugen, erläutert.
Eine Kombination aus millis() und AnalogRead() wäre auch eine Möglichkeit aber bei millis() braucht man einen Trigger... und wenn es ein Tastendruck auf einer Fernbedienung ist. Für einen Koketten Vorschlag wäre der Code nicht schlecht.
Es stammt irgenwi aus den Tiefen des Forums, ich weiß aber nicht mehr die Quelle.
Von jedem der 32 analogRead wird nur das niederwertigste Bit genommen und daraus eine 32 Bit Startzahl gebaut.
// etwas zufälligerer Startwert für Zufallsgenerator
void seedRandom32(uint8_t analogPort) {
uint32_t wert = analogRead(analogPort) & 0x1;
for(uint8_t i = 0; i < 32; i++) {
wert = wert << 1;
wert |= analogRead(analogPort) & 0x1;
}
randomSeed(wert);
}
Es reicht, wenn du vom Millis()-Wert die untersten 2 Bytes (also Integer) als Init-Wert für RandomSeed übernimmst. Dieser ändert sich bekanntlich 1000x in der Sekunde und es muss schon mit dem Teufel zugehen - wenn du nach dem Einschalten immer wieder in der selben Millisekunde auf den Start-Button drückst... Mir selbst ist es noch nicht gelungen und ich bekomme bei solchen Programmen generell unterschiedliche Ergebnisse.
Seed ist ein uint32_t Wert.
Genau das was millies() liefert.
Ich sehe da keinen besonderen Grund, den zu beschneiden.
Oder gar Vorzeichen behaftet zu machen.
Hast Recht combie! Das muss ich wohl überlesen haben. Egal, die Millis zwischen Boot und 1. Tastendruck liefern mir immer sehr brauchbare Ergebnisse - wenn ich mal Pseudo-Zufall brauche.
nach einem ersten Tastendruck reicht für diesen Anwendungsfall völlig aus.
Wenn man annimmt, dass üblicherweise nur eine kurze Zeit nach Reset vergehen wird, hat man aber die gesamte Vielfalt möglicher Initialwerte längst nicht ausgeschöpft.
randomSeed(micros()>>2); wäre etwa 256 Mal besser , aber das ist hier völlig wurscht;)
Man kann doch auch eine Prüfsumme von dem millis() oder micros() Wert 'errechnen' - halt, daß ein bisschen Leben in den Bithaufen kommt und nicht nur 22 Nullen gefolgt von einer kleinen binären vergangenen Zeit.
(wenn binnen der ersten Sekunde gedrückt würde - aber selbst nach 10 Sekunden haben wir bei Weitem die 32 Bit nicht ausgenutzt).
daß ein bisschen Leben in den Bithaufen kommt und nicht nur 22 Nullen gefolgt von einer kleinen binären vergangenen Zeit.
Man kann viel Unnützes machen.
Das Ziel ist, ausreichend viele verschiedene randomSeed Werte zu haben.
Ob du (untertrieben) zwei RandomSeed-Werte von 0 und 1, oder aber entweder 1234 oder 987989798123 hast: In beiden Fällen erhältst du eine von nur zwei möglichen Zufallszahlenfolgen, die jeweils anders als die andere ablaufen. In jeweils beiden Fällen ist in der resultierenden random() Reihe "gleichviel Leben".
Wenn du z.B. mit millis() die Dauer des Start-Tasters misst, und weisst wie dein Sketch abläuft und daher so kurz wie möglich drückst, erhältst du Zeiten von ca. 10..30 ms, also ca. 20 verschiedene randomSeed - Werte. Das ist schon so viel, dass du die daraus entstehenden verschiedenen Sequenzen von 7 verschiedenen Tetris-Figuren nur mit sehr viel Übung wiedererkennen kannst, und wohl -selbst wenn- nicht viel damit anfangen kannst. Kannst aber trainieren, den kürzestmöglichen Tastendruck reproduzierbarer hinzukriegen.
Wenn du statt millis() nun micros() verwendest und weisst, dass micros() nur in Viererschritten hochzählt, hast du statt ca. 20 Zufalls-Sequenzen ca. 5000 verschiedene Sequenzen.
Hast Recht - die Anzahl ändert sich ja erst 'mit der Zeit' und jeder weitere Seed ergibt eine 'neue' Reihenfolge.
... man muß nur Mal drüber NACHdenken - nicht die Anzahl der unterschiedlichen Bits, sondern die Anzahl der verschiedenen Kombinationen ist ausschlaggebend.