Création d'un jeu de Puissance 5 en C

CCBeginner
Pratiquer maintenant

💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici

Introduction

Dans ce projet, nous allons créer un simple jeu de Gomoku basé sur le texte à l'aide du langage de programmation C. Le Gomoku est un jeu de plateau de stratégie à deux joueurs où l'objectif est d'être le premier à aligner cinq pions consécutifs, horizontalement, verticalement ou en diagonale. Nous allons développer ce jeu en utilisant un plateau de jeu de 15x15.

👀 Aperçu

Gomoku Game

🎯 Tâches

Dans ce projet, vous allez apprendre :

  • Comment concevoir et implémenter un plateau d'échecs à l'aide d'un tableau à deux dimensions en C.
  • Comment créer une fonction principale pour contrôler le déroulement du jeu.
  • Comment implémenter des fonctions pour initialiser le jeu, afficher le plateau d'échecs et permettre aux joueurs de prendre leurs tours.
  • Comment développer une fonction pour vérifier si une condition de victoire est atteinte dans le jeu.
  • Comment compiler et exécuter le programme.

🏆 Réalisations

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

  • Travailler avec des tableaux à deux dimensions en C.
  • Concevoir et implémenter un déroulement de jeu à l'aide de fonctions.
  • Vérifier les conditions de victoire dans un jeu.
  • Compiler et exécuter un programme C.

Créer les fichiers du projet

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

cd ~/projet
touch gomoku.c
✨ Vérifier la solution et pratiquer

Conception d'un plateau d'échecs

Utiliser 'O' et 'X' pour représenter les pièces

Tout d'abord, nous avons besoin d'un plateau d'échecs (15 * 15) pour enregistrer la "situation" de chaque position sur le plateau. Nous pouvons donc définir un tableau chessboard[16][16]. Pourquoi pas [15][15]? C'est parce que de cette manière, les coordonnées du tableau correspondent exactement aux lignes et aux colonnes du plateau d'échecs, ce qui facilite l'écriture du code ultérieur.

#include <stdio.h>

#define N 15

// Définir un tableau et attribuer 0 comme valeur initiale à chaque élément.
int chessboard[N + 1][N + 1] = { 0 };
✨ Vérifier la solution et pratiquer

Fonction principale

Avant de commencer à écrire la fonction principale, considérons brièvement le déroulement typique d'un jeu. Tout d'abord, nous entrons dans l'interface principale du jeu, puis nous cliquons sur le bouton de démarrage pour entrer dans le jeu, puis le plateau de jeu est affiché, la victoire ou la défaite est déterminée et le jeu prend fin. Alors, quel est le déroulement d'un jeu comme le Go?

Tout d'abord, nous entrons dans l'écran d'accueil du jeu, puis nous entrons Y pour commencer le jeu (sinon, nous quittons le jeu), le plateau de jeu est affiché et les deux joueurs prennent tour à tour leurs tours pour placer leurs pièces, puis la victoire ou la défaite est déterminée (s'il y a cinq pièces alignées).

// Elle est utilisée pour suivre si c'est le tour du joueur 1 ou du joueur 2, un nombre impair représentant le tour du joueur 1 et un nombre pair représentant le tour du joueur 2.
int whoseTurn = 0;

int main(void)
{
	// Une fonction personnalisée qui initialise le jeu, c'est-à-dire qui affiche l'écran d'accueil et entre dans le plateau de jeu.
	initGame();

	// Cette boucle est pour que les deux joueurs prennent tour à tour leurs tours.
	while (1)
	{
		// A chaque cycle, on incrémente de 1, de sorte que deux personnes puissent prendre tour à tour leurs tours.
		whoseTurn++;

		// Une fonction personnalisée qui effectue une opération de pose.
		playChess();
	}

	return 0;
}
✨ Vérifier la solution et pratiquer

Fonction initGame

Dans cette fonction, les fonctionnalités que nous souhaitons implémenter sont les suivantes :

  • Afficher un simple écran d'accueil.
  • Demander l'entrée de 'Y' et afficher le plateau d'échecs après l'entrée.
void initGame(void)
{
	char c;

	printf("Veuillez entrer 'y' pour commencer le jeu :");
	c = getchar();
	if ('y'!= c && 'Y'!= c)
		exit(0);

	//Effacer
	system("clear");

	//Ici, nous appelons à nouveau une fonction personnalisée dont la fonction est d'afficher le plateau d'échecs.
	printChessboard();
}

