Le C en 20 heures


précédentsommairesuivant

XVII. Exercices

XVII-A. Objectifs

Ces quelques exercices avec corrigés vous permettront de vous familiariser un peu plus avec le langage C. Dans tous ces exercices, on supposera que l'utilisateur ne fait pas d'erreur de saisie.

XVII-B. Jeu de morpion

XVII-B-1. Principe

Il s'agit du morpion classique que l'on pourrait représenter comme ceci :

 
Sélectionnez
X O .
X O X
O . O

Le gagnant est celui qui aligne le premier 3 signes identiques (3 X ou 3 O), sur l'horizontale, la verticale ou la diagonale.

XVII-B-2. Affichage du plateau de jeu

Nous allons définir un tableau pour composer le plateau du morpion et l'initialiser à 0.

Nous dirons qu'une case du plateau de jeu est vide si la case du tableau correspondante contient la valeur 0.

  • Écrivez une fonction qui dessine ce plateau.
  • Écrivez un programme qui dessine le plateau vide, puis avec les éventuels « O » ou « X ».

XVII-B-3. Saisie des coordonnées

  • Écrivez une fonction qui permet la saisie d'une coordonnée.
  • Dans un premier temps on ne contrôlera que si la coordonnée est comprise entre 1 et 3.
  • Complétez le programme en permettant la saisie des deux coordonnées X et Y.
  • Complétez le programme en affichant la grille résultante de la saisie de ces coordonnées (on ne contrôlera pas le fait que la case soit occupée ou non).
  • Complétez le programme en testant si la case n'est pas déjà occupée.

XVII-B-4. Alternance des joueurs

Modifiez le programme pour que celui-ci fasse jouer deux joueurs :
  • on positionnera la valeur de la case du tableau à 1 pour le joueur 1 et à 2 pour le joueur 2,
  • on ne regardera pas qui a gagné dans l'immédiat,
  • on affichera 0 pour le joueur 1 et X pour le joueur 2.

XVII-B-5. Fin du jeu

  • Modifiez le programme pour que celui‐ci s'arrête lorsque toutes les cases sont occupées.
  • Modifiez le programme pour que celui‐ci s'arrête lorsque l'un des deux joueurs a gagné ou lorsque toutes les cases sont occupées.

XVII-B-6. Améliorations possibles

Faites en sorte que l'ordinateur joue en tant que joueur 2 :

  • dans un premier temps de manière aléatoire en testant la possibilité de poser son pion (9 cases) ;
  • dans un second temps en pondérant les différentes cases du plateau (le centre est la case la plus forte, le coin vient ensuite…)

XVII-C. Jeu de pendu

XVII-C-1. Principe

Le but du jeu est de deviner en moins de 7 essais un mot que seul l'ordinateur connaît. Pour mener à bien votre mission, vous allez proposer une lettre :

  • si la lettre est correcte alors, celle‐ci s'affiche à sa place dans le mot à deviner ;
  • si la lettre est incorrecte, alors, votre nombre d'essais diminue de 1.

Autrement dit :

  • lorsqu'une lettre est correcte, le nombre d'essais reste inchangé ;
  • lorsqu'une lettre est incorrecte, le nombre d'essais diminue de 1 ;
  • lorsque tout le mot a été deviné, vous avez gagné ;
  • lorsque le nombre d'essais est à zéro (0), vous avez perdu.

XVII-C-2. Exemple

Supposons que le mot à deviner soit « bonjour ».

Vous proposez la lettre « o », cette dernière se trouve dans le mot, l'ordinateur affiche donc *o**o**. Si vous proposez ensuite la lettre « u », l'ordinateur affiche : *o**ou*.

Si vous vous sentez à l'aise, ne lisez pas ce qui suit et essayez de programmer le jeu. Dans le cas contraire, le détail des différentes étapes vous aidera sans doute à réaliser le programme.

XVII-C-3. Un peu d'aide

XVII-C-3-a. Point de départ

Commencez par écrire un programme qui déclare une variable contenant le mot à trouver : motAtrouver et une autre contenant une chaine de même longueur remplie avec des * : motCherche.

XVII-C-3-b. Algorithme

Un tour de jeu se compose des phases suivantes :

 
Sélectionnez
Saisie d'un caractère
Initialisation des caractères correspondant dans le mot caché
Si aucun caractère n'a été trouvé
    nombre d'essais -1
