Benötige Hilfe! Zufallszahlen eingrenzen (Lotto)



  • 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";
    }
    


  • @matze-o:

    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?


  • Mod

    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.


  • Mod

    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;
        }
    }
    

  • Mod

    🙂 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 ausgeben

    Allein 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) weiter

    oder

    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 hinzu

    Die 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 wie

    srand(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 ausgeben

    Das 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



  • volkard schrieb:

    int( (rand() / (RAND_MAX+1.0)) * m_kugeln.size() );
    

    Den Trick werde ich nie verstehen.

    das stand mal im Magazin in Marcus' Artikel "Zufälle gibt's". Inzwischen hat er den Artikel aber überarbeitet.

    volkard schrieb:

    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 wie

    srand(time(0)*time(0));
    

    Mein Tipp: Entweder nicht machen oder richtig machen.

    Und mein Tipp - nicht nur lästern was falsch ist, sondern auch zeigen, wie es richtig geht.

    Gruß
    Werner


Anmelden zum Antworten