Dans la fonction initGame, nous utilisons les fonctions exit et system, donc nous devons inclure le fichier d'en-tête stdlib.h en haut du programme.

#include <stdlib.h>
✨ Vérifier la solution et pratiquer

Fonction printChessboard

Dans cette fonction, notre objectif est de :

  • Afficher les numéros de ligne et de colonne, et afficher le plateau d'échecs.
  • Si la valeur de l'élément du tableau est 0, afficher un astérisque (*) pour indiquer que la position est vide.
  • Si la valeur de l'élément du tableau est 1, afficher un cercle plein (X), représentant la pièce du joueur 1.
  • Si la valeur de l'élément du tableau est 2, afficher un cercle vide (O), représentant la pièce du joueur 2.
void printChessboard(void)
{
	int i, j;

	for (i = 0; i <= N; i++)
	{
		for (j = 0; j <= N; j++)
		{
			if (0 == i)		//Cela affiche le numéro de colonne.
				printf("%3d", j);
			else if (j == 0)	//Affiche le numéro de ligne.
				printf("%3d", i);
			else if (1 == chessboard[i][j])
				printf("  X");
			else if (2 == chessboard[i][j])
				printf("  O");
			else
				printf("  *");
		}
		printf("\n");
	}
}
✨ Vérifier la solution et pratiquer

Fonction playChess

Dans cette fonction, nous souhaitons réaliser les opérations suivantes :

  • Demander à l'utilisateur d'entrer la position pour placer la pièce.
  • Si c'est actuellement le tour du joueur 1, attribuer la valeur 1 à l'élément correspondant dans le tableau.
  • Si c'est actuellement le tour du joueur 2, attribuer la valeur 2 à l'élément correspondant dans le tableau.
  • Après chaque coup, déterminer si le joueur actuel a gagné.
void playChess(void)
{
	int i, j, winner;

	//Déterminer si c'est le tour du joueur 1 ou du joueur 2, puis attribuer la valeur à l'élément correspondant dans le tableau.
	if (1 == whoseTurn % 2)
	{
		printf("C'est au tour du joueur 1, veuillez entrer la position, le format est numéro de ligne + espace + numéro de colonne : ");
		scanf("%d %d", &i, &j);
		chessboard[i][j] = 1;
	}
	else
	{
		printf("C'est au tour du joueur 2, veuillez entrer la position, le format est numéro de ligne + espace + numéro de colonne : ");
		scanf("%d %d", &i, &j);
		chessboard[i][j] = 2;
	}

	//Afficher à nouveau le plateau.
	system("clear");
	printChessboard();	//Cette fonction est appelée à nouveau.

	/*
	*La section suivante appelle la fonction personnalisée (la fonction de jugement).
	*Elle est utilisée pour déterminer si le joueur actuel a gagné avec ce coup ou non.
	*/
	if (judge(i, j, whoseTurn))
	{
		if (1 == whoseTurn % 2)
			printf("Le gagnant est le joueur 1!\n");
		else
			printf("Le gagnant est le joueur 2!\n");
	}
}
✨ Vérifier la solution et pratiquer

Fonction judge

Paramètres de la fonction :

  • x : le numéro de ligne du coup actuel
  • y : le numéro de colonne du coup actuel

Valeur de retour :

  • 1 ou 0. 1 signifie que le joueur actuel a gagné après avoir effectué le coup.
int judge(int x, int y)
{
    int i, j;
    int t = 2 - whoseTurn % 2;
    const int step[4][2]={{-1,0},{0,-1},{1,1},{1,0}};
    for(int i=0;i<4;++i)
    {
        const int d[2]={-1,1};
        int count=1;
        for(int j=0;j<2;++j)
            for(int k=1;k<=4;++k){
                int row=x+k*d[j]*step[i][0];
                int col=y+k*d[j]*step[i][1];
                if( row>=1 && row<=N && col>=1 && col<=N &&
                    chessboard[x][y]==chessboard[row][col])
                    count+=1;
                else
                    break;
            }
        if(count>=5)
            return 1;
    }
    return 0;
}

Dans la fonction judge, il y a 3 boucles for imbriquées, et leur but est de déterminer s'il y a une ligne de cinq pièces consécutives.

Une ligne de cinq pièces peut être soit horizontale, soit verticale, soit diagonale. Ici, nous utiliserons une approche par essai et erreur, cherchant les pièces consécutives dans les directions horizontale, verticale et diagonale. Prendons un exemple :