Si motAtrouver == motCherche GAGNE
Si nombre d'essais == 0 PERDU

XVII-C-4. Améliorations possibles

Libre à vous d'ajouter ce que vous voulez. Voici quelques suggestions :

  • lire le mot dans un dictionnaire de mots.
  • sauvegarder/recharger une partie en cours.
  • gérer les meilleurs scores au moyen d'un fichier.
  • dessiner une potence, mettre un peu de couleur.

XVII-D. Balle rebondissante

On souhaite réaliser un programme qui permettrait de faire rebondir une balle sur les bords de l'écran. La balle doit pouvoir rebondir sur un écran de la forme suivante (figure de gauche) :

Afin de faciliter la programmation, on rajoute une couronne d'étoiles qui permettra de simplifier les tests lorsque la balle arrivera sur un bord (figure de droite). 

Image non disponible
Figure 15.1 - Balle rebondissante

La balle, qui est symbolisée par le caractère 'O' démarre à la position [4;4]. Elle part suivant le vecteur d'abscisse +1 et d'ordonnée +1.

Lorsqu'elle arrive sur un bord vertical, il suffit d'inverser le sens de déplacement selon l'axe des ordonnées. De même, si la balle arrive sur un bord horizontal, on inverse le sens du déplacement selon l'axe des abscisses.

Pour tester si on arrive sur un bord, il est possible de faire :
 
Sélectionnez
if (grille[nouvelle_pos_x][nouvelle_pos_y]=='*')

Naturellement il est aussi possible de tester les coordonnées nouvelle_pos_x et nouvelle_pos_y pour savoir si on arrive sur un bord.

Image non disponible Compléter le programme suivant …

 
Sélectionnez
#include <stdio.h>
#include <string.h>
/************PROTOTYPES DES FONCTIONS ***************************/
/* Initialise la grille de façon à ce qu'elle contienne ce qu'il 
   y a à la figure de droite 
*/
void init_grille (char grille[][10],int pos_balle_x,int pos_balle_y);
/* Affiche le rectangle d'étoiles et la balle (tout ceci en même
   temps et non pas le rectangle puis la balle...) 
*/
void affiche_grille (char grille[][10]); /* 10 lignes 10 colonnes */
/* Calcule la nouvelle position de la balle en fonction de 
   l'ancienne position de la balle (old_pos_balle_x, old_pos_balle_y) 
   et du vecteur de déplacement (deplacement_x, deplacement_y).
*/
void calcule_position_balle (char grille[][10], int *pos_balle_x, 
                            int *pos_balle_y, int *deplacement_x, int *deplacement_y);
/*************  IMPLEMENTATION DES FONCTIONS ****************/
void init_grille (char grille[][10], int pos_balle_x,int pos_balle_y) {...}
void affiche_grille (char grille[][10]) {...}
void calcule_position_balle (char grille[][10], int *pos_balle_x, 
                            int *pos_balle_y,int *deplacement_x,int *deplacement_y); {...}
int main () {
   int pos_balle_x=4, pos_balle_y=4;     /* position  balle au départ  */
   int deplacement_x=1, deplacement_y=1; /* déplacement balle  */
   char grille[10][10]; /* grille qui contiendra 3 caractères : */
                         /* '*' ou 'O' ou le caractère espace ' '*/
   init_grille (grille, pos_balle_x, pos_balle_y);
   while (1) {
      system("clear");
      affiche_grille(grille);
      calcule_position_balle (grille, &pos_balle_x, &pos_balle_y, 
                             &deplacement_x, &deplacement_y);
      usleep(500000);  /* Pause de 500 000 micro secondes donc 1/2 seconde */
   }
}

XVII-D-1. Améliorations

Comme on peut le constater, le mouvement de la balle est cyclique, introduisez un déplacement aléatoire de 1 case tous les x tours où x est un nombre aléatoire entre 0 et 9.

XVII-E. Solutions

