Fehler in der Schleife



  • Hallö,
    ich habe hier ein Tik-Tak-Toe. Leider habe ich einen Logikfehler bei der Wiederholung am Ende, sodass sich das Programm direkt wieder schließt, statt mich wählen zu lassen.

    Und eine zusätzliche Frage habe ich auch noch:
    Gibt es eine Möglichkeit die Symbole in ein Spielfeld zu schreiben, statt das es immer wieder neu in die Console geschrieben wird?

    #include<stdio.h>
    
    int main(void)
    {
    	//Variablendeklaration//
    
    	char spielfeld[10] = { '0','1','2','3','4','5','6','7','8','9' };
    	int durchlauf;
    	int wahl;
    	char spielen;
    	int gewonnen = 0;
    
    
    	do {
    		//Berüßung und Vorstellen des Spiels//
    		printf("Herzlich Willkommen zu  Tic - Tac - Toe.\n");
    		getchar();
    
    		printf("Bitte geben Sie fuer Ihre geweahlte stelle auf dem Spielfeld, die entsprechende Zahl ein.\n");
    		printf("Ein Spieler hat gewonnen, wenn er es geschafft hat seine Steine so zu setzten,\n");
    		printf("dass er entweder 3 wagerecht, 3 senkrecht oder 3 diagonal in einer Reihe hat.\n");
    		printf("\nSpieler 1 spielt mit einem X und Spieler 2 mit einem O!\n");
    
    
    
    		printf("\nDas Spielfeld:\n\n");
    
    		printf(" %c %c %c\n", spielfeld[1], spielfeld[2], spielfeld[3]);
    		printf(" %c %c %c\n", spielfeld[4], spielfeld[5], spielfeld[6]);
    		printf(" %c %c %c\n", spielfeld[7], spielfeld[8], spielfeld[9]);
    
    
    		for (durchlauf = 1; durchlauf < 10 && gewonnen == 0; durchlauf++)
    		{
    			//Spielrunde 1, 3, 5, 7, 9//
    			if (durchlauf % 2 == 1)
    			{
    				//Eingabe//
    				do
    				{
    					printf("Spieler 1 ist an der Reihe, bitte geben Sie die entsprechende Zahl ein.\n");
    					scanf_s("%i", &wahl);
    					fflush(stdin);
    
    					//Überprüfen, ob Feld schon besetzt ist//
    					if ((spielfeld[wahl] == 'X') || (spielfeld[wahl] == 'O'))
    					{
    						printf("Das eingegebene Feld ist schon besetzt.\n");
    						//zum Wiederholen der Schleife//
    						wahl = 10;
    					}
    				}
    
    				while ((wahl < 1) || (wahl > 9));
    
    
    				//Belegung des Spielfeldes//
    				spielfeld[wahl] = 'X';
    			}
    			//Spielrunde 2, 4, 6, 8//
    			else
    			{
    				//Eingabe//
    				do
    				{
    					printf("Spieler 2 ist an der Reihe, bitte geben Sie die entsprechende Zahl ein.\n");
    					scanf_s("%i", &wahl);
    					fflush(stdin);
    
    					//Überprüfen, ob Feld besetzt ist //
    					if ((spielfeld[wahl] == 'O') || (spielfeld[wahl] == 'X'))
    					{
    						printf("Das eingegebene Feld ist schon besetzt.\n");
    						//zum Wiederhollen der Schleife//
    						wahl = 10;
    					}
    				}
    				//Bedinung, um Schleife zu verlassen//
    				while ((wahl < 1) || (wahl > 9));
    
    				//Belegung des Spielfeldes// 
    				spielfeld[wahl] = 'O';
    			}
    
    
    
    			printf("\n %c %c %c\n", spielfeld[1], spielfeld[2], spielfeld[3]);
    			printf(" %c %c %c\n", spielfeld[4], spielfeld[5], spielfeld[6]);
    			printf(" %c %c %c\n", spielfeld[7], spielfeld[8], spielfeld[9]);
    
    			//Bedingungen zum Sieg
    
    
    			if (((spielfeld[1] == 'O') && (spielfeld[2] == 'O') && (spielfeld[3] == 'O')) || ((spielfeld[4] == 'jO') && (spielfeld[5] == 'O') && (spielfeld[6] == 'O')) || ((spielfeld[7] == 'O') && (spielfeld[8] == 'O') && (spielfeld[9] == 'O')) || ((spielfeld[1] == 'O') && (spielfeld[5] == 'O') && (spielfeld[9] == 'O')) || ((spielfeld[3] == 'O') && (spielfeld[5] == 'O') && (spielfeld[7] == 'O')) || ((spielfeld[1] == 'O') && (spielfeld[4] == 'O') && (spielfeld[7] == 'O')) || ((spielfeld[2] == 'O') && (spielfeld[5] == 'O') && (spielfeld[8] == 'O')) || ((spielfeld[3] == 'O') && (spielfeld[6] == 'O') && (spielfeld[9] == 'O')))
    			{
    				printf("\nSpieler 2, Sie haben gewonnen!\n");
    
    				
    			}
    
    			if (((spielfeld[1] == 'X') && (spielfeld[2] == 'X') && (spielfeld[3] == 'X')) || ((spielfeld[4] == 'X') && (spielfeld[5] == 'X') && (spielfeld[6] == 'X')) || ((spielfeld[7] == 'X') && (spielfeld[8] == 'X') && (spielfeld[9] == 'X')) || ((spielfeld[1] == 'X') && (spielfeld[5] == 'X') && (spielfeld[9] == 'X')) || ((spielfeld[3] == 'X') && (spielfeld[5] == 'X') && (spielfeld[7] == 'X')) || ((spielfeld[1] == 'X') && (spielfeld[4] == 'X') && (spielfeld[7] == 'X')) || ((spielfeld[2] == 'X') && (spielfeld[5] == 'X') && (spielfeld[8] == 'X')) || ((spielfeld[3] == 'X') && (spielfeld[6] == 'X') && (spielfeld[9] == 'X')))
    			{
    				printf("\nSpieler 1, Sie haben gewonnen!\n");
    
    				
    			}
    
    		}
    
    		// Bedingung für Unentschieden
    		if (gewonnen == 0)
    		{
    			printf("\nEs ist Unenschieden\n");
    		}
    
    		printf("\n");
    		//Wiederholen?//
    		printf("Geben Sie j ein, wenn Sie Tik-Tak-Toe spielen wollen und n, wenn nicht.\n");
    		scanf_s("%c", &spielen, 2);
    
    	} while (spielen == 'j');
    
    	return 0;
    }
    


  • @Cia Du hast nur Platz für ein Zeichen in spielen.
    Warum gibst du beim scanf_s eine 2 an?
    Ein sizeof(spielen) könnte helfen.

    Und nimm als Formatstring mal " %c" (achte auf das Leerzeichen vor dem % )
    Eine Kontrollausgabe wie printf("Sie haben '%c' gewählt\n", spielen); ist da oft hilfreich (wenn man keinen Debugger nutzen möchte)

    @Cia sagte in Fehler in der Schleife:

    Gibt es eine Möglichkeit die Symbole in ein Spielfeld zu schreiben, statt das es immer wieder neu in die Console geschrieben wird?

    Es gibt Librariers dafür. Z.B. nCurses (eigentlich für Unix)



  • du kannst dir auch den borland-compiler (für windows) holen, da gibt es dann gotoxy in der conio.h.



  • @DirkB ich dachte mit der 2 gebe ich die Parameter an, die ich in der Funktion benutzte.

    okii danke, probiere das sizeof mal:)

    Wie meinst du das mit %c und dem Leerzeichen? und %c habe ich ja schon benutzt.

    ah oki danke, ich schaue mal:)



  • @Cia sagte in Fehler in der Schleife:

    ich dachte mit der 2 gebe ich die Parameter an, die ich in der Funktion benutzte.

    Nein. Das erkennt die Funktion mithilfe des Formatstrings (grob an der Anzahl der %-Zeichen)
    Bei %c erwartet sie noch einen 2. Parameter - die Anzahl der zur Verfügung stehenden Zeichen im Zielspeicher. Ein char = ein Zeichen.

    okii danke, probiere das sizeof mal:)

    Ok.

    Wie meinst du das mit %c und dem Leerzeichen? und %c habe ich ja schon benutzt.

    Ja, aber kein Leerzeichen. Jedes Zeichen im Formatstring hat eine Bedeutung. Auch ein Leerzeichen.

    ah oki danke, ich schaue mal:)

    Vor allem mal die Dokumentation zu scanf_s. Da steht das drin.

    Du solltest auch direkt nach der Feldeingabe (wahl) überprüfen ob es ein gültiger Wert ist und nicht erst nach dem Zugriff auf das Feld.
    Das kann böse enden.

    Auch unterscheiden sich der if- und else-Zweig von if (durchlauf % 2 == 1) nur durch die Zuweisung am Ende.
    Darum reicht es dort entweder 'o' oder 'X' zuzuweisen.

    Und ein 'J' ist kein 'j' falls du das auch noch abfangen möchtest.



  • @Wade1234 dankii ich werde das direkt mal probieren:)



  • @DirkB
    ah das mit den Leerzeichen wusste ich nicht.

    vielen Dank. Ich stecke noch in den Anfängen und bringe mir C selber bei, da schleichen sich leider oft Fehler ein.
    Vielen vielen lieben Dank für deine Hilfe!:)



  • @Cia Womit und auf welchem System programmierst du?

    Das Leerzeichen im Formatstring überliest führende Whitespace, die noch von einem vorherigem scanf im Eingabestrom stehen können.



  • @Cia Und gerade wenn du nicht zu 100% weißt, was eine Funktion tut, schau in der Refenrenz nach. Zum Beispiel hier: https://en.cppreference.com/w/c/io/fscanf



  • @Cia sagte in Fehler in der Schleife:

    ...
    Und eine zusätzliche Frage habe ich auch noch:
    Gibt es eine Möglichkeit die Symbole in ein Spielfeld zu schreiben, statt das es immer wieder neu in die Console geschrieben wird?

    Falls Du für Windows programmierst:
    Hier gibt es, was Dein Herz begehrt:
    https://docs.microsoft.com/en-us/windows/console/console-functions



  • @Belli @Wade1234 ⏩ PDCurses



  • Jo, ich weiß ...
    Aber so für unter Windows empfehle ich immer die nativen Windows-Funktionen, ich finde, da lernt man immer noch mal ne Menge über sein (Windows)System dazu.
    Und - sie sind einfach da, ohne noch irgendwie irgendwo irgendwas nachzuinstallieren.



  • @wob sagte in Fehler in der Schleife:

    tut, schau in der Refenrenz nach. Zum Beispiel hier:

    scanf_s unterscheidet sich aber zu scanf in einigen Formatspecifieren.



  • @DirkB auf windows mit visual studio 2019:)

    Dankii schön



  • @DirkB sagte in Fehler in der Schleife:

    @wob sagte in Fehler in der Schleife:

    tut, schau in der Refenrenz nach. Zum Beispiel hier:

    scanf_s unterscheidet sich aber zu scanf in einigen Formatspecifieren.

    Genau, weswegen man die Referenz auch vollständig lesen muss. Die Funktionen scanf, fscanf, sscanf, scanf_s, fscanf_s, sscanf_s sind zusammen erklärt. Es stehen Zahlen neben den Funktionen. Die mit _s sind 4 bis 6. Und da steht dann auch, wo der Unterschied genau liegt.


Anmelden zum Antworten