Erstes C++ Programm (Schere, Stein, Papier) - Kritik erwünscht!



  • Hallo,

    ich habe gestern angefangen mich intensiver mit C++ zu beschäftigen.
    Ich besitze bereits ein paar Vorkenntnisse aus PHP, MYSQL und ein bisschen Java.
    Die letzten 2 Tage habe ich mich mit Videos gefüttert zu den Grundlagen von C++ (bin noch lange nicht fertig) und habe jetzt erstmal mein erstes "Programm" geschrieben. Nunja..eigentlich ist es eher ein Spiel.
    Und jetzt wollte ich ein paar Verbesserungsvorschläge hören und eventuell auch Vereinfachungen (mir ist aufgefallen, dass ich bei den 3 Strings immer "Schlechtes PTR habe).

    Hier der Code

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main ()
    {
    	string u_eingabe;
    	int c_runden = 0;
    	int p_runden = 0;
    	string c_gameplay;
    	int c_gameplay_random = 0;
    	string c_gameplay_array[3] = {"Schere", "Stein", "Papier"};
    
    	for (c_runden; c_runden < 3 && p_runden < 3; c_runden)
    	{
    		cout << "Bitte machen sie ihre Eingabe (Schere, Stein , Papier oder Quit): ";
    		cin >> u_eingabe;
    		if (u_eingabe == "Quit")
    		{
    			break;
    		}
    		c_gameplay_random = rand()%3;
    		c_gameplay = c_gameplay_array[c_gameplay_random];
    
    			if (u_eingabe == c_gameplay)
    			{
    				cout << "Draw!" << endl;
    			}
    			else if (u_eingabe == "Schere" && c_gameplay == "Stein")
    			{
    				cout << "Stein zerstoert Schere, Punkt fuer C1! " << endl;
    				c_runden++;
    			}
    			else if (u_eingabe == "Schere" && c_gameplay == "Papier")
    			{
    				cout << "Schere zerschneidet Papier, Punkt fuer Spieler! " << endl;
    				p_runden++;
    			}
    			else if (u_eingabe == "Stein" && c_gameplay == "Schere")
    			{
    				cout << "Stein zerstoert Schere, Punkt fuer Spieler! " << endl;
    				p_runden++;
    			}
    			else if (u_eingabe == "Stein" && c_gameplay == "Papier")
    			{
    				cout << "Papier wickelt Stein ein, Punkt fuer C1! " << endl;
    				c_runden++;
    			}
    			else if (u_eingabe == "Papier" && c_gameplay == "Stein")
    			{
    				cout << "Papier wickelt Stein ein, Punkt fuer Spieler! " << endl;
    				p_runden++;
    			}
    			else if (u_eingabe == "Papier" && c_gameplay == "Schere")
    			{
    				cout << "Schere zerschneidet Papier, Punkt fuer C1! " << endl;
    				c_runden++;
    			}
    
    	}
    	if (c_runden == 3)
    		cout << "Der Computer hat gewonnen! ";
    	else 
    		cout << "Glückwunsch, du hast das Spiel gewonnen! "<< endl;
    
    }
    


  • Eine Änderung von

    cout << "Bitte machen sie ihre Eingabe (Schere, Stein , Papier oder Quit): ";
    

    in

    cout << "Bitte machen sie ihre Eingabe [Schere(1), Stein(2) , Papier(3) oder Quit(4)]: ";
    

    mit entsprechender Änderung des Programms von Strings nach Integer-Variablen würde die Eingabe erleichtern und die Vergleiche übersichtlicher machen.



  • Ja , hatte auch schon an Zahlen als Eingabe gedacht..Hätte wohl auch die If´s leichter gemacht.

    Eine Frage habe ich noch: Wie kann ich denn mit meinem IDE (Visual C++ Express) eine .exe erstellen, so dass ich sie ohne das Programm ausführen kann?

    Vielen Dank schonmal



  • Sowas

    for(;;)
    

    ist in c++ eine korrekte Endlosschleife. Du brauchst den Platz zwischen den Semikolon-Zeichen nicht mit irgendeinem Unsinn zu füllen, nur damit dort etwas steht.



  • sYpro schrieb:

    Ja , hatte auch schon an Zahlen als Eingabe gedacht..Hätte wohl auch die If´s leichter gemacht.

    Eine Frage habe ich noch: Wie kann ich denn mit meinem IDE (Visual C++ Express) eine .exe erstellen, so dass ich sie ohne das Programm ausführen kann?

    Vielen Dank schonmal

    Als Release kompilieren.



  • sYpro schrieb:

    Eine Frage habe ich noch: Wie kann ich denn mit meinem IDE (Visual C++ Express) eine .exe erstellen, so dass ich sie ohne das Programm ausführen kann?

    Wenn du dich für ein c++ Projekt ohne .NET entschieden hast (Win32 Konsolen Application) findest du die exe-Datei im Projektpfad im Unterverzeichnis Debug oder Release, je nachdem wie du sie erstellt hast.

    Hast du aus Versehen ein .NET Projekt erstellt. Tja, dann ...



  • Tipp3 schrieb:

    sYpro schrieb:

    Eine Frage habe ich noch: Wie kann ich denn mit meinem IDE (Visual C++ Express) eine .exe erstellen, so dass ich sie ohne das Programm ausführen kann?

    Wenn du dich für ein c++ Projekt ohne .NET entschieden hast (Win32 Konsolen Application) findest du die exe-Datei im Projektpfad im Unterverzeichnis Debug oder Release, je nachdem wie du sie erstellt hast.

    Hast du aus Versehen ein .NET Projekt erstellt. Tja, dann ...

    Habs gefunden. Vielen Dank.

    @Endlosschleife:

    Danke, das Erste und Letzte kann ich quasi dann rausnehmen, solange die ";" da sind. Will ja nur, dass das Spiel nach 3 gewonnenen Runden aufhört. 🙂



  • Als erstes bitte [cpp]- und nicht [code]-Tags verwenden. 😉

    Ansonsten, was mir gerade aufgefallen ist:

    • Was sollen die Präfixe u_ , p_ und c_ ? Wähle aussagekräftige Bezeichner, z.B. user statt u_ .
    • Redundante if -Abfragen. Komme davon weg, indem du Verschachtelungen nutzt. Alternative siehe nächsten Punkt.
    • Funktionen sind generell immer empfehlenswert, um Teilprobleme auszulagern. Du könntest z.B. einer Funktion zwei Zustände (z.B. "Schere" und "Papier") übergeben und dann zurückgeben lassen, ob der erste, der zweite oder niemand gewinnt.
    • Fehleingaben abfangen.
    • Zufallsgenerator mit srand() initialisieren - siehe www.cplusplus.com.
    • Wenn du deine Zustände schon als String-Array speicherst, greif doch auch auf diese zu, anstatt jeweils wieder neue Stringliterale in Anführungszeichen in den Code zu schreiben.


  • Habe jetzt ein paar Dinge bearbeitet:

    "Funktionen sind generell immer empfehlenswert, um Teilprobleme auszulagern. Du könntest z.B. einer Funktion zwei Zustände (z.B. "Schere" und "Papier") übergeben und dann zurückgeben lassen, ob der erste, der zweite oder niemand gewinnt. "

    Könntest du das eventuell nochmal etwas genauer erklären bzw. ein Beispiel aufzeigen? Ich verstehe nicht ganz, wie das von Vorteil sein könnte.
    Vielen Dank

    Hier der bearbeitete Code:

    #include <iostream>
    #include <string>
    #include <time.h>
    
    using namespace std;
    
    int main ()
    {
    	string u_eingabe;
    	int c_runden = 0;
    	int p_runden = 0;
    	string c_gameplay;
    	int c_gameplay_random = 0;
    	string c_gameplay_array[3] = {"Schere", "Stein", "Papier"};
    
    	for (c_runden; c_runden < 3 && p_runden < 3;)
    	{
    		cout << "Bitte machen sie ihre Eingabe (Schere, Stein , Papier oder Quit): ";
    		cin >> u_eingabe;
    		if (u_eingabe == "Quit")
    		{
    			break;
    		}
    		c_gameplay_random = rand()%3;
    		srand ( time(NULL) );
    		c_gameplay = c_gameplay_array[c_gameplay_random];
    
    			if (u_eingabe == c_gameplay)
    			{
    				cout << "Draw!" << endl;
    			}
    			else if (u_eingabe == c_gameplay_array[0] && c_gameplay == c_gameplay_array[1])
    			{
    				cout << "Stein zerstoert Schere, Punkt fuer C1! " << endl;
    				c_runden++;
    			}
    			else if (u_eingabe == c_gameplay_array[0] && c_gameplay == c_gameplay_array[2])
    			{
    				cout << "Schere zerschneidet Papier, Punkt fuer Spieler! " << endl;
    				p_runden++;
    			}
    			else if (u_eingabe == c_gameplay_array[1] && c_gameplay == c_gameplay_array[0])
    			{
    				cout << "Stein zerstoert Schere, Punkt fuer Spieler! " << endl;
    				p_runden++;
    			}
    			else if (u_eingabe == c_gameplay_array[1] && c_gameplay == c_gameplay_array[2])
    			{
    				cout << "Papier wickelt Stein ein, Punkt fuer C1! " << endl;
    				c_runden++;
    			}
    			else if (u_eingabe == c_gameplay_array[2] && c_gameplay == c_gameplay_array[1])
    			{
    				cout << "Papier wickelt Stein ein, Punkt fuer Spieler! " << endl;
    				p_runden++;
    			}
    			else if (u_eingabe == c_gameplay_array[2] && c_gameplay == c_gameplay_array[0])
    			{
    				cout << "Schere zerschneidet Papier, Punkt fuer C1! " << endl;
    				c_runden++;
    			}
    
    	}
    	if (c_runden == 3)
    		cout << "Der Computer hat gewonnen! "<< endl;
    	else 
    		cout << "Glueckwunsch, du hast das Spiel gewonnen! "<< endl;
    
    }
    


  • Ich muss mich Nexus anschließen. Ich bin ja normalerweise eher ein Verfechter der Ungarischen Notation (zumindest teilweise) und wollte dir schon sagen, dass du sie ruhig benutzen kannst, wenn du das willst... als ich sah, dass deine Präfixe gar keine UN sind! Das verwirrt gleich doppelt, da man erstmal denkt, dass ein Präfix irgendeinen Typen repräsentiert. Und sobald man merkt, dass das gar nicht zutrifft, grübelt man über die tatsächliche Bedeutung, die ja nicht sofort ersichtlich ist. Also verwende lieber sprechende Variablennamen, die können dann auch ruhig etwas länger sein.

    Ansonsten muss ich aber sagen, dass abseits der genannten Kritikpunkte deine Code-Notation recht gelungen ist. Du bist wenigstens in der Lage, vernünftig einzurücken, was viele Anfänger noch nicht so wirklich drauf haben. 🙂



  • hinweis zu srand() :

    nur _einmal_ _vor_ dem ersten Aufruf von rand() aufrufen.

    Du legst damit den Startpunkt des "Zufallsgenerators" fest, also reicht einmal.

    Die Funktion würde dir dahingehend Arbeit ersparen, dass du einfach die beiden gezogenen Figuren übergibst und dann den Rückgabewert auswertest. Meinetwegen 0 für unentschieden, 1 für Spieler hat gewonnen, 2 für Computer hat gewonnen.

    Würde so aussehen:

    int zug( const string& spieler, const string& computer)
    {
        if ( spieler == computer )
            return 0;
    
        if ( spieler == "Schere" && computer == "Papier"
          || spieler == "Papier" && computer == "Stein"
          || spieler == "Stein" && computer == "Schere" )
            return 1;
    
        return 2;
    }
    

    in deiner Schleife dann:

    for([...])
    {
        [...]
        int zugergebnis = zug(u_eingabe, c_gameplay)
    
        switch (zugergebnis) // notfalls auch mit if-else
        {
        case 0:
            // unentschieden
        case 1:
            // Punkt für Spieler
        case 2:
            // Punkt für PC
        default:
            // Fehler
        }
    }
    


  • Oder man baut sich ein Array

    int Auswertung[3];
    

    mit der Bedeutung
    Auswertung[0] entspricht Anzahl der Unentschieden
    Auswertung[1] Anzahl Siege Spieler
    Auswertung[2] Anzahl Siege Computer
    und statt der switch-Anweisung einfach

    Auswertung[zug(u_eingabe, c_gameplay)]++;
    

    Der entscheidende Punkt ist jedoch die vereinfachte Abfrage von zwutz. Denn wenn es kein Untentschieden ist und der eine Spieler nicht gewonnen hat, hat automatisch der andere gewonnen, oder umgekehrt. Schön vereinfacht.



  • Vielen Dank für das Beispiel.

    #include <iostream>
    #include <string>
    #include <time.h>
    
    using namespace std;
    
    int zug( const string& spieler, const string& computer) 
    { 
        if ( spieler == computer ) 
            return 0; 
    
        if ( spieler == "Schere" && computer == "Papier" 
          || spieler == "Papier" && computer == "Stein" 
          || spieler == "Stein" && computer == "Schere" ) 
            return 1; 
    
        return 2; 
    }
    
    int main ()
    {
    	string u_eingabe;
    	int c_runden = 0;
    	int p_runden = 0;
    	string c_gameplay;
    	int c_gameplay_random = 0;
    	string c_gameplay_array[3] = {"Schere", "Stein", "Papier"};
    
    	srand ( time(NULL) );
    
    	for (; c_runden < 3 && p_runden < 3;) // For Schleife bis c oder p_runden 3 ist (gewonnen)
    	{
    		cout << "Bitte machen sie ihre Eingabe (Schere, Stein , Papier oder Quit): ";
    		cin >> u_eingabe;
    		if (u_eingabe == "Quit")
    		{
    			break;
    		}
    		c_gameplay_random = rand()%3; //random 0-3 -> array
    		c_gameplay = c_gameplay_array[c_gameplay_random]; 
    
    		int zugergebnis = zug(u_eingabe, c_gameplay); //Übergabe in die zug Funktion
    
    		switch (zugergebnis) 
    		{ 
    		case 0: // unentschieden 
    
    			cout << "Draw! " << endl;
    			break;
    
    		case 1: // Punkt für Spieler 
    
    			cout << "Punkt fuer den Spieler! " << endl;	
    			p_runden++;
    			break;
    
    		case 2: // Punkt für PC 
    
    			cout << "Punkt fuer den Computer! " << endl;
    			c_runden++;
    			break;
    
    		default: // Fehlerhafte Eingabe 
    			cout << "Falsche Eingabe , bitte erneut versuchen! " << endl;
    		}
    	}
    	if (c_runden == 3) // Ende bei 3 gewonnenen Runden
    		cout << "Der Computer hat gewonnen! "<< endl;
    	else 
    		cout << "Glueckwunsch, du hast das Spiel gewonnen! "<< endl;
    
    }
    

    Ich denke das kann man fürs erste Programm erstmal so lassen, oder?



  • Sypro schrieb:

    for (; c_runden < 3 && p_runden < 3; )[/cpp]

    Wieso nimmst du hier eigentlich keine while-Schleife?



  • _matze schrieb:

    Sypro schrieb:

    for (; c_runden < 3 && p_runden < 3; )[/cpp]

    Wieso nimmst du hier eigentlich keine while-Schleife?

    Gute Frage. Changed 🙂


Anmelden zum Antworten