XVII-E-1. Le morpion

 
Sélectionnez
#include <stdio.h>
#include <string.h>
#define TRUE  1
#define FALSE 0
void dessine_plateau (int plateau[][3]) {
   int i=0,j=0;
   printf ("\n-------\n");
   for (i=0;i<3;i++) {
      for (j=0;j<3;j++) {
         printf("|");
         switch(plateau[i][j]) {
            case 0:
               printf(" ");
               break;
            case 1:
               printf("O");
               break;
            case 2:
               printf("X");
               break;
         }
      }
      printf ("|\n");
      printf ("-------\n");
   }
}
int fin_jeu (int plateau[][3]) {
   int i=0,j=0;
   for (i=0;i<3;i++) {
      for (j=0;j<3;j++) {
         if (plateau [i][j]==0) {
            return FALSE;
         }
      }
   }
   return TRUE;
}
int saisie_donnee (char *invite) {
   int valeur;
   do {
      printf ("%s", invite);
      scanf ("%d",&valeur);
   } while (( valeur <1) || (valeur >3));
   return (valeur);
}
int gagne (int plateau[][3]) {
   int i=0;
   // Test sur les lignes
   for ( i=0; i<3; i++) {
      if (( plateau[i][0] >0) && ( plateau[i][0] == plateau[i][1] ) && ( plateau[i][1] == plateau[i][2] )) {
         puts ("GAGNE");
         return TRUE;
      }
   }
   // Test sur les colonnes
   for ( i=0; i<3; i++) {
      if (( plateau[0][i] >0) && ( plateau[0][i] == plateau[1][i] ) && ( plateau[1][i] == plateau[2][i] )) {
         puts ("GAGNE");
         return TRUE;
      }
   }
   // Test sur les diagonales
   if (( plateau[0][0] >0) && ( plateau[0][0] == plateau[1][1] ) && ( plateau[1][1] == plateau[2][2] )) {
      puts ("GAGNE");
      return TRUE;
   }
   // Test sur les diagonales
   if (( plateau[0][2] >0) && ( plateau[0][2] == plateau[1][1] ) && ( plateau[1][1] == plateau[2][0] )) {
      puts ("GAGNE");
      return TRUE;
   }
   return FALSE;
}
void jeu (int plateau[][3], int joueur) {
   int pos_x=0,pos_y=0;
   int correct=FALSE;
   do {
      printf ("Joueur %d\n",joueur);
      pos_x= saisie_donnee ("Ligne : ");
      pos_y= saisie_donnee ("Colonne : ");
      if ( plateau[pos_x-1][pos_y-1]>0 ) {
         printf ("Case occupée !\n");
      } else {
         plateau[pos_x-1][pos_y-1]=joueur;
         correct=TRUE;
      }
   }
   while (! correct);
   dessine_plateau (plateau);
}
int main () {
   int plateau [3][3];
   int joueur=1;
   // la fonction memset permet d'initialiser chacun
   // des octets d'une zone donnée avec une valeur
   // déterminée (ici: 0)
   memset (plateau, 0, 9*sizeof (int));
   dessine_plateau (plateau);
   do {
      jeu (plateau, joueur);
      if ( joueur==1 ) {
         joueur=2;
      } else {
         joueur=1;
      }
   }
   while (( !gagne (plateau)) && (!fin_jeu (plateau)) );
   return 0;
}

XVII-E-2. Le pendu

 
Sélectionnez
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
char lireCaractere() {
   char chaine[2]; 
   gets(chaine);
   return chaine[0];
}
int main() {
   int i=0;
   int coups=7;
   char motAtrouver[]="BONJOUR";
   char lettreSaisie=' ';
   int lettre_trouvee=FALSE;
   char gagne=FALSE;
   char* motCherche;
   motCherche=malloc (sizeof (motAtrouver));
   memset (motCherche,'*',sizeof (motAtrouver));
   motCherche[sizeof (motAtrouver)-1]=0;
   printf("Jeu de pendu \n");
   do {
      // Aucune lettre trouvée
      lettre_trouvee=FALSE;
      // Saisie d'une lettre et mise en majuscule
      printf("\nVotre lettre : ");
      lettreSaisie=lireCaractere();
      // Comparaison avec le mot secret
      for(i=0; i<strlen (motAtrouver); i++) {
         if(lettreSaisie==motAtrouver[i]) {
            motCherche[i]=lettreSaisie;
            lettre_trouvee=TRUE;
         }
      }
      printf("%s", motCherche); //on affiche le mot cache
      if (!lettre_trouvee) {
         coups--;
      }
      printf("\nIl vous reste %d coups.\n ", coups );
      gagne=! strcmp(motAtrouver, motCherche);
   }
   while(!gagne && coups>0);
   if ( gagne )
      puts ("GAGNE");
   else
      puts ("PERDU");
   getchar();
   free (motCherche);
   return 0;
}

