Plan du site  
pixel
pixel

Articles - Étudiants SUPINFO

Le jeu du Morpion en C++

Par Ayoub BELMAHFOUD Publié le 29/07/2017 à 14:51:40 Noter cet article:
(0 votes)
Avis favorable du comité de lecture

Introduction

Dans cet article je vais vous montrer comment développer un tictactoe ou jeu du morpion en console avec le langage C++. Cet exercice est une bonne occasion pour maitriser le langage C++ et de solidifier ses connaissances en algorithmique. Je pense que vous avez tous jouer au jeu du morpion aoins une fois dans votre vie et vous connaissez parfaitement les règles du jeu, mais je vais quand même expliquer pour les rares personnes qui découvriront ce que le TicTacToe. Alors TicTacToe connus aussi sous le nom du morpion est un jeu de réflexion qui ne nécessite qu’un papier, un crayon et deux joueurs. Le jeu évolue sur une grille (3x3), le principe est simple chaque joueur rempli à son tour une case de la grille par le symbole qui lui est attribué (X ou O), dans le but d’aligner 3 symboles identiques verticalement, horizontalement ou en diagonale. Une partie peut finir soit avec la victoire de l’un des deux joueurs soit en match nul.

Dans cette première image, on a un exemple d’une grille avant le début de la partie.

Une deuxième image montrant le déroulement de la partie.

Une dernière image concrétisant la victoire d’un des joueurs

Developpement du jeu

La grille

Le but dans cette première partie est de pouvoir afficher la grille sur laquelle pour se déroulé le jeu. La grille du jeu est composée de 3 lignes et 3colonnes ce qui nous fait un total de 9 cases, on pourra représenter cela en un tableau double dimensions de taille 3. On choisira un tableau de caractère (char) qui ne contiendra que 3 valeur possible (‘_’ si la case est vide, ‘o’ si la case a été rempli par le joueur 1 et ‘x’ si la case a été rempli par le joueur 2). A la création du tableau il faudra l’initialiser au complet avec la valeur ‘_’. Voici le code pour la création et l’initialisation de la grille :

char grille[3][3];

	for (int i(0); i < 3; i++) {
		for (int j(0); j < 3; j++) {
			grille[i][j] = '_';
		}
	}

Place à l’affichage maintenant, comme on peut le constater dans la capture d’écran au-dessus les valeurs du tableau sont séparé par un ‘|’ et par un saut de ligne après chaque 3 valeurs. Donc il suffira de faire 2boucle imbriqués qui ______ le tableau et d’afficher le contenu de la case suivi d’un ‘|’ pour les deux premières valeurs de chaque ligne et d’un saut à la ligne pour la 3éme valeur. Il faut aussi mettre en place une condition qui va afficher un espace ‘ ‘ au lieu ‘_’ à la 3éme ligne pour ne pas se retrouver avec une grille qui ressemble à ceci :

Voici le code complet de l’affichage :

void afficher(char grille[][3])
{
	for (int i(0); i < 3; i++) {
		for (int j(0); j < 3; j++) {
			if (grille[i][j] == '_' && i == 2)
				cout << " ";
			else
				cout << grille[i][j];
			if (j != 2)
				cout << "|";
			else
				cout << endl;
		}
	}
	cout << endl;
}
	

La saisie des coordonnées :

