Zufälliges Wort / Satz ausgeben?



  • Hallo,
    erstmal schön, dass hier auch unregistrierte Benutzer Beiträge schreiben können, find ich gut 😉

    Nun zum Problem:
    Ich bin ein absoluter Anfänger in C++, ich klick mich gerade durch diverse Tutorials und habe noch wenig Erfahrung.

    Ich habe nun ein paar Arrays:

    char wort1[] = {"Hallo"};
    	char wort2[] = {"Welt"};
    	char wort3[] = {"Mir"};
    	char wort4[] = {"geht"};
    	char wort5[] = {"es"};
    	char wort6[] = {"gut"};
    

    Nun möchte ich, über einen Zufallsgenerator, dass ein zufälliges Array ausgegeben wird. Bei Zahlen mache ich das so:

    [code="cpp"]
    srand(timeGetTime());
    ...
    zahl = ( rand() % 100 )
    ...
    cout << zahl;
    [code="cpp"]

    Soweit kenne ich mich mit dem Zufall schon aus 😉

    Wie kann ich aber bestimmte Wörter zufällig ausgeben, im Beispiel soll also entweder "Hallo" oder "Welt" oder "Mir"...ausgegeben werden; oder geht das gar nicht über Arrays?
    Wenn es klappt, kann ich dann auch so mit ganzen Sätzen verfahren?

    Vielen Dank im Voraus
    DerNoob

    PS: Bitte nichts allzu kompliziertes 😞



  • Hi,

    erstmal muss ich dir leider sagen, du bist (leider ein weiteres) Opfer eines C++-Tutorials geworden. Die Chance, dass du ein gutes C++-Tutorial findest liegt irgendwo zwischen 0 und weniger als 0.
    Nun zu deinen Vorhaben. Natürlich kannst du aus einer Liste von Wörtern ein zufälliges auswählen und ausgeben. Was du brauchst, ist eine Liste, die du momentan noch nicht hast. Im Moment hast du einfach nur einzelne Wörter irgendwo. Aber keine Liste. Was du brauchst ist:
    1. std::vector // Repräsentiert dann die Liste.
    2. std::string // Repräsentiert ein Wort (oder auch Satz) der Liste.

    Schau mal, ob du damit weiter kommst :).



  • #include <iostream>
    #include <array>
    #include <string>
    #include <random>
    
    int main()
    {
    	std::random_device rd;
    	std::mt19937 gen(rd());
    	std::uniform_int_distribution<> dis(0, 5);
    
    	std::array<std::string, 6> words = {"Hallo", "Welt", "Mir", "geht", "es", "gut"};
    	std::cout << words[dis(gen)];
    
    	std::cin.get();
    }
    


  • 🙄

    Edit: Ernsthaft? Du nutzt Mersenne Twister für so etwas?



  • DerNoob schrieb:

    PS: Bitte nichts allzu kompliziertes 😞

    Die allereinfachste Variante wäre mit if bzw. switch:

    int main()
    {
        char wort1[] = {"Hallo"};
        char wort2[] = {"Welt"};
        char wort3[] = {"Mir"};
        char wort4[] = {"geht"};
        char wort5[] = {"es"};
        char wort6[] = {"gut"};
    
        srand(timeGetTime()); 
        int zahl = (rand() % 6);
    
        switch (zahl)
        {
        case 0:
            puts(wort1);
            break;
        case 1:
            puts(wort2);
            break;
        case 2:
            puts(wort3);
            break;
        case 3:
            puts(wort4);
            break;
        case 4:
            puts(wort5);
            break;
        case 5:
            puts(wort6);
            break;
        default:
            assert(0 && "darf nicht vorkommen");
        }
    }
    

    Sollte aber klar sein dass das nicht so optimal ist.
    Je mehr Wörter du hast, und je mehr Stellen du hast wo du auf diese zugreifen musst, desto unübersichtlicher wird es.

    Also packst du die Wörter in eine Liste.
    Die einfachste Variante ist ein Array mit fixer Grösse zu nehmen:

    int main()
    {
        char wort1[] = {"Hallo"};
        char wort2[] = {"Welt"};
        char wort3[] = {"Mir"}; // Grosses M?
        char wort4[] = {"geht"};
        char wort5[] = {"es"};
        char wort6[] = {"gut"};
    
        char* woerter[] = { wort1, wort2, wort3, wort4, wort5, wort6 };
        int wort_anzahl = sizeof(woerter) / sizeof(woerter[0]);
    
        srand(timeGetTime()); 
        int zahl = (rand() % wort_anzahl);
    
        puts(woerter[zahl]);
    }
    

    Und wenn du die Wort-Arrays nicht für sich alleine brauchst, dann noch kürzer so:

    int main()
    {
        char const* woerter[] = { "Hallo", "Welt", "mir", "geht", "es", "gut" };
        int wort_anzahl = sizeof(woerter) / sizeof(woerter[0]);
    
        srand(timeGetTime()); 
        int zahl = (rand() % wort_anzahl);
    
        puts(woerter[zahl]);
    }
    

    Ansonsten ist das was "out" schon richtig. Guck dir std::string und std::vector an.



  • Edit: Ernsthaft? Du nutzt Mersenne Twister für so etwas?

    Was würdest du verwenden? 🙂



  • Da die Qualität der Zufallszahlen in diesem Beispiel sowas von egal sind, std::default_random_engine. Erst wenn es auf die Qualität der Zahlen ankommt (Kryptographie oder ähnliches), wähle ich explicit einen aus.



  • Nathan schrieb:

    Da die Qualität der Zufallszahlen in diesem Beispiel sowas von egal sind, std::default_random_engine.

    Wenn die Qualität des PRNGs egal ist, wieso dann nicht einfach std::rand . Das wird meistens durch einen linearen Kongruenzgenerator implementiert. Das reicht völlig aus.



  • Ja, klar, aber wenn man komplizierter distributions nehmen will?
    OK, ich könnte std::minstnd_rand nehmen oder wie der Generator heißt, aber ich vertraue einfach mal dem Compiler. Der wird schon wissen, was er tut.
    Edit: Bei mir ist std::minstnd_rand0 sowieso default.



  • Danke an hustbaer, seine zweite Möglichkeit gefällt mir und funktioniert auch 😃

    Was gibt es denn bei Zufallszahlen für evtl. Qualitätsmängel? 😕



  • DerNoob schrieb:

    Was gibt es denn bei Zufallszahlen für evtl. Qualitätsmängel? 😕

    Einige Pseudozufallsgeneratoren haben bspw. eine kleine Periode*, oder weisen weniger Hyperebenen auf.

    Natürlich sind alle Folgen, die durch PRNGs erzeugt werden, deterministisch - also berechnet. Es geht aber darum, einen Pseudozufall zu erzeugen - also Zahlenfolgen, die zufällig wirken.

    Das tun einige Generatoren eben einfach nicht so gut wie andere.

    *Und: Nein, das ist mehr als nur eine Penislänge.


  • Mod

    Nochmal laut und deutlich: std::rand, std::default_random_engine und eigentlich jeder normale Zufallsgenerator der irgendwo angeboten wird sind mehr als ausreichend für 99.9% aller Programmierer. Die Leute, die tatsächlich auf die Qualität der Zufallszahlgeneratoren achten müssen (wissenschaftliches Rechnen, Kryptographie), wissen (hoffentlich) schon über das Thema Bescheid.



  • @SeppJ:
    std::rand ist oft aus Kompabilitätsgründen ein wirklich mieser Generator. So mies, dass es selbst beim Mischen von Karten für ein Kartenspiel schon zu seltsamen Effekten kommen kann.

    Weiters finde ich std::rand nicht gut, weil es globalen State hat.
    In Fällen wo man reproduzierbare Ergebnisse nach dem Seeden mit einer bestimmten Zahl braucht, würde ich grundsätzlich davon abraten.
    Weil man nie garantieren kann dass nicht irgend ein anderer Programmteil ebenfalls rand/srand verwendet.

    std::default_random_engine sollte für die allermeisten Sachen OK sein, wenn man die untersten 2-3 Bits verwirft.

    Nur frag' ich mich wieso man nicht gleich z.B. ranlux24 bzw. ranlux48 verwenden sollte, wenn man keine speziellen Anforderungen hat.
    Ich weiss nicht wie schnell die sind, aber "muss super schnell sein" wäre ja schon eine spezielle Anforderung.


Anmelden zum Antworten