Erstellen eines 2048-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

2048 ist ein beliebtes Zahlenrätselspiel, bei dem das Ziel darin besteht, die Kachel mit der Zahl 2048 zu erreichen, indem man benachbarte Kacheln mit der gleichen Zahl zusammenführt. In diesem Projekt lernst du, wie man ein einfaches 2048-Spiel in C erstellt. Wir geben schrittweise Anweisungen, um das Spiel zu entwickeln, von der Initialisierung des Spielfelds bis zur Implementierung der Spiel Logik und zum Ausführen des Spiels.

👀 Vorschau

2048 Spiel

🎯 Aufgaben

In diesem Projekt wirst du lernen:

  • Wie man die Projekt Dateien erstellt
  • Wie man Konstanten für das Spiel definiert
  • Wie man die main()-Funktion implementiert, um die Spielschleife auszuführen
  • Wie man das Spielfeld initialisiert
  • Wie man Funktionen implementiert, um den Spielzustand zu überprüfen
  • Wie man die Logik für das Bewegen der Kacheln erstellt
  • Wie man das Spielfeld anzeigt
  • Wie man das Spiel kompiliert und testet

🏆 Errungenschaften

Nach Abschluss dieses Projekts kannst du:

  • Ein C-Programm für ein Spiel erstellen
  • Arrays verwenden, um das Spielfeld darzustellen
  • Spiel Logik für das Zusammenführen von Kacheln implementieren
  • Das Spielfeld anzeigen
  • Spieler Eingaben verarbeiten
  • Überprüfen, ob das Spiel vorbei ist oder ob die Gewinnbedingung erfüllt ist

Erstellen der Projekt Dateien

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

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

Definieren von Konstanten

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

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

Bevor wir die main()-Funktion schreiben, lassen Sie uns einige grundlegende Aufgaben erledigen, um einige Konstanten zu definieren:

#define SIZE 4
#define WIN_SCORE 2048

int board[SIZE][SIZE];
int score = 0;
✨ Lösung prüfen und üben

main-Funktion

int main() {
    srand(time(NULL));
    init_board();
    print_board();

    while (1) {
        if (is_won()) {
            printf("You won!\n");
            break;
        }

        if (is_full() &&!can_move()) {
            printf("Game over!\n");
            break;
        }

        int direction;
        printf("Enter the move direction (0-Up, 1-Down, 2-Left, 3-Right): ");
        scanf("%d", &direction);

        if (move(direction)) {
            // Print the board after the move
            print_board();
        }
    }

    return 0;
}
  • init_board(): Dieser Funktionsaufruf initialisiert das Spielfeld, setzt alle Zellen des Spielfelds auf 0 und generiert dann zwei anfängliche Zufallszahlen (2 oder 4) an zufälligen Positionen.
  • print_board(): Diese Funktion wird verwendet, um den aktuellen Zustand des Spielfelds anzuzeigen, einschließlich des aktuellen Punktestands und der Zahl in jeder Zelle.
  • while (1): Dies ist eine Endlosschleife, die das Spiel ausführt, bis die Spiel-Endbedingung erfüllt ist.

Der Hauptablauf des 2048-Spiels wird hier implementiert, einschließlich der Initialisierung des Spielfelds, des Verschiebens der Zahlenblöcke, der Beurteilung des Spielsiegs oder -niedergangs und des Wartens auf die Spieler Eingabe zur Steuerung des Spielverlaufs.

✨ Lösung prüfen und üben

Initialisierung des Spielfelds

Um das Spielfeld zu initialisieren, erstellen wir eine Funktion init_board, die das Spielfeld einrichtet und zwei anfängliche Zufallszahlen generiert.

void init_board() {
    // Initialize the board by setting all cells to 0
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            board[i][j] = 0;
        }
    }

    // Generate two initial random numbers
    for (int k = 0; k < 2; k++) {
        int i = rand() % SIZE;
        int j = rand() % SIZE;
        int value = (rand() % 2 + 1) * 2; // Generate 2 or 4 randomly
        board[i][j] = value;
    }
}

Was diese Funktion tut, ist, dass zu Beginn des Spiels alle Zellen auf dem Spielfeld geleert werden und zwei anfängliche Zufallsblöcke mit Zahlen an zufälligen Positionen generiert werden, um dem Spieler einen anfänglichen Spielzustand zu bieten.

✨ Lösung prüfen und üben

Implementierung von Funktionen zur Überprüfung des Spielzustands

