"Zahlenraten" - Eine vorher eingegebene Zahl erkennen



  • Hallo c-plusplus-Community!

    Ich, Programmieranfänger, bin gerade dabei eine Spiel zu programmieren.
    Der Benutzer soll die generierte Zahl erraten.

    Hier eben der Code:

    [include]
    ...
    Mainprogramm()
    {
    Start:
    char NeuesSpiel;
    int zahl,i,versuche=0;
    srand((unsigned) time(NULL)); // Initialisieren des Zufallszahlengenerators
    zahl = rand() %10 + 1;
    
    cout << "Zahlenerraten" << endl;
    cout << "Erraten sie die per Zufall generierte Zahl von 1 bis 10!" << endl;
    cout << "Sie haben 5 Versuche" << endl;
    cout << "Geben Sie eine Zahl ein: ";
    
    Anfang:
    versuche++;
    cin >> i;
    
    if(i==zahl)  //Zahl erraten
    {
    cout << "Sie haben richtig gerraten!" << endl;
    cout << versuche <<" Versuche wurden benoetigt!" << endl;
    if(versuche>1)
    {
    cout << "Das geht noch besser!" << endl;
    }
    else
    {
    cout << "Super! Besser geht es nicht!" << endl;
    }
    }
    
    if(i>zahl)  //eingegebene Zahl zu groß
    {
    cout << i << " ist zu gross und somit falsch" << endl;
    if(versuche>=5)
    {
    cout << "Sie haben alle 5 Versuche versagt!";
    }
    else
    {
    goto Anfang;
    }
    }
    
    if(i<zahl)  //eingegebene Zahl zu klein
    {
    cout<< i << " ist zu klein und somit falsch" << endl;
    if(versuche>=5)
    {
    cout << "Sie haben alle 5 Versuche versagt!";
    }
    else
    {
    goto Anfang;
    }
    }
    
    cout << "Wollen Sie nochmal spielen? (j/n)" << endl;
    cin >> NeuesSpiel;
    
    if (NeuesSpiel == 'j')
    {
    goto Start;
    }
    else
    {
    system("PAUSE");
    }
    

    Bin fast schon fertig - mir fehlen "nur noch" 2 Sachen.
    Und zwar möchte ich, dass mein Programm eine zuvor eingegebene Zahl erkennt.
    Da habe ich's mit einer if-Schleife versucht, leider ohne Erfolg.
    Versuch war in etwa:

    if((versuche=1(i)) == (versuche=2)(i))
    {
    cout << "Zahl wurde schon einmal eingegeben!" << endl;
    }
    

    Problem ist halt, wie "sage" ich dem Programm, dass er einfach schauen soll, ob i im ersten Versuch gleich i im zweiten Versuch ist (dann für alle 5 Versuche - bisschen "Schreibarbeit" lol)

    Und Zweitens:
    Wie erkennt mein Programm, ob die Eingabe wirklich eine Zahl ist und kein Buchstabe / Sonderzeichen? Da habe ich leider kein Plan.

    Könnt Ihr mir auf die Sprünge helfen?

    lg
    fener000


  • Mod

    Versuch war in etwa: [...Blödsinn...]

    Bitte nicht wahllos irgendwelche Zeichen irgendwie zusammenschustern.
    Kritik am Code:

    • goto und Labels solltest du durch Schleifen ersetzen.
    • Variablen erst da deklarieren, wo du sie brauchst.
    • Wieso hast du überall endl stehen, wo du nur einen Zeilenumbruch willst?

    Wie erkennt mein Programm, ob die Eingabe wirklich eine Zahl ist und kein Buchstabe / Sonderzeichen? Da habe ich leider kein Plan.

    In dem du den Fehlerzustand von cin prüfst.

    Ich habe alles eingebaut, was du wolltest, und es grundlegend verbessert:

    #include <iostream>
    #include <set>
    #include <limits>
    #include <ctime>
    #include <cstdlib>
    
    int main()
    {
    	using std::cout;
    	using std::cin;
    
    	srand(time(NULL));
    
    	for(;;)
    	{
    		unsigned const zahl = rand() %10 + 1;
    
    		cout << "Geben Sie eine Zahl ein: ";
    
    		std::set<unsigned> bisherigeVersuche;
    		for(unsigned versuche = 1;; )
    		{
    			unsigned i;
    
    			if( !(cin >> i) )
    			{
    				cout << "Falsche Eingabe! Nochmal: ";
    				cin.clear(); // Fehlerstatus zurücksetzen
    				cin.ignore( std::numeric_limits<std::streamsize>::max(), '\n' ); // Alle falschen Zeichen aus dem Buffer entfernen
    				continue;
    			}
    			// Bereits im set vorhanden
    			if( !bisherigeVersuche.insert(i).second )
    			{
    				cout << "Diese Zahl wurde schon einmal eingegeben! Eine andere, bitte: ";
    				continue;
    			}
    
    			if( i == zahl )
    			{
    				cout << "Sie haben richtig gerraten!\n"
    				     << versuche <<" Versuche wurden benoetigt!\n"
    				     << ( versuche > 1 ? "Das geht noch besser!" : "Super! Besser geht es nicht!" ) << '\n';
    
    				break;
    			}
    			else
    			{
    				cout << "i ist zu " << (i > zahl? "gross" : "klein") << "!\n";
    				if( versuche >= 5 )
    				{
    					cout << "Sie haben alle 5 Versuche versagt!\n";
    					break;
    				}
    			}
    			++versuche;
    		}
    
    		cout << "Wollen Sie nochmal spielen? (j/*)\n";
    		if( (cin >> std::ws).get() != 'j' )
    			break;
    	}
    }
    

    Edit: Zwei Fehler behoben.



  • Erst einmal Riesendank Arcoth, dass du dir die Mühe gemacht hast, mir zu helfen.
    goto's durch Schleifen ersetzen - das muss ich mir wohl einprägen und in der Zukunft umsetzen.
    Zeilenumbruch durch "\n" - war bekannt, aber "endl" verwendet, da ich
    den Unterschied nicht wirklich kenne,
    Das mit der falschen Eingabe und zuvor eingegebene Zahl erkennen - zwar ist das Problem so gelöst, aber die "Befehle" kenne ich nicht wirklich.
    So könnte ich sie zwar in mein Programm übernehmen, aber in der Zukunft nicht anwenden können.

    Ich muss zugeben, mir fehlt viel an Wissen in C++, da wir das Programmieren in der Schule erst seit wenigen Wochen behandeln. Es macht mir eigentlich Spaß und ich würde auch gerne in meiner Freizeit dazulernen.
    Nur was könntet ihr mir da empfehlen? Vllt. ein Buch für Einsteiger wie mich - welches nach einer logischen Reihenfolge lehrt?
    Könnt ihr mir da vllt. Ratschläge geben?

    lg
    fener000


  • Mod

    Vllt. ein Buch für Einsteiger wie mich - welches nach einer logischen Reihenfolge lehrt?

    Schön, dass du das direkt ansprichst. Ja, der einzige Weg C++ vernünftig zu lernen, besteht in einem Grundlagenbuch. Schau dir mal folgenden Thread an, da sind die wichtigsten Bücher: http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list (Schau unter 'Beginner')
    Ich empfehle dir den C++-Primer, das ist der Platzhirsch der Grundlagenbücher. Leider ist die neueste Version nicht übersetzt erhältlich (zumindest nicht auf Amazon).

    Zeilenumbruch durch "\n" - war bekannt, aber "endl" verwendet, da ich den Unterschied nicht wirklich kenne,

    Der ist einfach: Alle Zeichen, die in der Konsole landen sollen, nachdem sie durch cout 'ausgegeben' wurden, werden erst zwischengespeichert. Mit endl teilst du dem Streambuffer mit, dass er alle zwischengespeicherten Zeichen und einen Zeilenumbruch jetzt nach stdin (und damit auf die Konsole) weiterleiten soll - diesen Vorgang (der zusätzliche Zeilenumbruch gehört natürlich standardmäßig nicht dazu) nennt man flushen. std::flush macht dasselbe, nur ohne den Zeilenumbruch.

    Nun brauchst du auf Windows diesen Flush nicht. Daher reicht ein einfaches '\n' .

    aber die "Befehle" kenne ich nicht wirklich.

    Das ist natürlich ungünstig. std::set ist ein Container, der alle eingefügten Elemente automatisch sortiert und Duplikate entfernt.


Anmelden zum Antworten