Benötige Hilfe! Zufallszahlen eingrenzen (Lotto)
-
Für Zufallszahlen aus einer kleinen Menge ginge das hier. Es wird eine Menge aller möglichen Zufallszahlen erzeugt und gemischt. Anschliessend kann per next() die erste Zahl aus der Menge gelesen werden, die dann aus der Menge entfernt wird. Damit ist es unmöglich, Duplikate zu bekommen, da alle gezogenenen Zahlen aus der Menge der verbleibenden Kandiaten entfernt werden.
#include <cassert> #include <vector> #include <iostream> #include <algorithm> class RangeRNG { std::vector<unsigned int> Numbers_; public: RangeRNG( unsigned int Min, unsigned int Max ) { First = std::min( Min, Max ); Last = std::max( Min, Max ); Numbers_.reserve( Last - First +1 ); while( First <= Last ) Numbers_.push_back( First++ ); std::random_shuffle( Numbers_.begin(), Numbers.end() ); } bool empty() const { return Numbers_.empty(); } unsigned int next() { assert( !empty() ); // aus Performancegründen werden Zahlen von hinten aus // dem Vektor entfernt... auch wenn´s nur Spielerei ist unsigned int n = Numbers_.back(); Numbers_.erase( Numbers_.end() -1 ); return n; } }; int main() { RangeRNG Lottoziehung( 1,49 ); for( unsigned int i = 0; i < 6; ++i ) { std::cout << "Zahl " << i << ": " << Lottoziehung.next() << std::endl; } }Edit: Anfangsposting nur halb gelesen und für das typische Anfänger-Lottozahlen-Problem gehalten und dazu eine Lösung gebastelt...
-
dann erklähr mir doch bitte mal warum das bullshit ist!?
es funktionier doch so!
ich habe jetzt auch meine erste anforderung gelöst mit ner do-while schleife.
aber wenn er keine zahlen mit der summe zwischen 142-156 findet, dauert jede neue berechnung der zahlen immer länger.
was kann ich machen um den zwichenspeicher zu löschen, das er quasi wieder ganz von forne anfängt?
-
uuuups nicht aktuallisiert!
ein zahlen paar = zwei auf einander folgende zahlen z.b. 35, 36
-
#include "stdafx.h" #include <iostream> #include <time.h> #include <string> int _tmain(int argc, _TCHAR* argv[]) { unsigned int zufallszahlen[6]; bool eindeutig = false; bool valid = false; unsigned int anzKlein = 0; unsigned int anzGerade = 0; unsigned int summe = 0; srand((unsigned)time(NULL)); while (!valid) { for (int i = 0; i<6; i++) { while (!eindeutig) { int zufallszahl = rand()%49+1; zufallszahlen[i] = zufallszahl; eindeutig = true; for (int j = 0; j<i; j++) { if (zufallszahl == zufallszahlen[j]) eindeutig = false; } } eindeutig = false; } // sortieren for (int i = 0; i<6-1; i++) { for (int j = i+1; j<6; j++) { if (zufallszahlen[i] > zufallszahlen[j]) { int temp = zufallszahlen[i]; zufallszahlen[i] = zufallszahlen[j]; zufallszahlen[j] = temp; } } } anzKlein = 0; anzGerade = 0; summe = 0; // Kleine zählen for (int i = 0; i<6; i++) if (zufallszahlen[i] <25) anzKlein++; // Gerade zählen if (anzKlein == 2) { for (int i = 0; i<6; i++) if (zufallszahlen[i] %2 == 0) anzGerade++; // Summe berechnen if (anzGerade == 2) { for (int i = 0; i < 6; i++) summe += zufallszahlen[i]; // Nach Pärchen prüfen if (summe >=142 && summe <= 156) for (int i = 0; i<6-1; i++) if (zufallszahlen[i]+1 == zufallszahlen[i+1]) valid = true; } } } for (int i = 0; i<6; i++) std::cout << zufallszahlen[i] << " "; getchar(); return 0; }
-
keyzer777 schrieb:
dann erklähr mir doch bitte mal warum das bullshit ist!?
es funktionier doch so!Nö, tuts nicht, du erkennst es bloß nicht. Wenn du zu faul bist zu googlen und ein wenig selbst nachzudenken, probier doch mal sowas:
while(true) { srand(time(NULL)); int i = rand(); cout << i << "\n"; }
-
Mit welcher IDE arbeitest du? Unter Code-Blocks wurden mehrere Fehler ausgegeben.
Unter Einbindung dieser Bibliotheken geht es:#include <iostream> #include <cstdio> #include <cstdlib> #include <time.h>
-
hi matze-o
bei deinem programm blicke ich so einigermasen durch leider funzt es nicht.`_TCHAR has not been declared
auch mit #include "stdafx.h"
kann ich nichts anfangen
grüße
ach noch ne frage kanns auch daran liegen das ich nur den dev-C++ nutze?
-
keyzer777 schrieb:
hi matze-o
bei deinem programm blicke ich so einigermasen durch leider funzt es nicht.Doch es funktioniert, musst nur die includes ändern:
#include <iostream> #include <cstdio> #include <cstdlib> #include <time.h>Und lad dir anstatt devc++ lieber Code::Blocks, das wir noch weiterentwickelt!
-
volkard schrieb:
brotbernd schrieb:
class SupaDupaDistribution { public: SupaDupaDistribution() : ..., dist(0,49), ... {} unsigned int operator()() { unsigned int n = dist(eng); if (good(n)) return n; else nochmal //(bzw while nicht good) } private: size_t count, odd, sum usw... std::mt19937 eng; // o.a. std::uniform_int<unsigned int> dist; };Was soll das denn?
Das ist ne Mischung aus C++ und Pseudocode

Ziehe ne Zufallszahl so lange sie bestimmte Bedingungen erfüllt. Ich dachte das könne man vielleicht daraus ablesen.
-
ja das hab ich auch nich kapiert was da steht...
sack und asche wenn ich bei einer do-while-schleife eine UND bedingung festlegen will könnte das doch so aussehen?
do
{
blablabla
}
while ( summe >= 142 && summe <= 156);er soll nur weiter machen im programm, wenn die zahl aus bla bla zwischen 142 und 156 liegt!
das macht er irgendwie nicht er beachte irgendwie nur die erste regel.und kann ich dann noch mehrere bedingungen in die gleiche klammer einbauen? wieviele?
-
keyzer777 schrieb:
er soll nur weiter machen im programm, wenn die zahl aus bla bla zwischen 142 und 156 liegt!
das macht er irgendwie nicht er beachte irgendwie nur die erste regel.Das ist aber richtig, so wie es da steht. Du hast vermutlich noch einen anderen Fehler im Programmablauf.
und kann ich dann noch mehrere bedingungen in die gleiche klammer einbauen? wieviele?
So viele wie du willst. Achte bei komplizierten logischen Ausdrücken aber auf die Rangfolge der Operatoren und setz gegebenenfalls Klammern.
-
keyzer777 schrieb:
do
{
blablabla
}
while ( summe >= 142 && summe <= 156);er soll nur weiter machen im programm, wenn die zahl aus bla bla zwischen 142 und 156 liegt!
Da steht aber: tue blablabla solange summe zwischen 142 und 156 und nicht höre auf wenn ...
Wenn der Ausdruck in while() wahr ist, wird die Schleife wiederholt.
-
brotbernd schrieb:
Da steht aber: tue blablabla solange summe zwischen 142 und 156 und nicht höre auf wenn ...
Wenn der Ausdruck in while() wahr ist, wird die Schleife wiederholt.Ach so war das gemeint mit dem "weitermachen". Ich hatte gedacht "mach weiter mit der Schleife" wäre gemeint. war schon total verwirrt, wie man bei der Konstruktion etwas falsch machen kann.
@keyzer777: Ein paar Vokabeln Englisch helfen solche Fehler in Zukunft zu vermeiden.
-
SeppJ schrieb:
@keyzer777: Ein paar Vokabeln Englisch helfen solche Fehler in Zukunft zu vermeiden.
Vielleicht mit REPEAT UNTIL verwechselt..

-
Müsste nicht das hier auch gehen (Nur auf die schnelle hingeklatscht):
bool weiter = false; int summe; int i = 0; // Durchgänge while(!weiter && i < 6) { // Berechnungen rein usw. if(summe >= 142 && summe <= 156) { weiter = true; } }
-
schrieb:Müsste nicht das hier auch gehen (Nur auf die schnelle hingeklatscht):
Ja, aber wieso sollte man so etwas tun?

-
schrieb:Müsste nicht das hier auch gehen (Nur auf die schnelle hingeklatscht):
bool weiter = false; int summe; int i = 0; // Durchgänge while(!weiter && i < 6) { // Berechnungen rein usw. if(summe >= 142 && summe <= 156) { weiter = true; } }.........!!
-
keyzer777 schrieb:
Da ich leider schon länger nicht mehr mit C++ gearbeitet hat komme ich zur Zeit da nicht weiter und hoffe das mir hier vielleicht jemand etwas unter die Arme greifen kann.
Hallo keyzer,
unabhängig davon, ob Du mit C++ oder einer anderen Sprache arbeitest, sollte man sich vorher überlegen, wie man sein Problem in kleine handliche Teile zerlegen kann. In Deinem Fall gibt es eine Menge verschiedener Möglichkeiten - eine naheliegende, die hier auch schon angewendet wurde, ist:
1.) 6 verschiedene Zahlen aus 1 bis 49 bestimmen
2.) prüfen, ob diese die gewünschten Eigenschaften haben
3.) wenn nein, dann bei 1.) weitermachen
4.) Zahlen ausgebenAllein für den Teil 1.) ist hier im Forum schon einiges gesagt worden, suche einfach mal nach dem Stichwort 'Lotto'. Um 6 paarweise verschieden(!) Zahlen aus 1 bis 49 zu bestimmen gibt es im wesentlichen zwei Möglichkeiten:
1a) bestimme eine Zahl zwischen 1 bis 49
1b) falls sie noch nicht im Ergebnis vorkommt, füge sie hinzu
1c) falls noch keine 6 Zahlen beisammen sind, mache bei 1a) weiteroder
1a) generiere eine Menge von Zahlen von 1 bis 49
1b) mache 6 mal:
1c) wähle zufällig eine Zahl aus der Menge aus und lösche sie dort und füge sie dem Ergebnis hinzuDie erste Variante ist vielleicht einfacher zu codieren, aber hat u.a. den Nachteil, dass sie länger dauert, wenn eine Zahl ausgewählt wird, aber nur noch wenige zur Auswahl stehen. Bei 6 aus 49 ist das noch kein Problem, aber da Du weitere Bedingungen eingeführt hast, die die Auswahl irgendwann einschränken, würde ich hier die zweite Variante wählen.
Dazu baue ich zunächst eine Klasse, die den Pott von 49 Kugeln (jede Kugel mit einer Zahl drauf) modelliert. Dort kann man zufällig Zahlen entnehmen.
#include <cstdlib> // rand, srand #include <iostream> #include <ctime> // time() #include <vector> class _49 { public: _49() : m_kugeln() { // hier wird 'm_kugeln' mit den Werten von 1 bis 49 gefüllt for( int kugel = 1; kugel <= 49; ++kugel ) m_kugeln.push_back( kugel ); } // -- liefert zufällig eine der noch enthaltenen Kugeln und entfernt sie aus der Menge int zieheEineKugel() { init(); using namespace std; const vector< int >::iterator zufaelligerIndex = m_kugeln.begin() + int( (rand() / (RAND_MAX+1.0)) * m_kugeln.size() ); const int gezogeneKugeln = *zufaelligerIndex; m_kugeln.erase( zufaelligerIndex ); return gezogeneKugeln; } private: static void init() { if( !m_initialized ) { using namespace std; srand( static_cast< unsigned int >( time(0) ) ); m_initialized = true; } } static bool m_initialized; std::vector< int > m_kugeln; }; bool _49::m_initialized = false; int main() { using namespace std; _49 kugeln; for( int i = 0; i < 6; ++i ) cout << kugeln.zieheEineKugel() << endl; return 0; }im main() ist ein einfaches Beispiel, wie diese Klasse zu benutzen ist. Also einfach ein Objekt mit diesem Typ anlegen - hier 'kugeln' und dann immer eine ziehen. Es ist garantiert, dass Du nie zwei Kugeln mit dem gleichem Wert ziehst.
Jetzt gehe ich einen kleinen Schritt weiter und betrachte die Ziehung der 6 Kugeln als Einheit. Ziel ist es, eine Ziehung vom einem Algorithmus generieren zu lassen
#include <algorithm> // copy #include <cstdlib> // rand, srand #include <ctime> // time() #include <iostream> #include <iterator> // ostream_iterator #include <set> #include <vector> class _49 ... // wie oben // -- liefert 6 'Kugeln' aus 1 bis 49 std::set< int > ziehung_6_aus_49() { _49 kugeln; std::set< int > ergebnis; for( int i=0; i<6; ++i ) ergebnis.insert( kugeln.zieheEineKugel() ); return ergebnis; } int main() { using namespace std; set< int > gezogenenKugeln = ziehung_6_aus_49(); // -- Ergebnis der Ziehung ausgeben copy( gezogenenKugeln.begin(), gezogenenKugeln.end(), ostream_iterator< int >( cout, " " ) ); cout << endl; return 0; }damit wäre der oben erwähnte Teil 1 erledigt; und Teil 4 bei der Gelegenheit auch - sonst sieht man ja nicht, ob Teil 1 erfolgreich war

Jetzt zu "2.) prüfen, ob diese die gewünschten Eigenschaften haben".
Hier kann man massiv Algorithmen aus dem C++-Standard einsetzen. Zusammen mit dem Funktoren aus <functional>. Ich unterstelle mal, dass Du damit nicht vertraut bist, aber ich versuch' es trotzdem mal - wir sind ja hier schließlich im C++-Forum und das ist alles Standard!#include <algorithm> // copy #include <cassert> #include <cmath> // abs #include <cstdlib> // rand, srand #include <ctime> // time() #include <functional> // bind*, less, usw. #include <iostream> #include <iterator> // ostream_iterator #include <numeric> // accumulate #include <set> #include <vector> class _49 ... // wie oben // -- liefert 6 'Kugeln' aus 1 bis 49 std::set< int > ziehung_6_aus_49() .. // wie oben struct istPaerchen : std::binary_function< int, int, bool > { // liefert true, falls a und b ein Pärchen sind result_type operator()( first_argument_type a, first_argument_type b ) const { return std::abs( a - b ) == 1; } }; // -- liefert 'true', falls die Menge der gezogenen Kugeln im Intervall [first,last) // die Anforderungen erfüllt template< typename T > bool passt( T first, T last ) { using namespace std; assert( distance( first, last ) == 6 ); const int summe = accumulate( first, last, 0 ); return summe >= 142 && summe <= 156 // 142 <= summe <= 256 && count_if( first, last, bind2nd( less< int >(), 25 ) ) == 2 // 2 mal x < 25 && count_if( first, last, bind2nd( greater< int >(), 25 ) ) == 4 // 4 mal x > 25 && count_if( first, last, bind2nd( modulus< int >(), 2 ) ) == 4 // 4 mal x ist ungerade (=> 2 mal gerade) && adjacent_find( first, last, istPaerchen() ) != last // mindestens ein Pärchen existiert ; } int main() { using namespace std; set< int > gezogenenKugeln = ziehung_6_aus_49(); // -- Ergebnis der Ziehung ausgeben copy( gezogenenKugeln.begin(), gezogenenKugeln.end(), ostream_iterator< int >( cout, " " ) ); cout << endl; cout << "Die Ziehung erfuellt " << (passt( gezogenenKugeln.begin(), gezogenenKugeln.end() )? "" : "NICHT") << " die Anforderungen" << endl; return 0; }Neu ist der Algorithmus 'passt()', der aus einer Menge von (6) 'Kugeln' bestimmt, ob die von Dir gesetzten Anforderungen erfüllt sind.
Wenn Du dieses Programm jetzt ein paar Mal ausführst, so wirst Du merken, dass Deine Anforderungen praktisch nie erfüllt sind. Nach meiner Abschätzung wirst Du das Programm im Mittel 280 Mal aufrufen, bevor es einmal meldet 'Anforderungen erfüllt'. Das geht natürlich einfacher in einer Schleife, und damit sind wir bei
"3.) wenn nein, dann bei 1.) weitermachen" .. und dazu muss man nur noch das main() erweitern:
int main() { using namespace std; set< int > gezogenenKugeln; do { gezogenenKugeln = ziehung_6_aus_49(); } while( !passt( gezogenenKugeln.begin(), gezogenenKugeln.end() ) ); // wiederholen, solange es nicht passt // -- Ergebnis der Ziehung ausgeben copy( gezogenenKugeln.begin(), gezogenenKugeln.end(), ostream_iterator< int >( cout, " " ) ); cout << endl; return 0; }.. das soll für's erste reichen.
Gruß
Werner
-
int( (rand() / (RAND_MAX+1.0)) * m_kugeln.size() );Den Trick werde ich nie verstehen. Jetzt sind nicht mehr die ersten 36 Zahlen um 0.1497% häufiger, sondern die Häufigeren Zahlen verteilen sich jetzt gleichmäßig über das Intervall.
Klingt für mich nach Mystik wiesrand(time(0)*time(0));Mein Tipp: Entweder nicht machen oder richtig machen.
-
Hallo keyzer,
Du wirst vielleicht einwenden, dass mein Vorschlag viel zu kompliziert ist, und nicht mehr macht, als der von matze-o - mal abgesehen davon, dass er die 25 vergessen hat. OK - ich meine komplizierter ist er gar nicht, sondern nur ungewohnt bzw befremdlich für jemanden der das so nicht kennt.
Ein Vorteil liegt darin, dass man den Vorgang der Ziehung jetzt ändern kann, ohne sich mit dem, Rest herumschlagen zu müssen. Ich hatten im ersten Beitrag schon erwähnt, dass es mehr als eine Möglichkeit gibt, zu den von Dir gewünschten Lottozahlen zu kommen. Ein großer Nachteil der bisher vorgestellten Lösungsmöglichkeit ist der Aufwand so viele Lottoziehungen machen zu müssen, bis das gewünschte dabei ist. Die zweite Möglichkeit, die ich hier vorstellen will, soll diesen Nachteil beheben.
1.) generiere den 'Pott' mit 49 Kugeln (class _49)
2.) mache folgendes 6 mal
3.) prüfe ob noch Kugeln vorhanden sind, falls nein beginne von vorn (-> 1.)
4.) ziehe zufällig eine Kugel und füge sie dem Ergebnis hinzu
5.) beseitige alle Kugeln aus dem Pott, die zusammen mit den bereits gezogenen Kugeln nicht mehr in Frage kommen
5.a) -- Ende der Schleife 2.)
6.) Ergebnis ausgebenDas Problem dabei ist, dass das gar nicht so einfach ist, zu bestimmen, welche Kugeln noch in Frage kommen und welche nicht. Deshalb wähle ich einen gemischten Ansatz, wo am Ende immer noch geprüft wird, ob die Anforderungen passen.
Zunächst muss aber _49 noch etwas erweitert werden, Kugeln sollen entfernt werden können und eine Abfrage, ob keine Kugeln mehr da sind, fehlt noch
class _49 { public: _49(); // wie oben int zieheEineKugel(); // wie oben // -- entfernt alle Kugeln mit der Eigenschaft 'pred( kugel ) == true' template< typename F > void remove_if( F pred ) { m_kugeln.erase( std::remove_if( m_kugeln.begin(), m_kugeln.end(), pred ), m_kugeln.end() ); } bool empty() const { return m_kugeln.empty(); } private: static void init(); // wie oben static bool m_initialized; std::vector< int > m_kugeln; };Um die oben beschriebene Vorgehensweise zu erreichen, erweitere ich den Algorithmus der Ziehung
template< typename T > struct KeinPaerchenMoeglich_type : std::unary_function< int, bool > { KeinPaerchenMoeglich_type( T first, T last ) : m_first( first ), m_last( last ) {} result_type operator()( argument_type a ) const { return std::find_if( m_first, m_last, std::bind2nd( istPaerchen(), a ) ) == m_last; } private: T m_first, m_last; }; template< typename T > KeinPaerchenMoeglich_type< T > keinPaerchenMoeglich( T first, T last ) { return KeinPaerchenMoeglich_type< T >( first, last ); } std::set< int > ziehung_6_aus_49_b() { using namespace std; std::set< int > ergebnis; do { ergebnis.clear(); // wg. Wiederholungen _49 kugeln; bool geradeZahlenEntfernt = false; bool ungeradeZahlenEntfernt = false; bool kleiner25Entfernt = false; bool groesser25Entfernt = false; int cntGerade = 0; int cntKleiner25 = 0; kugeln.remove_if( bind2nd( equal_to< int >(), 25 ) ); // Kugel 25 darf nicht drin vorkommen for( int anz = 1; ; ++anz ) { if( kugeln.empty() ) break; const int kugel = kugeln.zieheEineKugel(); ergebnis.insert( kugel ); if( anz == 6 ) break; // <== Schleifenende fertig if( kugel < 25 ) ++cntKleiner25; if( kugel % 2 == 0 ) ++cntGerade; if( anz < 2 ) continue; if( !kleiner25Entfernt && cntKleiner25 == 2 ) { kugeln.remove_if( bind2nd( less< int >(), 25 ) ); kleiner25Entfernt = true; } if( !geradeZahlenEntfernt && cntGerade == 2 ) { kugeln.remove_if( not1( bind2nd( modulus< int >(), 2 ) ) ); geradeZahlenEntfernt = true; } if( anz < 4 ) continue; if( !groesser25Entfernt && (anz - cntKleiner25) == 4 ) { kugeln.remove_if( bind2nd( greater< int >(), 25 ) ); groesser25Entfernt = true; } if( !ungeradeZahlenEntfernt && (anz - cntGerade) == 4 ) { kugeln.remove_if( bind2nd( modulus< int >(), 2 ) ); ungeradeZahlenEntfernt = true; } if( anz == 5 && adjacent_find( ergebnis.begin(), ergebnis.end(), istPaerchen() ) == ergebnis.end() ) { kugeln.remove_if( keinPaerchenMoeglich( ergebnis.begin(), ergebnis.end() ) ); } } } while( ergebnis.size() < 6 ); return ergebnis; }der Rest bleibt gleich; lediglich im main muss statt 'ziehung_6_aus_49()' 'ziehung_6_aus_49_b()' aufgerufen werden. Den Prüfer 'passt' könnte man jetzt noch soweit vereinfachen, nur die Summe zu prüfen, der Rest der Anforderungen ist von 'ziehung_6_aus_49_b()' garantiert.
Gruß
Werner