Wir benötigen Funktionen, um zu überprüfen, ob der Spieler gewonnen hat, ob das Spielfeld voll ist und ob noch gültige Züge möglich sind. Hier sind die Funktionen:

int is_full() {
    // Check if the board is full
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            if (board[i][j] == 0) {
                return 0; // Board is not full
            }
        }
    }
    return 1; // Board is full
}

int is_won() {
    // Check if the player has won
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            if (board[i][j] == WIN_SCORE) {
                return 1; // Player has won
            }
        }
    }
    return 0; // Player has not won
}

int can_move() {
    // Check if there are any valid moves left
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            if (board[i][j] == 0) {
                return 1; // There are still empty cells to move
            }
            if (j > 0 && board[i][j] == board[i][j - 1]) {
                return 1; // Can move left
            }
            if (j < SIZE - 1 && board[i][j] == board[i][j + 1]) {
                return 1; // Can move right
            }
            if (i > 0 && board[i][j] == board[i - 1][j]) {
                return 1; // Can move up
            }
            if (i < SIZE - 1 && board[i][j] == board[i + 1][j]) {
                return 1; // Can move down
            }
        }
    }
    return 0; // No valid moves left
}
  • int is_full(): Diese Funktion wird verwendet, um zu überprüfen, ob das Spielfeld voll ist, d. h., ob alle Zellen belegt sind.

  • int is_won(): Diese Funktion überprüft, ob der Spieler gewonnen hat, d. h., ob es eine Zelle mit dem Wert von WIN_SCORE (normalerweise 2048) für den Sieg im Spiel gibt.

  • int can_move(): Diese Funktion wird verwendet, um zu überprüfen, ob es noch gültige Züge gibt, um sicherzustellen, dass das Spiel fortgesetzt werden kann.

✨ Lösung prüfen und üben

Implementierung der Logik zum Verschieben von Kacheln

Implementieren Sie die Logik zum Verschieben von Kacheln in der move-Funktion. Diese Funktion behandelt die Züge des Spielers in vier Richtungen: nach oben, unten, links und rechts. Sie überprüft auch, ob der Zug gültig ist, aktualisiert den Punktestand und generiert eine neue Zufallszahl.

