Erstellen eines einfachen Tic-Tac-Toe-Spiels in C

CCBeginner
Jetzt üben

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Projekt lernst du, wie du ein einfaches Tic-Tac-Toe-Spiel in C programmierst. Das Spiel wird von zwei Spielern gespielt, die abwechselnd Felder in einem 3x3-Raster markieren. Der erste Spieler, der drei seiner Markierungen in einer Reihe, Spalte oder Diagonale hat, gewinnt. Wenn alle Felder gefüllt sind und kein Spieler drei Markierungen in einer Reihe hat, endet das Spiel unentschieden.

👀 Vorschau

Tic Tac Toe game preview

🎯 Aufgaben

In diesem Projekt wirst du lernen:

  • Wie man ein Spielfeld erstellt und es mit leeren Feldern initialisiert.
  • Wie man Funktionen implementiert, um den Bildschirm zu löschen, das Spielfeld anzuzeigen und zu prüfen, ob das Spiel beendet ist.
  • Wie man den Gewinner des Spiels ermittelt.
  • Wie man die Hauptspielschleife implementiert, damit die Spieler abwechselnd am Zug sind und mit dem Spiel interagieren können.

🏆 Errungenschaften

Nach Abschluss dieses Projekts kannst du:

  • Arrays in C erstellen und manipulieren.
  • Schleifen und bedingte Anweisungen verwenden, um die Spiellogik zu implementieren.
  • Mit dem Benutzer über die Befehlszeilenschnittstelle interagieren.
  • Code in Funktionen organisieren, um eine bessere Modularität und Lesbarkeit zu erreichen.

Erstellen der Projekt-Dateien

Zuerst erstelle eine neue Datei mit dem Namen tictactoe.c und öffne sie in deinem bevorzugten Code-Editor.

cd ~/project
touch tictactoe.c
✨ Lösung prüfen und üben

Definieren von Konstanten

Jetzt müssen wir den C-Code schreiben. Der erste Schritt besteht darin, die Header-Dateien einzubinden:

#include <stdio.h>
#include <stdbool.h>

Definieren Sie die Größe des Spielfelds:

char board[3][3];
✨ Lösung prüfen und üben

Initialisieren des Spielfelds

Initialisiere das Spielfeld mit leeren Feldern.

void initializeBoard() {
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            board[i][j] = ' ';
        }
    }
}

Die erste for-Schleife ist eine äußere Schleife, die die Variable i verwendet, um von 0 bis 2 zu iterieren. Dies repräsentiert die Anzahl der Reihen auf dem Spielfeld. Die zweite for-Schleife ist eine innere Schleife, die die Variable j verwendet, um von 0 bis 2 zu iterieren und somit die Anzahl der Spalten auf dem Spielfeld darstellt.

board[i][j] = ' ' setzt in der inneren Schleife den Inhalt der Felder in der i-ten Zeile und j-ten Spalte des Spielfelds auf das Leerzeichen (' '). Dies bedeutet, dass das gesamte Spielfeld in einen leeren Zustand initialisiert wird, d. h. noch keine Spieler auf dem Spielfeld gespielt haben.

✨ Lösung prüfen und üben

Bildschirm nach jedem Zug löschen

Implementiere eine Funktion, um den Bildschirm nach jedem Zug zu löschen.

void clearScreen() {
    printf("\033[H\033[J");
}

Die clearScreen-Funktion wird hauptsächlich verwendet, um den Inhalt des Terminals oder Konsolenbildschirms zu löschen, um den vorherigen Spielzustand und die Ausgabe am Ende jedes Zuges zu entfernen. Dies geschieht, indem eine spezielle Escape-Sequenz an einen Standardausgabestrom (normalerweise ein Terminalfenster) ausgegeben wird, die den Textinhalt auf dem Bildschirm löscht.

