Tic Tac Toe



  • Hallo,
    ich bin neu hier, hab keine Ahnung und habe ein Problem.
    Ich soll für ein Schulprojekt mit Hilfe von Microsoft Visual Studio C++ das Spiel TicTacToe realisieren.

    Mein 1. Problem ist:

    dass ich z.B. wenn Spieler 1 gewonnen hat, nachfrage ob man erneut spielen möchte, dann goto anfang .
    Jedoch löscht er nicht die X und O aus den Feldern. Also i-wie müsste ich den Speicher oder so löschen.Hat da jemand eine Idee? System("cls") bringt nichts!

    Mein 2. Problem ist:

    Ich habe die system farbe mit hilfe von system("color F9") geändert und möchte aber zusätzlich der übersichtshalber, dass die eingesetzten X und O in z.B. rot erscheinen:
    Das probiere ich durch den Befehl:

    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),252);

    weiß aber nicht genau wo ich das eintragen muss bzw. ob ich i-wie

    if mark='x'
    {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),252);
    }

    Hier mal der Quellcode:

    #include <iostream>
    #include <windows.h>// für die funktion sleep
    using namespace std;
    
    char square[10] ={'0','1','2','3','4','5','6','7','8','9'};//Repräsentiert die 9 Felder des Spielfeldes
    //Der erste Wert ist unbedeutent und nur wichtig damit die eingegebene Zahl gleich dem Index ist
    
    int checkwin();// int = ganze zahlen überprüfung ob gewonnen
    void board();//zeichnet das Spielfeld
    
    int main()//Hauptmetode
    {
    
    anfang:
    
    	int player = 1; //Überprüft wer an der Reihe ist
    	int i;
    	int choice;
    	char mark;// X oder O
    	char again;
    
    		do
    		{
    
    			board();//Zeichne das Spielfeld
    
    			player=(player%2)?1:2;//Ermittelt anhand der gespielten Züge den spieler der dran ist
    
    			cout << "Spieler " << player << ", Sie sind an der Reihe, Bitte geben Sie eine Zahl ein :  ";//Spieler aufforden eine Zahl einzugeben
    			cin >> choice;
    
    			mark=(player == 1) ?'X' : 'O';//Überprüfung wenn Spieler 1 dann X sonst O
    			//Setzte in square den entsprechenden Wert auf X oder O
    			//aber nur wenn das Feld noch nicht genutzt wurde
    
    			if (choice == 1 && square[1] == '1')
    
    				square[1] = mark;
    			else if (choice == 2 && square[2] == '2')
    
    				square[2] = mark;
    			else if (choice == 3 && square[3] == '3')
    
    				square[3] = mark;
    			else if (choice == 4 && square[4] == '4')
    
    				square[4] = mark;
    			else if (choice == 5 && square[5] == '5')
    
    				square[5] = mark;
    			else if (choice == 6 && square[6] == '6')
    
    				square[6] = mark;
    			else if (choice == 7 && square[7] == '7')
    
    				square[7] = mark;
    			else if (choice == 8 && square[8] == '8')
    
    				square[8] = mark;
    			else if (choice == 9 && square[9] == '9')
    
    				square[9] = mark;
    			else
    			{
    				cout<<endl;
    				cout<<"Ung\x81 \bltige Eingabe, dr\x81 \bcken Sie eine beliebige Taste zum widerholen !";//Bei ungültiger Eingabe ist der Spieler erneut an der Reihe
    				// \x81\ um das ü darzustellen
    				player--;
    				cin.ignore();
    				cin.get();
    			}
    
    			i=checkwin();//Überprüfung ob einer gewonnen hat
    
    			player++;
    		}while(i==-1);//Spiel ist noch nicht vorbei
    
    		board();//Erneut das Spielfeld zeichnen und dem Sieger gratulieren bzw beiden Spielern zum unentschieden !
    		if(i==1)//Spiel ist vorbei und es gibt einen Sieger
    
    			cout<<"Spieler "<<--player<<" hat gewonnen, herzlichen Gl\x81 \bckwunsch !";
    		else
    			cout<<"Spiel ist unentschieden !";
    
    		Sleep(2000);// wartet ca 2 sekunden bis das programm fortfährt.Wird in Millisekunden angegeben 2 Sekunden = 2000 Millisekunden
    
    		cout<<endl;
    		//system("cls");
    		cout<< "\n\nM\x94 \bchten Sie erneut spielen ? ";
    		cout<< "\n\nDr\x81 \bcken Sie <j> um erneut zu Spielen oder <n> um das Spiel zu beenden !";// j für erneutes Spiel n für programm schließen
    		cin>> again;
    
    	if(again=='j')
    
    	{
    		system("cls");
    		goto anfang;
    	}
    
    	if (again=='n')
    	{
    		return 0;
    	}
    
    }
    
    /*********************************************
    Funktion um den Status des Spiels zurückzugeben
    1  --> Spiel ist vorbei und es gibt einen Sieger
    -1 --> Spiel ist noch nicht entschieden
    0  --> Spiel ist vorbei und es gibt keinen Sieger
    **********************************************/
    
    int checkwin()
    {
    
    	if (square[1] == square[2] && square[2] == square[3]) //Überprüft ob im Kasten 1 + 2 und 2 + 3 das gleiche Symbol ist!
    
    		return 1;// wenn JA dann 1 = Spiel vorbei und es gibt einen Sieger
    	//Das gleiche mit den anderen Zeilen und Spalten sowie Diagonal
    	else if (square[4] == square[5] && square[5] == square[6])
    
    		return 1;
    	else if (square[7] == square[8] && square[8] == square[9])
    
    		return 1;
    	else if (square[1] == square[4] && square[4] == square[7])
    
    		return 1;
    	else if (square[2] == square[5] && square[5] == square[8])
    
    		return 1;
    	else if (square[3] == square[6] && square[6] == square[9])
    
    		return 1;
    	else if (square[1] == square[5] && square[5] == square[9])
    
    		return 1;
    	else if (square[3] == square[5] && square[5] == square[7])
    
    		return 1;
    	else if (square[1] != '1' && square[2] != '2' && square[3] != '3'
    		&& square[4] != '4' && square[5] != '5' && 
    		square[6] != '6'
    		&& square[7] != '7' && square[8] != '8' && square[9] != '9')// Überprüft ob in einem Kasten noch die dazugehörige Nummer steht,
    
    		return 0;
    	else
    		return -1;// wenn ja dann -1 = das spiel ist noch nicht vorbei !
    }
    
    /*******************************************************************
    Funktion um das Spielfeld zu Zeichnen
    ********************************************************************/
    void board()
    {
    
    	system("cls");//löscht die darüberstehende Ausgabe, ansonsten würden i-wann 9 Spielfelder untereinander stehen.
    	system("color F9"); // Änderung der Hintergrund und Textfarbe
    
    	cout<< "\n\n\t\t   Tic Tac Toe\n\n"<<endl;//\t bedeutet ein tab also eingerückter text
    	cout<< "      Spieler 1  ( X )  -  Spieler 2  ( O )"<<endl<<endl;
    
    	cout<< endl;
    	cout<< "\t\t     |     |     "<<endl;
    	cout<< "\t\t  "<<square[1]<<"  |  "<<square[2]<<"  |  "<<square[3]<<endl; 
    	cout<< "\t\t_____|_____|_____"<<endl;
    	cout<< "\t\t     |     |     "<<endl; 
    	cout<< "\t\t  "<<square[4]<<"  |  "<<square[5]<<"  |  "<<square[6]<<endl;
    	cout<< "\t\t_____|_____|_____"<<endl;
    	cout<< "\t\t     |     |     "<<endl;
    	cout<< "\t\t  "<<square[7]<<"  |  "<<square[8]<<"  |  "<<square[9]<<endl;
    	cout<< "\t\t     |     |     "<<endl<<endl;
    
    }
    


  • Mein 1. Problem ist: ...

    Du musst nicht den Speicher löschen sondern deinen Ausgangszustand wiederherstellen. Das heißt du musst square[] wieder mit 0,1,2,... füllen sobald ein neues Spiel beginnt.



  • @Freddy#32: Und editiere deinen Beitrag und setze den Code in entsprechende C++ Tags...



  • @ Neo 47 ,
    danke schonmal für die Antwort aber :

    An welcher stelle? also ich hab es schonmal so versucht:

    #include <iostream>
    #include <windows.h>// für die funktion sleep
    using namespace std;
    
    char square[10] ={'0','1','2','3','4','5','6','7','8','9'};//Repräsentiert die 9 Felder des Spielfeldes
    //Der erste Wert ist unbedeutent und nur wichtig damit die eingegebene Zahl gleich dem Index ist
    
    int checkwin();// int = ganze zahlen überprüfung ob gewonnen
    void board();//zeichnet das Spielfeld
    
    int main()//Hauptmetode
    {
    
     anfang:
    
    	char square[10] ={'0','1','2','3','4','5','6','7','8','9'};
    	int player = 1; //Überprüft wer an der Reihe ist
    	int i;
    	int choice;
    	char mark;// X oder O
    	char again;
    
    ...
    

    das funktioniert leider nicht, denn dann wird gar kein Zeichen mehr angezeigt.
    Also gesetzt schon, denn wenn ich z.B. auf 1 drücke...bleibt die 1 stehen aber er setzt dort was hin (was er nicht anzeigt) denn wenn ich erneut auf 1 drücke, sagt er mir ungültige eingabe ...

    ich bin echt ratlos -,-



  • Freddy#32 schrieb:

    int main()
    {
    // ...
    
    char square[10] ={'0','1','2','3','4','5','6','7','8','9'};//Repräsentiert die 9 Felder des Spielfeldes
    
    // ...
    

    das funktioniert leider nicht, denn dann wird gar kein Zeichen mehr angezeigt.

    Ja. Gratuliere. Du hast eben selbst erlebt warum es (unter anderem) doof ist, globale Variablen zu verwenden.
    Du deklarierst (und definierst) square sowohl im globalen scope als auch im scope von main() . Die beiden sind zwei seperate Variablen. Das Problem ist, daß das square in main() das andere im globalen scope überdeckt. Dh. du setzt in main() lustig Werte in square , jedoch ermittelt board() seine Ausgabe anhand des globalen suare , daß sich aber nie nicht ändert.

    @ Freddy #32 ,
    tu was dir Th69 gesagt hat!



  • @ Swordfish

    Lösungsvorschlag?

    Wie gesagt, bin Anfänger, wäre schön wenn jemand mir nen leicht zu verstehenden Lösungsvorschlag anbieten könnte.



  • Freddy#32 schrieb:

    Lösungsvorschlag?

    Akut? Nicht neu deklarieren sondern nur den Elementen des Arrays die Werte zuweisen, die sie haben sollen.
    Langfristig? Funktionsparameter statt globaler Variablen.
    Ziel? OOP wo's sinn macht.



  • Hättest du eventuell ein Beispiel für das Akkute? 🙂



  • Mit einer Schleife drüberlaufen und Werte setzten?



  • ich weiß nicht genau wie du das meinst....
    kannst du nicht bitte kurz den Quellcode posten, wäre auf jeden Fall leichter...



  • char square[10];
    
    int main()
    {
          anfang: 
    
          for(int i = 0; i < 10; i++)
                square[i] = '0' + i;
    
          ....
    
    }
    

    Das hat Swordfish gemeint.


  • Mod

    Oder ganz einfach noch lokaler werden, wie es sich gehört. Alles was zum Spiel gehört, gehört eben auch nur in den Block des Spiels:

    int main()
    {
      anfang:
      {
        char square[10] ={'0','1','2','3','4','5','6','7','8','9'};
        int player = 1;
        char mark;
        int i;
    
        // Hier das Spiel
      }
      {
        char again;
        cout<< "\n\nM\x94 \bchten Sie erneut spielen ? ";
        cout<< "\n\nDr\x81 \bcken Sie <j> um erneut zu Spielen oder <n> um das Spiel zu beenden !";// j für erneutes Spiel n für programm schließen
        cin>> again;
    
        if(again=='j')
    
        {
            system("cls");
            goto anfang;
        }
    
        if (again=='n')
        {
            return 0;
        }
      }
    }
    

    Das wäre natürlich wesentlich einfacher, wenn man vernünftige Kontrollstrukturen nutzen würde, statt goto. Und wesentlich lesbarer, wenn man nicht den Uraltstil benutzen würde, alles am Anfang eines Blocks zu deklarieren.

    Und die check-Funktion kann nun nicht mehr auf ein globales Spielfeld zugreifen. Aber das ist eine gute Sache, denn das zwingt dich, es richtig zu lernen.

    goto, globale Variablen, und dein Uralt-Stil 😮 . Wo hast du C++ gelernt? Das Programm ist wie eine Ansammlung sämtlicher Techniken, die man nicht nutzen sollte. Gerade goto wird normalerweise gar nicht mehr richtig gelehrt, höchstens als Randnotiz, dass es das auch gibt und man es meiden sollte. Deine Probleme hier sind größtenteils auch darauf zurück zu führen, wieso man diese Techniken normalerweise nicht (oder nur mit viel Erfahrung und großer Vorsicht) benutzen sollte.

    Deine Zeilen 43-69 sind übrigens recht kompakt schreibbar:

    if (choice >= 1 && choice <= 9 && square[choice] == choice + '0') square[choice] = mark;
    

    Als Anfänger bist du natürlich noch nicht so vertraut damit, solche Abkürzungen zu sehen, aber als Faustregel, kommt in einem guten Code keine Zeile doppelt vor oder auch nur eine Zeile, die einer anderen sehr ähnlich sieht. Wenn sich etwas zig-Mal mit leichter Variation wiederholt, dann gibt es garantiert eine bessere Lösung. Solche Stellen gibt es in deinem Code noch anderswo.


Anmelden zum Antworten