XVII-E-3. Balle rebondissante

 
Sélectionnez
#include <stdio.h>
#include <string.h>
/************PROTOTYPES DES FONCTIONS ***************************/
/* Initialise la grille de façon à ce qu'elle contienne ce qu'il 
   y a à la figure de droite 
*/
void init_grille (char grille[][10],int pos_balle_x,int pos_balle_y);
/* Affiche le rectangle d'étoiles et la balle (tout ceci en même
   temps et non pas le rectangle puis la balle...) 
*/
void affiche_grille (char grille[][10]); /* 10 lignes 10 colonnes */
/* Calcule la nouvelle position de la balle en fonction de 
   l'ancienne position de la balle (old_pos_balle_x, old_pos_balle_y) 
   et du vecteur de déplacement (deplacement_x, deplacement_y).
*/
void  calcule_position_balle (char grille[][10], int *pos_balle_x, 
                             int *pos_balle_y, int *deplacement_x, int *deplacement_y);
/***************** IMPLEMENTATION ******************************/
void init_grille(char grille[][10],int pos_balle_x,int pos_balle_y){
   int ligne, colonne;
   memset (grille,' ',100);
   for (colonne=0; colonne <10; colonne++) {
      grille [0][colonne]='*';
      grille [9][colonne]='*';
   }
   for (ligne=0; ligne<10; ligne++) {
      grille [ligne][0]='*';
      grille [ligne][9]='*';
   }
   grille [pos_balle_x][pos_balle_y]='O';
}
void affiche_grille (char grille[][10]) {
   int ligne, colonne;
   for (ligne=0; ligne<10; ligne++ ) {
      for (colonne=0; colonne <10; colonne++) {
         printf ("%c",grille[ligne][colonne]);
      }
      printf ("\n");
   }
}
void  calcule_position_balle (char grille[][10], int *pos_balle_x, 
                             int *pos_balle_y,int *deplacement_x,int *deplacement_y) {
   int theo_pos_x=0;
   int theo_pos_y=0;
   // On efface l'ancienne balle
   grille[*pos_balle_x][*pos_balle_y]=' ';
   printf ("Position actuelle : %d / %d\n",*pos_balle_x,*pos_balle_y);
   printf ("Déplacement : %d / %d\n",*deplacement_x,*deplacement_y);
   // On calcule la future position théorique de la balle
   theo_pos_x = *pos_balle_x + *deplacement_x;
   theo_pos_y = *pos_balle_y + *deplacement_y;
   // En fonction de la position théorique de la balle 
   // on modifie les vecteurs de déplacement
   if (grille[theo_pos_x][theo_pos_y]=='*') {
      // Si on tape sur l'axe vertical
      if (( theo_pos_x == 0 ) || ( theo_pos_x == 9 ))
         *deplacement_x = - *deplacement_x;
      // Si on tape sur l'axe horizontal
      if (( theo_pos_y == 0 ) || ( theo_pos_y == 9 ))
         *deplacement_y = - *deplacement_y;
   }
   // On calcule la nouvelle position de la balle
   *pos_balle_x += *deplacement_x;
   *pos_balle_y += *deplacement_y;
   printf ("Nouvelle Pos : %d/%d\n",*pos_balle_x,*pos_balle_y);
   // On met la balle dans la grille
   grille[*pos_balle_x][*pos_balle_y]='O';
}
int main () {
   int pos_balle_x=4, pos_balle_y=4;     /* position  balle au départ  */
   int deplacement_x=1, deplacement_y=1; /* déplacement balle  */
   char grille[10][10]; /* grille qui contiendra 3 caractères : */
                         /* '*' ou 'O' ou le caractère espace ' '*/
   init_grille (grille, pos_balle_x, pos_balle_y);
   while (1)  {
      system("clear");
      affiche_grille(grille);
      calcule_position_balle (grille, &pos_balle_x, &pos_balle_y, &deplacement_x, &deplacement_y);
      usleep(500000);  /* Pause de 500 000 micro secondes donc 1/2 seconde */
   }
}

précédentsommairesuivant

  

Licence Creative Commons
Le contenu de cet article est rédigé par Eric Berthomier et Daniel Schang et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.