printf("\033[H\033[J") verwendet ANSI-Escape-Sequenzen:

  • \033 ist die oktale Darstellung des ASCII-Escape-Zeichens, das den Beginn der Sequenz markiert.
  • [H gibt an, dass der Cursor in die obere linke Ecke des Bildschirms bewegt wird, was äquivalent ist zu einer Positionierung des Cursors in die erste Zeile und erste Spalte des Bildschirms.
  • [J steht für Bildschirm löschen. Es löscht alle Textinhalte nach der Cursorposition, einschließlich des vorherigen Spielzustands und der Ausgabe.

Das bedeutet, dass jedes Mal, wenn die clearScreen-Funktion aufgerufen wird, der Inhalt des aktuellen Terminals oder Konsolenbildschirms gelöscht wird, um den neuen Spielzustand vor der nächsten Spielrunde anzuzeigen, was zu einer saubereren Benutzeroberfläche führt.

✨ Lösung prüfen und üben

Anzeigen des Spielfelds

Erstelle die printBoard-Funktion, um den aktuellen Zustand des Spielfelds visuell auf dem Bildschirm anzuzeigen. Dadurch kann der Spieler die Position der Spielsteine auf dem Spielfeld verstehen. Dies ist ein Teil des Spiels, der in Tic-Tac-Toe-Spielen verwendet wird, um den Spielzustand anzuzeigen.

void printBoard() {
    printf("\n");
    printf("  1   2   3\n");
    printf("1 %c | %c | %c\n", board[0][0], board[0][1], board[0][2]);
    printf("  ---------\n");
    printf("2 %c | %c | %c\n", board[1][0], board[1][1], board[1][2]);
    printf("  ---------\n");
    printf("3 %c | %c | %c\n", board[2][0], board[2][1], board[2][2]);
}
✨ Lösung prüfen und üben

Prüfen, ob das Spiel beendet ist

Implementiere eine Funktion namens isGameOver, um zu bestimmen, ob das Tic-Tac-Toe-Spiel beendet ist, und gebe einen booleschen Wert (true oder false) zurück.

bool isGameOver() {
    // Check rows
    for (int i = 0; i < 3; i++) {
        if (board[i][0]!= ' ' && board[i][0] == board[i][1] && board[i][0] == board[i][2]) {
            return true;
        }
    }

    // Check columns
    for (int j = 0; j < 3; j++) {
        if (board[0][j]!= ' ' && board[0][j] == board[1][j] && board[0][j] == board[2][j]) {
            return true;
        }
    }

    // Check diagonals
    if (board[0][0]!= ' ' && board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
        return true;
    }
    if (board[0][2]!= ' ' && board[0][2] == board[1][1] && board[0][2] == board[2][0]) {
        return true;
    }

    // Check for a draw
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            if (board[i][j] == ' ') {
                return false;
            }
        }
    }

    return true;
}

Prüfen, ob eine Zeile einen Gewinner hat: Wenn alle drei Zellen in einer Zeile von demselben Spieler besetzt sind, gibt es einen Gewinner und die Funktion gibt true zurück.

Prüfen, ob eine Spalte einen Gewinner hat: Wenn alle drei Zellen in einer Spalte von demselben Spieler besetzt sind, gibt es einen Gewinner und die Funktion gibt true zurück.

Prüfen, ob es einen Gewinner auf der Diagonale gibt: Wenn alle drei Felder auf einer beliebigen Diagonale von demselben Spieler besetzt sind, gibt es einen Gewinner und die Funktion gibt true zurück.

Prüfen auf ein Unentschieden: Schließlich prüft die Funktion, ob alle Zellen besetzt sind, aber es keinen Gewinner gibt. Wenn dies der Fall ist, endet das Spiel unentschieden und die Funktion gibt true zurück.

✨ Lösung prüfen und üben

Bestimmung des Gewinners

Es wird eine Funktion namens getWinner definiert, deren Zweck es ist, zu bestimmen, ob es in einem Tic-Tac-Toe-Spiel einen Gewinner gibt, und das Symbol des Gewinners (X oder O) zurückzugeben. Wenn es keinen Gewinner gibt, wird ein Leerzeichen (' ') zurückgegeben.

char getWinner() {
    // Check rows
    for (int i = 0; i < 3; i++) {
        if (board[i][0]!= ' ' && board[i][0] == board[i][1] && board[i][0] == board[i][2]) {
            return board[i][0];
        }
    }

    // Check columns
    for (int j = 0; j < 3; j++) {
        if (board[0][j]!= ' ' && board[0][j] == board[1][j] && board[0][j] == board[2][j]) {
            return board[0][j];
        }
    }

    // Check diagonals
    if (board[0][0]!= ' ' && board[0][0] == board[1][1] && board[0][0] == board[2][2]) {
        return board[0][0];
    }
    if (board[0][2]!= ' ' && board[0][2] == board[1][1] && board[0][2] == board[2][0]) {
        return board[0][2];
    }

    return ' '; // No winner
}
✨ Lösung prüfen und üben

Implementierung der Hauptspielschleife

