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

🎯 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
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;
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.
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.
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 deWIN_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.
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
movedpour 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_boardpour 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
movedest 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 (movedest é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é.
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.
Compiler et tester
Entrez la commande suivante dans le terminal pour compiler et exécuter :
cd ~/project
gcc -o 2048 2048.c
./2048

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!