int move(int dir) {
    int moved = 0;

    // Store the current board state
    int prev_board[SIZE][SIZE];
    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            prev_board[i][j] = board[i][j];
        }
    }

    // Move upwards
    if (dir == 0) {
        for (int j = 0; j < SIZE; j++) {
            for (int i = 1; i < SIZE; i++) {
                if (board[i][j]!= 0) {
                    int k = i;
                    while (k > 0 && board[k - 1][j] == 0) {
                        board[k - 1][j] = board[k][j];
                        board[k][j] = 0;
                        k--;
                        moved = 1;
                    }
                    if (k > 0 && board[k - 1][j] == board[k][j]) {
                        board[k - 1][j] *= 2;
                        score += board[k - 1][j];
                        board[k][j] = 0;
                        moved = 1;
                    }
                }
            }
        }
    }

    // Move downwards
    else if (dir == 1) {
        for (int j = 0; j < SIZE; j++) {
            for (int i = SIZE - 2; i >= 0; i--) {
                if (board[i][j]!= 0) {
                    int k = i;
                    while (k < SIZE - 1 && board[k + 1][j] == 0) {
                        board[k + 1][j] = board[k][j];
                        board[k][j] = 0;
                        k++;
                        moved = 1;
                    }
                    if (k < SIZE - 1 && board[k + 1][j] == board[k][j]) {
                        board[k + 1][j] *= 2;
                        score += board[k + 1][j];
                        board[k][j] = 0;
                        moved = 1;
                    }
                }
            }
        }
    }

    // Move left
    else if (dir == 2) {
        for (int i = 0; i < SIZE; i++) {
            for (int j = 1; j < SIZE; j++) {
                if (board[i][j]!= 0) {
                    int k = j;
                    while (k > 0 && board[i][k - 1] == 0) {
                        board[i][k - 1] = board[i][k];
                        board[i][k] = 0;
                        k--;
                        moved = 1;
                    }
                    if (k > 0 && board[i][k - 1] == board[i][k]) {
                        board[i][k - 1] *= 2;
                        score += board[i][k - 1];
                        board[i][k] = 0;
                        moved = 1;
                    }
                }
            }
        }
    }

    // Move right
    else if (dir == 3) {
        for (int i = 0; i < SIZE; i++) {
            for (int j = SIZE - 2; j >= 0; j--) {
                if (board[i][j]!= 0) {
                    int k = j;
                    while (k < SIZE - 1 && board[i][k + 1] == 0) {
                        board[i][k + 1] = board[i][k];
                        board[i][k] = 0;
                        k++;
                        moved = 1;
                    }
                    if (k < SIZE - 1 && board[i][k + 1] == board[i][k]) {
                        board[i][k + 1] *= 2;
                        score += board[i][k + 1];
                        board[i][k] = 0;
                        moved = 1;
                    }
                }
            }
        }
    }

    // Check if the move was successful
    if (moved) {
        // Generate a new random number
        int i = rand() % SIZE;
        int j = rand() % SIZE;
        while (board[i][j]!= 0) {
            i = rand() % SIZE;
            j = rand() % SIZE;
        }
        board[i][j] = (rand() % 2 + 1) * 2; // Generate 2 or 4

        // Print the board after the move
        print_board();
    }

    // Check if the move was successful
    if (moved) {
        return 1;
    } else {
        // If the move failed, restore the previous board state
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                board[i][j] = prev_board[i][j];
            }
        }
        return 0;
    }
}
  • Zunächst wird eine Variable moved definiert, um zu markieren, ob ein Zug erfolgt ist. Der Anfangswert ist 0, was bedeutet, dass keine Bewegung stattgefunden hat. Ein temporäres 2D-Array namens prev_board wird erstellt, um den aktuellen Zustand des Spielfelds zu speichern, damit es bei einem fehlgeschlagenen Zug in den vorherigen Zustand zurückgesetzt werden kann.

  • Der aktuelle Zustand des Spielfelds wird in prev_board kopiert, um den aktuellen Zustand des Spielfelds im Falle eines fehlgeschlagenen Zuges zu sichern.

  • Entsprechend dem Wert des Parameters dir (0 für oben, 1 für unten, 2 für links, 3 für rechts) wird die entsprechende Verschiebungsoperation ausgeführt.

  • Wenn eine Verschiebung oder ein Zusammenführen erfolgt, wird die moved-Flagge auf 1 gesetzt, was bedeutet, dass sich der Spielzustand geändert hat. Wenn die Verschiebungs- oder Zusammenführungsoperation erfolgreich ausgeführt wird, wird eine neue Zufallszahl generiert, die verwendet wird, um einen neuen Zahlenblock an einem leeren Platz auf dem Spielfeld zu generieren. Schließlich gibt die Funktion 1 zurück, wenn eine Bewegung erfolgt ist (moved ist 1), was bedeutet, dass der Zug erfolgreich war. Wenn der Zug fehlschlägt (es gibt keine Verschiebungs- oder Zusammenführungsoperation), wird das Spielfeld in seinen vorherigen Zustand zurückgesetzt und 0 zurückgegeben, was bedeutet, dass der Zug fehlgeschlagen ist.

✨ Lösung prüfen und üben

Anzeige des Spielfelds

Um das Spielfeld anzuzeigen, erstellen wir eine print_board-Funktion, die das Terminal leert und den aktuellen Zustand des Spielfelds ausgibt.

void print_board() {
    // Clear the terminal
    system("clear");

    printf("Score: %d\n", score);

    for (int i = 0; i < SIZE; i++) {
        for (int j = 0; j < SIZE; j++) {
            printf("%4d", board[i][j]);
        }
        printf("\n");
    }
}

Der Hauptzweck hier ist es, den Terminalbildschirm zu leeren, dann den aktuellen Punktestand oben auf dem Bildschirm anzuzeigen und anschließend den Zustand des Spielfelds auf dem Bildschirm auszugeben, damit der Spieler die Zahlenblöcke auf dem Spielfeld und den Punktestand deutlich sehen kann. Dies hilft, eine benutzerfreundliche Schnittstelle bereitzustellen, die es den Spielern ermöglicht, den aktuellen Spielzustand zu kennen.

✨ Lösung prüfen und üben

Kompilieren und Testen

Geben Sie den folgenden Befehl im Terminal ein, um zu kompilieren und auszuführen:

cd ~/project
gcc -o 2048 2048.c
./2048
2048 Game
✨ Lösung prüfen und üben

Zusammenfassung

In diesem Projekt haben Sie gelernt, wie man ein einfaches 2048-Spiel in C erstellt. Sie haben das Spielfeld initialisiert, Funktionen zur Überprüfung des Spielzustands implementiert, die Logik zum Verschieben von Kacheln erstellt, das Spielfeld angezeigt und das Spiel gestartet. Viel Spaß beim Spielen und beim weiteren Verbessern Ihres 2048-Spiels!