Comme le jeu est sur console et que le joueur ne pourra pas dessiner lui-même le symbole à l’endroit où il veut le programme devras faire tout ça pour lui. La manière la plus simple de faire et demander au joueur de faire entrer le numéro de la ligne et le numéro de la colonne correspondant à la case où il veut placer son symbole. Donc les valeurs possibles pour les deux variables qui seront de type entier sont 1, 2 ou 3. Après que le joueur est entré les coordonnées de la case qu’il veut jouer il faudra vérifier deux conditions. La première est que les coordonnées que le joueur a entrées sont bien comprise dans la grille et non pas en dehors. La deuxième est de vérifier si la case est vide, autrement dit si la case du tableau ne contient pas une autre valeur que le ‘_’ (rappelez-vous ce caractère indique que la case du tableau n’a pas encore été jouer). Si l’une des conditions n’est pas respecté il faudra demander aux joueurs de ressaisir les coordonnées de la case qu’il veut jouer, dans le cas contraire il conviendra de remplir la case du tableau par le symbole respectif du joueur. Voici le code pour la saisie des coordonnées ci-dessous :

	do {

		system("cls"); //Clear la console
		compteur++;
		afficher(grille);
		cout << "Tour du Joueur " << numeroJoueur << " : " << endl;
		do {
			cout << "Choisissez la ligne de la case   : ";
			cin >> ligneCase;
			cout << "Choisissez la colonne de la case : ";
			cin >> colonneCase;

		} while (!EstCordonneValide(grille,ligneCase,colonneCase));
bool EstCordonneValide(char grille[][3], int x, int y)
{
	if (x <= 3 && x >= 1 && y <= 3 && y >= 1) {
		if (grille[x - 1][y - 1] != '_')
			cout << "Case deja pleine !  " << endl << endl;
		else
			return true;
	}
	else
		cout << "Coordonees Invalide ! " << endl<< endl;

	return false;
}

Notez que la fonction « EstCordonneValide » est placé comme condition de la boucle, elle s’occupera de la vérification de la validité des coordonnées en renvoyant un Boolean à la condition de la boucle de saisie des coordonnées, c’est-à-dire soit true soit false.

Vérifier si un joueur a gagné :

Pour vérifier si un joueur a gagné après avoir joué, on mettra en place une fonction qui va vérifier si l’une des 3 lignes ou l’une des 3 colonnes ou l’une des 2 diagonales contient 3 valeur identiques différentes de ‘_’ bien sûr. Cette fonction est appelée après chaque tour d’un joueur pour vérifier si ce dernier a gagné ou pas. C’est une fonction qui renvoi un Boolean, je vous expliquerais la raison plus tard, elle retourne donc true si le joueur a gagné et false dans le cas contraire. Voici la fonction pour vérifier si un joueur a gagné ci-dessous :

bool EstPartieGagne(char grille[][3]) 
{
	if (grille[0][0] == grille[0][1] && grille[0][0] == grille[0][2] && grille[0][0] != '_')		//Ligne 1 
		return  true;
	else if (grille[1][0] == grille[1][1] && grille[1][0] == grille[1][2] && grille[1][0] != '_') //Ligne 2 
		return  true;
	else if (grille[2][0] == grille[2][1] && grille[2][0] == grille[2][2] && grille[2][0] != '_') //Ligne 3 
		return  true;
	else if (grille[0][0] == grille[1][0] && grille[0][0] == grille[2][0] && grille[0][0] != '_') // colonne 1 
		return  true;
	else if (grille[0][1] == grille[1][1] && grille[0][1] == grille[2][1] && grille[0][1] != '_')  // colonne 2
		return  true;
	else if (grille[0][2] == grille[1][2] && grille[0][2] == grille[2][2] && grille[0][2] != '_')  // colonne 3 
		return  true;
	else if (grille[0][0] == grille[1][1] && grille[0][0] == grille[2][2] && grille[0][0] != '_') // Diagonale 1 
		return  true;
	else if (grille[0][2] == grille[1][1] && grille[0][2] == grille[2][0] && grille[0][2] != '_') // Diagonale 2 
		return  true;

	return false;
}

Notez que la vérification est faite en dur et que ce n’est pas la meilleure façon de faire mais vu que y’a pas beaucoup de calculs à faire et que les machines de maintenant sont largement capable d’exécuter ça en quelque millisecondes, j’ai préféré le faire comme ça, cela va aussi vous permettre de penser à une meilleure façon de faire, je vous donnerais des pistes plus tard dans l’article.

Changement de joueur

On sait tous qu’après avoir joué c’est le tour de l’adversaire sinon le jeu serait très facile 😊. Pour représenter les joueurs j’ai utilisé une variable de type entier qui prend 2 valeur soit 1 pour représenter bien évidemment le premier joueur et 2 pour représenter … le deuxième joueur. Cette variable change de valeur après le tour de chaque joueur, elle passe a 2 si le joueur 1 a joué et passe a 1 si le joueur 2 a joué. Pour réussir à faire cette transaction pas la peine de faire de condition une ligne de code suffira pour le faire : numeroJoueur = numeroJoueur % 2 + 1; Je vous laisse comprendre tout seul la logique de cette ligne de code. 5 La boucle du jeu La boucle du jeu est la principale boucle qui va représenter le déroulement de la partie cette boucle ne s’arrête qu’a deux conditions : La première est que l’un des deux joueurs a gagné, cette condition sera vérifiée grâce à la fonction « EstPartieGagne » cité avant. La deuxième est qu’il n’y plus de coups à jouer et que la partie se solde par un match nul, cette condition sera vérifiée a l’aide d’un compteur qu’on mettre en place et qui vaut 0 et qui s’incrémentera de 1 à chaque fois qu’un joueur joue, arrivé à 9 la partie est terminée. A la fin du jeu on indique le vainqueur de la partie ou si la partie s’est terminé à égalité. Ci-dessous les 3 cas possibles :

Voici le code complet du jeu :

// TicTacToe.cpp : définit le point d'entrée pour l'application console.
//

#include "stdafx.h"
#include <iostream>
using namespace std;

void afficher(char grille[][3]);
bool EstCordonneValide(char grille[][3] , int x , int y);
bool EstPartieGagne(char grille[][3]);

int main()
{
	int numeroJoueur = 1;
	int ligneCase = 0;
	int colonneCase = 0;
	int compteur = 0;

	char grille[3][3];

	for (int i(0); i < 3; i++) {
		for (int j(0); j < 3; j++) {
			grille[i][j] = '_';
		}
	}

	do {

		system("cls"); //Clear la console
		compteur++;
		afficher(grille);
		cout << "Tour du Joueur " << numeroJoueur << " : " << endl;
		do {
			cout << "Choisissez la ligne de la case   : ";
			cin >> ligneCase;
			cout << "Choisissez la colonne de la case : ";
			cin >> colonneCase;

		} while (!EstCordonneValide(grille,ligneCase,colonneCase));

		if (numeroJoueur == 1)
			grille[ligneCase-1][colonneCase-1] = 'x';
		else
			grille[ligneCase-1][colonneCase-1] = 'o';
		

		numeroJoueur = numeroJoueur % 2 + 1;

		
	} while (!EstPartieGagne(grille) && compteur != 9);
	system("cls");

	afficher(grille);

	numeroJoueur = numeroJoueur % 2 + 1;
	if(EstPartieGagne(grille))
		cout << "Le Joueur " << numeroJoueur << " a gagne la partie " << endl << endl;
	else
		cout << "La partie s'est termine a egalite !" << endl <<endl ;
	
	

    return 0;
}

void afficher(char grille[][3])
{
	for (int i(0); i < 3; i++) {
		for (int j(0); j < 3; j++) {
			if (grille[i][j] == '_' && i == 2)
				cout << " ";
			else
				cout << grille[i][j];
			if (j != 2)
				cout << "|";
			else
				cout << endl;
		}
	}
	cout << endl;
}

bool EstCordonneValide(char grille[][3], int x, int y)
{
	if (x <= 3 && x >= 1 && y <= 3 && y >= 1) {
		if (grille[x - 1][y - 1] != '_')
			cout << "Case deja pleine !  " << endl << endl;
		else
			return true;
	}
	else
		cout << "Coordonees Invalide ! " << endl<< endl;

	return false;
}

bool EstPartieGagne(char grille[][3]) 
{
	if (grille[0][0] == grille[0][1] && grille[0][0] == grille[0][2] && grille[0][0] != '_')		//Ligne 1 
		return  true;
	else if (grille[1][0] == grille[1][1] && grille[1][0] == grille[1][2] && grille[1][0] != '_') //Ligne 2 
		return  true;
	else if (grille[2][0] == grille[2][1] && grille[2][0] == grille[2][2] && grille[2][0] != '_') //Ligne 3 
		return  true;
	else if (grille[0][0] == grille[1][0] && grille[0][0] == grille[2][0] && grille[0][0] != '_') // colonne 1 
		return  true;
	else if (grille[0][1] == grille[1][1] && grille[0][1] == grille[2][1] && grille[0][1] != '_')  // colonne 2
		return  true;
	else if (grille[0][2] == grille[1][2] && grille[0][2] == grille[2][2] && grille[0][2] != '_')  // colonne 3 
		return  true;
	else if (grille[0][0] == grille[1][1] && grille[0][0] == grille[2][2] && grille[0][0] != '_') // Diagonale 1 
		return  true;
	else if (grille[0][2] == grille[1][1] && grille[0][2] == grille[2][0] && grille[0][2] != '_') // Diagonale 2 
		return  true;

	return false;
}

Améliorations possibles

Comme je vous l’ai indiqué avant on peut améliorer ce code pour le rendre plus propre. Je vous citerais ici quelques améliorations possibles : Si vous essayez de rentré un caractère au lieu d’un entier le programme va crasher ou aura un comportement inattendu, essayer de trouver une solution pour contourner ce problème. Comme cité précédemment essayer de trouver d’autre algorithmes pour vérifier si un joueur a gagné, astuce : vérifier qu’a partir du dernier coup joué. La possibilité de rejouer la partie et que ça soit l’autre joueur qui commence cette fois ci. Voici de quoi vous occupez un petit bout de temps afin de rendre le programme complet. Amusez-vous bien 😉 !

Conclusion

Le jeu du morpion est un bon exercice pour mettre en pratiques ses connaissance en algorithmique et en programmation. J’espère que cet article vous a plus et à la prochaine pour un autre jeu en console peut être 😃.

A propos de SUPINFO | Contacts & adresses | Enseigner à SUPINFO | Presse | Conditions d'utilisation & Copyright | Respect de la vie privée | Investir
Logo de la société Cisco, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société IBM, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sun-Oracle, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Apple, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Sybase, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Novell, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Intel, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Accenture, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société SAP, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Prometric, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo de la société Toeic, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management Logo du IT Academy Program par Microsoft, partenaire pédagogique de SUPINFO, la Grande École de l'informatique, du numérique et du management

SUPINFO International University
Ecole d'Informatique - IT School
École Supérieure d'Informatique de Paris, leader en France
La Grande Ecole de l'informatique, du numérique et du management
Fondée en 1965, reconnue par l'État. Titre Bac+5 certifié au niveau I.
SUPINFO International University is globally operated by EDUCINVEST Belgium - Avenue Louise, 534 - 1050 Brussels