TP 5 (partie 1) : Réalisation d'un Puissance 4 et Projet associé

Mettre de la couleur dans le terminal sous GNU / Linux

Puisque les cours d'IHM (Interface Homme Machine) ne commencent qu'au second semestre, nous allons voir comment nous pouvons spécifier, dans un programme, la couleur des caractères ainsi que celle du fond d'une console, mais aussi effacer son contenu.
Puisque la console est une émulation d'un terminal VT100, toutes les instructions que nous allons lui donner commencent par \033[. Ensuite, une autre séquence d'instruction, concaténée à la première, provoque l'effacement de l'écran, le changement de la couleur de la police ou du fond.

Remarque : les informations évoquées dans cette partie fonctionnent aussi sous Mac OS-X, mais pas sous Windows.

Effacer l'écran

Afin d'effacer l'écran, la seconde séquence est : H\033[2J. En conséquence, la fonction suivante permet d'effacer l'écran :

void ClearScreen ()
{
    cout << "\033[H\033[2J";
}

Copiez la, et mettez la dans votre espace de nom anonyme.

Changer la couleur

Afin de changer la couleur, la seconde séquence est : XXm, où m est le code de la couleur souhaitée. Ce code est constitué de 2 chiffres comme le montre le tableau suivant :

Couleur Code associé
0 réinitialise le système de couleur à la valeur par défaut du shell
30 Noir
31 Rouge
32 Vert
33 Jaune
34 Noir
35 Magenta
36 Cyan

Copiez le code suivant, et mettez le dans votre espace de nom anonyme :
const string KReset   ("0");
const string KNoir    ("30");
const string KRouge   ("31");
const string KVert    ("32");
const string KJaune   ("33");
const string KBleu    ("34");
const string KMAgenta ("35");
const string KCyan    ("36");
	
void Couleur (const string & coul)
{
    cout << "\033[" << coul.c_str () <<"m";
}	

Remarque : Notez la transformation de la string en NTCTS.

En conséquence, le bout de code suivant :

Couleur (KRouge);
cout << "Rouge" << endl;
Couleur (KVert);
cout << "Vert" << endl;
Couleur (KReset);
cout << "Retour à la normale" << endl;

provoquera l'affichage :

Rouge
Vert
Retour à la normale

Changer le fond

Pour changer le fond, c'est exactement la même séquence d'instructions que pour changer la couleur. La seule différence provient du fait que les couleurs associées voient leur code respectif augmenté de 10.

Pour des informations complémentaires quant à la gestion du terminal (sous GNU / Linux), vous pouvez visiter cette page.

Gestion de la grille du Puissance 4

Si vous ne savez pas ce qu'un est un Puissance 4, lisez cet article.
Nous allons représenter la grille d'un Puissance 4 par une matrice carrée de char de dimension 7 (autrement dit, nous allons représenter la grille par une matrice 7x7 dont chaque case est un char). Par souci d'uniformité, pour ce TP, le caractère :

  1. 'X' symbolise le pion du joueur 1 (la couleur est à votre guise);
  2. '0' désigne le pion du joueur 2 (la couleur est à votre guise);
  3. '.' matérialise une case vide.
Le but de cette partie est d'obtenir un affichage d'une grille de Puissance 4 similaire à celle-ci (la couleur en plus):
 .  .  .  .  .  .  .
 .  .  .  .  .  .  .
 .  .  .  .  .  .  .
 .  .  .  .  .  .  .
 .  .  .  .  .  .  .
 .  .  .  .  .  .  .
 .  .  .  .  .  .  .
--------------------
 A  B  C  D  E  F  G	

Affichage d'une ligne

Afin de spécifier une ligne du Puissance 4, nous utilisons le raccourci suivant :

typedef vector <char> CVLigne;
Travail à effectuer : écrivez le corps de la fonction AfficheLigne () de profil :
void AfficheLigne (const CVLigne & Li);
Essayez d'espacer les caractères de la ligne Li. Par exemple, chaque caractère de Li pourrait être représenté sur une largeur de 3 "cases / caractères". Pour cela, utilisez la fonction setw (incluse dans iomanip).

Affichage d'une matrice

Nous utilisons le raccourcis suivant pour représenter une matrice de char :

typedef vector <CVLigne> CVMatrice;	
Travail à effectuer : écrivez le corps de la fonction AfficheMatrice () de profil :
void AfficheMatrice (const CVMatrice & Mat);
Cette fonction doit :
  1. faire appel à la fonction ClearScreen ();
  2. remettre la couleur des caractères à sa valeur par défaut;
  3. faire appel à la fonction AfficheLigne pour chaque ligne qui la compose.

Affichage d'une grille de Puissance 4

Nous distinguons l'affichage de la grille du Puissance 4 de celle de la matrice qui la représente. En effet, dans la représentation graphique que nous utilisons, les deux dernières lignes (les traits et les lettres servant à nommer les colonnes) ne doivent être présentent que dans la grille du Puissance 4.
Travail à effectuer : écrivez le corps de la fonction AffichePuissance4 () de profil :

void AffichePuissance4 (const CVMatrice & Mat);
Cette fonction doit :
  1. faire appel à la fonction AfficheMatrice ();
  2. afficher une ligne de tirets;
  3. afficher le nom des colonnes. Faites en sorte que le nom de chaque colonne soit aligné avec la colonne qu'il représente.

Le jeu

Initialisation de la grille du Puissance 4

Ecrire la fonction InitMat () de profil :

void InitMat (CVMatrice & Mat);
Cette fonction a pour but d'initialiser toutes les cases du Puissance 4 avec le caractère '.'.

Placement d'un jeton au bon endroit

Ecrire la fonction PositionneJeton () de profil :

void PositionneJeton (CVMatrice & Mat, const unsigned NumCol, unsigned & NumLi, const bool CoupDuJoueur1);	
Cette fonction place le jeton 'X' s'il s'agit du premier joueur (ou 'O' s'il s'agit du second) au bon endroit dans la matrice représentant le Puissance 4.
Remarques :
  1. puisque la matrice est modifiée (paramètre donnée-résultat), elle est passée par référence;
  2. la position du numéro de ligne (NumLi) est à déterminer dans cette procédure. C'est donc un paramètre résultat, lui aussi passé par référence;
  3. les deux autres paramètres formels étant des paramètres données, il sont passé par valeur (type primitif), et ne sont pas modifiés (const).

L'algorithme principal

Le but de cette partie est d'écrire la fonction ppal () (Programme PrincipAL) qui gère la partie. Cette fonction a pour profil :

int ppal ()	
Dans le main (), vous devez uniquement appeler cette fonction. Cette fonction :
  1. initialise la matrice du Puissance 4;
  2. affiche la grille du puissance 4;
  3. rentre dans une boucle tant qu'on peut jouer et qu'il n'y a pas de victoire;
    1. demande la position du pion à placer;
      Attention, aucun contrôle quant à la validité de l'indice des colonnes de la grille n'est effectué.
    2. place le pion au bon endroit.
      Attention, aucun contrôle quant à la validité de l'indice des lignes de la grille n'est effectué.
    3. affiche la grille du puissance 4;
    4. effectue les tests de victoire (colonne, ligne);
  4. teste dans quel(s) état(s) on est sorti de boucle (s'il y a eu une victoire ou un match nul) et affiche les informations en conséquence.

Précision sur l'instruction "tant qu'on peut jouer" et conséquences

Puisque la grille d'un Puissance 4 contient 49 cases (7 lignes de 7 colonnes), il arrive fréquemment qu'aucun des joueurs ne prenne le dessus sur son adversaire. En conséquence, la grille est remplie et aucune victoire ne peut être prononcée.

Indications de mise en oeuvre

Pour l'instant, vous n'avez pas écrit les fonctions relatives aux tests de victoire, en conséquence, ne faites pas ces tests. En revanche, testez que vos jetons sont positionnés aux bons endroits et que vous pouvez sortir de la boucle tant qu'on peut jouer sans qu'une victoire n'ait été trouvée.

Test de victoire en colonne

Le but de cette partie est d'écrire la fonction TestVictoireColonne (). Cette fonction teste, en fonction du dernier coup joué, s'il y a 4 pions qui sont identiques et alignés sur la même colonne. En conséquence, le profil de cette fonction est le suivant :

bool TestVictoireColonne (const CVMatrice & Mat, const unsigned NumLi, const unsigned NumCol, const bool CoupDuJoueur1);		
Cette fonction renvoie true si une victoire en colonne a été détectée, false sinon.

Test de victoire en ligne

Le but de cette partie est d'écrire la fonction TestVictoireLigne (). Cette fonction teste, en fonction du dernier coup joué, s'il y a 4 pions qui sont identiques et alignés sur la même ligne. En conséquence, le profil de cette fonction est le suivant :

bool TestVictoireLigne (const CVMatrice & Mat, const unsigned NumLi, const unsigned NumCol, const bool CoupDuJoueur1);		
Cette fonction renvoie true si une victoire en ligne a été détectée, false sinon.

Le projet

Le fichier de solution est une ébauche de Puissance 4. Vous disposez d'un peu plus de 15 jours pour y ajouter toutes les fonctionnalités que vous souhaitez (sans pour autant changer de langage de programmation).

Le rendu de projet

Remarque : pour ceux qui ont des connaissances supplémentaires (celles qu'on va vous enseigner en S2), vous pouvez utiliser un EDI ainsi que des fichiers séparés, mais cet ajout ne sera pas pris en compte lors de la notation du projet. En revanche, n'envoyez pas de binaire (exécutable) : votre mail a 99,99999% de chance de ne pas être reçu par vos enseignants.

Soutenance orale

Lors de votre soutenance, vous aurez 20 minutes (maximum) pour effectuer une présentation via diaporama afin d'expliquer quels sont les apports de votre projet par rapport à la version initialement proposée. S'en suivra une discussion de 10 mn.

Pénalités

La liste de pénalités suivante n'est pas exhaustive :

  1. Projet rendu en retard : -1 pt par heure d'envoi de l'email (les emails sont horodatés);
  2. Copie sur un autre groupe ( on se savait pas comment implémenter telle ou telle fonctionnalité dont on avait besoin pour aller plus loin, on l'a donc copiée sur un autre groupe), plusieurs cas se distinguent :
    • si le groupe est clairement nommé, cette fonctionnalité ne sera pas prise en compte dans la notation;
    • si le groupe est clairement nommé, et qu'il y a une amélioration de la fonctionnalité, (note pour la fonctionnalité / 2 - seulement la moitié du travail a été réalisée);
    • 0 aux deux groupes sinon.
    Deux groupes peuvent développer la même fonctionnalité, mais ils ne doivent pas avoir la même implémentation, les mêmes jeux d'essais.