Schreibe die Hauptspielschleife, um es den Spielern zu ermöglichen, abwechselnd Züge zu machen und mit dem Spiel zu interagieren.

int main() {
    initializeBoard();
    int currentPlayer = 1;

    while (1) {
        clearScreen();
        printf("Current board state:\n");
        printBoard();

        int row, col;
        printf("Player %d, please enter a row and column (e.g., 1 2):", currentPlayer);

        while (scanf("%d %d", &row, &col)!= 2) {
            printf("Invalid input, please try again: ");
            while (getchar()!= '\n');
        }

        if (row < 1 || row > 3 || col < 1 || col > 3 || board[row - 1][col - 1]!= ' ') {
            printf("Invalid move, please try again.\n");
        } else {
            if (currentPlayer == 1) {
                board[row - 1][col - 1] = 'X';
                currentPlayer = 2;
            } else {
                board[row - 1][col - 1] = 'O';
                currentPlayer = 1;
            }
        }

        if (isGameOver()) {
            clearScreen();
            printf("Game over!\n");
            printBoard();
            char winner = getWinner();
            if (winner!= ' ') {
                printf("Player %c wins!\n", winner);
            } else {
                printf("It's a draw!\n");
            }
            break;
        }
    }

    return 0;
}

Rufe die initializeBoard-Funktion auf, um das Spielfeld zu initialisieren und alle Felder auf Leerzeichen zu setzen.

Erstelle eine Ganzzahlvariable currentPlayer, um zu verfolgen, wen es an der Reihe ist. Die Anfangseinstellung ist 1, was Spieler 1 bedeutet.

In der while (1)-Hauptschleife:

  • Rufe die clearScreen-Funktion auf, um den Bildschirm zu löschen, damit die Anzeige nach jedem Zug aktualisiert wird.
  • Rufe die printBoard-Funktion auf, um das aktuelle Spielfeld auszugeben.

Spielereingabe: Fordert den aktuellen Spieler auf, über die scanf-Funktion Zeilen- und Spaltenkoordinaten einzugeben, z.B. Player 1, please enter a row and column (e.g., 1 2): . Wenn die Eingabe ungültig ist (nicht zwei Ganzzahlen), wird die Meldung Invalid input, please try again: angezeigt und der Eingabepuffer geleert, bis eine gültige Eingabe erhalten wird.

Eingabevalidierung: Überprüfe dann, ob die eingegebenen Zeilen- und Spaltenkoordinaten gültig sind (im Bereich von 1 bis 3) und ob die ausgewählte Position ein Leerzeichen ist. Wenn die Eingabe ungültig ist oder die ausgewählte Position bereits belegt ist, wird die Meldung Invalid move, please try again. angezeigt und der Spieler aufgefordert, erneut einzugeben.

Zug ausführen: Wenn die Eingabe gültig ist, platziert der Code ein X oder ein O an der entsprechenden Position auf dem Spielfeld, abhängig vom aktuellen Spieler (1 oder 2).

Spielendeerkennung: Der Code ruft dann die isGameOver()-Funktion auf, um zu überprüfen, ob das Spiel beendet ist. Wenn das Spiel endet, wird der Bildschirm gelöscht und eine Meldung angezeigt, dass das Spiel beendet ist, einschließlich eines Gewinners (falls vorhanden) oder eines Unentschiedens.

Spielergebnis: Wenn es einen Gewinner gibt, wird der Code Player X wins! oder Player O wins! ausgeben, je nachdem, welcher Spieler der Gewinner ist. Wenn es keinen Gewinner gibt, wird der Code It's a draw! ausgeben, um ein Unentschieden anzuzeigen.

✨ Lösung prüfen und üben

Projekt kompilieren und ausführen

Führe den gcc-Befehl aus, um das Projekt zu kompilieren:

cd ~/project
gcc -o tictactoe tictactoe.c
./tictactoe
Tic Tac Toe game demo
✨ Lösung prüfen und üben

Zusammenfassung

Herzlichen Glückwunsch! Sie haben erfolgreich ein einfaches Tic-Tac-Toe-Spiel in C erstellt. Die Spieler können abwechselnd Züge machen und ihre Positionen auf dem 3x3-Raster markieren. Das Spiel prüft nach jedem Zug, ob es einen Gewinner gibt oder ob es unentschieden ausgeht, und zeigt das Ergebnis entsprechend an. Dieses einfache Projekt demonstriert die grundlegenden Konzepte der C-Programmierung und kann als Ausgangspunkt für die Entwicklung komplexerer Spiele dienen.