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 :
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▲
- 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 :
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).
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.
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.
Compléter le programme suivant …
#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▲
#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▲
#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
(
"
\n
Votre 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
(
"
\n
Il 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▲
#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 */
}
}