Créer un jeu 2048 en C

CBeginner
Pratiquer maintenant

Introduction

2048 est un jeu de puzzle numérique populaire dont le but est d'atteindre la tuile 2048 en fusionnant des tuiles adjacentes ayant le même nombre. Dans ce projet, vous allez apprendre à créer un simple jeu 2048 en C. Nous fournirons des instructions étape par étape pour construire le jeu, depuis l'initialisation du plateau jusqu'à la mise en œuvre de la logique du jeu et l'exécution du jeu.

👀 Aperçu

2048 Game

🎯 Tâches

Dans ce projet, vous allez apprendre :

  • Comment créer les fichiers du projet
  • Comment définir des constantes pour le jeu
  • Comment implémenter la fonction main() pour exécuter la boucle du jeu
  • Comment initialiser le plateau de jeu
  • Comment implémenter des fonctions pour vérifier l'état du jeu
  • Comment créer la logique pour déplacer les tuiles
  • Comment afficher le plateau de jeu
  • Comment compiler et tester le jeu

🏆 Réalisations

Après avoir terminé ce projet, vous serez en mesure de :

  • Créer un programme C pour un jeu
  • Utiliser des tableaux pour représenter le plateau de jeu
  • Implémenter la logique du jeu pour fusionner les tuiles
  • Afficher le plateau de jeu
  • Gérer les entrées du joueur
  • Vérifier les conditions de fin de jeu et de victoire

Créer les fichiers du projet

Tout d'abord, créez un nouveau fichier nommé 2048.c et ouvrez-le dans votre éditeur de code préféré.

cd ~/project
touch 2048.c
✨ Vérifier la solution et pratiquer

Définir les constantes

Tout d'abord, nous devons écrire le code C. La première étape consiste à inclure les fichiers d'en-tête :

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

Avant d'écrire la fonction main(), effectuons quelques tâches de base pour définir certaines constantes :

#define SIZE 4
#define WIN_SCORE 2048

int board[SIZE][SIZE];
int score = 0;
✨ Vérifier la solution et pratiquer

Fonction main

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() : Cet appel de fonction initialise le plateau de jeu, met toutes les cellules du plateau de jeu à 0, puis génère deux nombres aléatoires initiaux (2 ou 4) à des emplacements aléatoires.
  • print_board() : Cette fonction est utilisée pour afficher l'état actuel du plateau de jeu, y compris le score actuel et le nombre sur chaque cellule.
  • while (1) : Il s'agit d'une boucle infinie qui continuera à exécuter le jeu jusqu'à ce que la condition de fin de jeu soit remplie.

Le flux principal du jeu 2048 est implémenté ici, y compris l'initialisation du plateau de jeu, le déplacement des blocs de nombres, le jugement de la victoire ou de la défaite du jeu et l'attente de l'entrée du joueur pour contrôler le déroulement du jeu.

✨ Vérifier la solution et pratiquer

Initialiser le plateau de jeu

Pour initialiser le plateau de jeu, nous allons créer une fonction init_board qui configure le plateau et génère deux nombres aléatoires initiaux.

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;
    }
}

Ce que fait cette fonction, c'est qu'au début du jeu, elle vide toutes les cellules du plateau de jeu et génère deux blocs de nombres aléatoires initiaux à des emplacements aléatoires, fournissant au joueur un état de jeu initial.

✨ Vérifier la solution et pratiquer

Implémenter les fonctions pour vérifier l'état du jeu

Nous avons besoin de fonctions pour vérifier si le joueur a gagné, si le plateau est plein et s'il reste des mouvements valides. Voici les fonctions :

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() : Cette fonction est utilisée pour vérifier si le plateau est plein, c'est-à-dire si toutes les cellules sont occupées.

  • int is_won() : Cette fonction vérifie si le joueur a gagné, c'est-à-dire s'il y a une cellule avec la valeur de WIN_SCORE (généralement 2048) pour gagner le jeu.

  • int can_move() : Cette fonction est utilisée pour vérifier s'il reste des mouvements valides afin de garantir que le jeu peut continuer.

✨ Vérifier la solution et pratiquer

Créer la logique pour déplacer les tuiles

Implémentez la logique pour déplacer les tuiles dans la fonction move. Cette fonction gère le mouvement du joueur dans quatre directions : haut, bas, gauche et droite. Elle vérifie également si le mouvement est valide, met à jour le score et génère un nouveau nombre aléatoire.

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;
    }
}
  • Tout d'abord, définissez une variable moved pour marquer si un mouvement s'est produit. La valeur initiale est 0, indiquant qu'aucun mouvement n'a eu lieu. Créez un tableau 2D temporaire appelé prev_board pour stocker l'état actuel du plateau de jeu afin qu'il puisse être restauré à l'état précédent si le mouvement échoue.

  • Copiez l'état actuel du plateau de jeu dans prev_board, enregistrant l'état actuel du plateau de jeu au cas où le mouvement échouerait.

  • Selon la valeur du paramètre dir (0 pour haut, 1 pour bas, 2 pour gauche, 3 pour droite), l'opération de mouvement correspondante est effectuée.

  • Si un mouvement ou une fusion se produit, le drapeau moved est défini sur 1, indiquant que l'état du jeu a changé. Si l'opération de mouvement ou de fusion est effectuée avec succès, un nouveau nombre aléatoire est généré, qui est utilisé pour générer un nouveau bloc de nombres dans un emplacement vide sur le plateau de jeu. Enfin, si un mouvement se produit (moved est égal à 1), la fonction retourne 1, indiquant que le mouvement a réussi. Si le mouvement échoue (il n'y a pas d'opération de mouvement ou de fusion), le plateau de jeu est restauré à son état précédent, retournant 0, indiquant que le mouvement a échoué.

✨ Vérifier la solution et pratiquer

Afficher le plateau de jeu

Pour afficher le plateau de jeu, nous allons créer une fonction print_board qui efface le terminal et affiche l'état actuel du plateau.

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");
    }
}

Le but principal ici est d'effacer l'écran du terminal, puis d'afficher le score actuel en haut de l'écran, et ensuite d'afficher l'état du plateau de jeu à l'écran afin que le joueur puisse clairement voir les blocs de nombres sur le plateau de jeu et le score. Cela contribue à fournir une interface conviviale qui permet aux joueurs de connaître l'état actuel du jeu.

✨ Vérifier la solution et pratiquer

Compiler et tester

Entrez la commande suivante dans le terminal pour compiler et exécuter :

cd ~/project
gcc -o 2048 2048.c
./2048
Jeu 2048
✨ Vérifier la solution et pratiquer

Résumé

Dans ce projet, vous avez appris à créer un jeu de base 2048 en C. Vous avez initialisé le plateau de jeu, implémenté des fonctions pour vérifier l'état du jeu, créé la logique pour déplacer les tuiles, affiché le plateau de jeu et exécuté le jeu. Amusez-vous bien à jouer et à améliorer encore votre jeu 2048!