Gomoku Game

Dans le plateau d'échecs ci-dessus, nous allons expliquer l'algorithme de détermination s'il y a une ligne de cinq pièces en fonction des coordonnées (9, 10).

Tout d'abord, nous vérifions s'il y a une ligne diagonale de cinq pièces partant de (9, 10). Le processus est le suivant :

  • En partant de (9, 10), nous cherchons dans la direction haut-gauche. Les coordonnées qui satisfont la condition sont (8, 9), (7, 8) et (6, 7). Puisque (5, 6) ne satisfait pas la condition, nous passons à l'étape suivante.
  • Ensuite, nous cherchons dans la direction bas-droite et trouvons (10, 11), qui est la seule coordonnée qui satisfait la condition.
  • Nous avons trouvé cinq points alignés, donc le joueur 2 gagne.

Si il n'y a pas de ligne de cinq pièces dans la direction diagonale, nous vérifions ensuite les directions verticale et horizontale. Si aucune d'entre elles ne satisfait la condition de victoire, cela signifie que le joueur actuel ne peut pas gagner et que le jeu continuera.

✨ Vérifier la solution et pratiquer

Ma pièce a été "mangée"

Je ne sais pas si quelqu'un a remarqué, mais dans notre jeu du Puissance 5, même si une position est déjà occupée, nous pouvons toujours "manger" la pièce originale lorsqu'on place la nôtre.

Cela s'explique parce que lorsque nous avons écrit la fonction playChess, nous n'avons pas vérifié la position où nous plaçons la pièce. Nous pouvons modifier notre code comme ceci :

void playChess(void)
{
	int i, j, winner;
	if (1 == whoseTurn % 2)
	{
		printf("C'est au tour du joueur 1, veuillez entrer la position, le format est numéro de ligne + espace + numéro de colonne : ");
		scanf("%d %d", &i, &j);
		//debug
		while(chessboard[i][j]!= 0)
		{
			printf("Cette position est déjà occupée, veuillez entrer la position à nouveau : ");
			scanf("%d %d",&i, &j);
		}
		//debug
		chessboard[i][j] = 1;
	}
	else
	{
		printf("C'est au tour du joueur 2, veuillez entrer la position, le format est numéro de ligne + espace + numéro de colonne : ");
		scanf("%d %d", &i, &j);
		//debug
		while(chessboard[i][j]!= 0)
		{
			printf("Cette position est déjà occupée, veuillez entrer la position à nouveau : ");
			scanf("%d %d",&i, &j);
		}
		//debug
		chessboard[i][j] = 2;
	}

	system("clear");
	printChessboard();

	if (judge(i, j))
	{
		if (1 == whoseTurn % 2)
			printf("Le gagnant est le joueur 1!\n");
		else
			printf("Le gagnant est le joueur 2!\n");
	}
}

Nous avons ajouté une boucle dans la fonction, de sorte que lorsqu'une position est déjà occupée, elle donne une invitation et demande une nouvelle entrée.

✨ Vérifier la solution et pratiquer

Pourquoi ne peux - je jamais gagner?

Lorsqu'il y a une ligne de cinq pièces et qu'il est annoncé que le "Joueur 1" ou le "Joueur 2" a gagné, puis qu'il est demandé "C'est au tour du joueur * de saisir la position de sa pièce...". N'est - ce pas frustrant? En fait, tout ce qu'il nous faut faire est d'ajouter une ligne de code!

	if (judge(i, j))
	{
		if (1 == whoseTurn % 2)
		{
			printf("Le gagnant est le joueur 1!\n");
			exit(0);	//debug
		}
		else
		{
			printf("Le gagnant est le joueur 2!\n");
			exit(0);	//debug
		}
	}
}

En plus d'annoncer le joueur gagnant après la victoire, sortir du jeu avec exit(0).

✨ Vérifier la solution et pratiquer

Compilation et exécution

Exécutez la commande gcc pour compiler :

cd ~/projet
gcc -o gomoku gomoku.c
./gomoku
Gomoku Game
✨ Vérifier la solution et pratiquer

Sommaire

Félicitations! Vous avez créé un simple jeu de Puissance 5 en utilisant le langage C. Les joueurs peuvent prendre tour à tour pour placer leurs pièces sur un plateau de 15x15, et lorsqu'un joueur a cinq pièces consécutives, le programme déclarera celui-ci le gagnant. Amusez-vous bien à jouer à ce jeu basé sur le texte avec vos amis!