TP3 - Cas d'étude : Robot traceur (1, 2, 3) - Partie 1
Exercice 1 • Afficher et dessiner sur une grille
Le but de cet exercice est d'écrire un petit programme qui affiche une grille de lettres.
Question 1.1 : Structure de données
La grille sera représentée par une matrice de caractères de taille WIDTH
x HEIGHT
.
Créez un nouveau fichier exo1.c
qui contiendra votre programme. Au début du fichier, commencez par définir les deux macro-constantes qui détermineront de la grille :
#define HEIGHT 10
Ensuite continuez d'écrire le programme, en déclarant une matrice de caractères (char
) dans la fonction main()
comme suit :
Question 1.2 : Initialisation
Écrivez une fonction qui prendra en paramètre une matrice de caractères de taille WIDTH
x HEIGHT
et qui initialise les cases de la matrice avec le caractère tiret '-'
. Voici son prototype :
Appelez cette fonction pour initialiser la grille qui est déclarée dans la fonction main()
.
Pour accéder et par exemple modifier la case [0][0] de la matrice m et lui affecter la lettre A, il faut écrire :
m[0][0] = 'A';
Question 1.3 : Fonction d'affichage
Écrivez une fonction qui prendra en paramètre une matrice de taille WIDTH
x HEIGHT
et qui affichera cette matrice avec un espace entre chaque caractère. Voici son prototype :
Appelez cette fonction pour afficher, après qu'elle fut initialisée, la grille qui est déclarée dans la fonction main()
.
Attention à l'ordre de parcours des lignes et des colonnes et à l'ordre d'imbrication des deux boucles for
Question 1.4 : Modification de cases
Avant que la grille ne soit affichée, mais après qu'elle fut initialisée, modifiez quatre cases de la grille :
Mettez 'A'
dans la case [1][1]
Mettez 'B'
dans la case [5][1]
Mettez 'C'
dans la case [1][5]
Mettez 'D'
dans la case [5][5]
Vérifiez que vous obtenez l'affichage suivant, sinon c'est que la fonction d'affichage écrite précédemment ne parcours pas lignes et colonnes dans le bon ordre pour afficher
Question 1.5 : Affichage d'une courbe
Nous allons essayer d'afficher modestement la sinusoïdale y = 3 + 3 * sin (x)
.
- Après le premier affichage de la grille, appelez de nouveau la fonction d'initialisation (écrite précédemment) pour réinitialiser la grille.
- Puis, en faisant varier un indice
x
de0
àWIDTH-1
, affectez les cases[x][3+3*sin(x)]
avec le caractère minuscule'o'
- Enfin, demandez à nouveau d'afficher la grille, en utilisant la fonction d'affichage (écrite précédemment).
Exercice 2 • Lecture d'un fichier de coordonnées et affichage sur une grille
L'utilisation des fonctions fopen()
, feof()
, fscanf()
et fclose()
pour la lecture de fichiers a été expliquée et illustrée dans la partie 4 du cours. Reprenez l'exemple de l'annuaire pour inspirer pour la lecture de fichier.
Le fichier coordonnees.txt décrit une liste de points. Chaque ligne est constituée de l'abscisse du point, suivit de l'ordonnée du point, suivit du caractère correspondant à ce point. Vous devez écrire un programme qui affiche les points de ce fichier sur une grille.
Commencez par reprendre le programme de l'exercice précédent exo1.c
en le copiant dans un nouveau fichier exo2.c
.
Modifier le programme pour qu'il procède aux étapes suivantes :
- Initialisation de la grille
- Ouverture en lecture du fichier coordonnees.txt
- Lecture des coordonnées dans le fichier et affectation de la grille avec la lettre associée au point
- Fermeture du fichier
- Affichage de la grille
Pour observer étape par étape les nouveaux points sur la grille, vous pouvez demander l'affichage de la grille après chaque lecture dans le fichier. La lecture du fichier étant très rapide, le défilement rend le résultat illisible. Pour avoir le temps d'observer ce qu'il se passe, faîtes un appel scanf("%*c");
après chaque affichage de la grille. Ainsi, le programme attendra qu'une touche soit appuyée pour continuer. Enfin, pour un affichage encore plus agréable, vous pouvez faire un appel à system("cls");
avant l'affichage de la grille (ou system("clear");
sous Linux).
Exercice 3 • Paquetage Robot
Comme cela a été fait dans le cours, pour un paquetage de géométrie (geometrie.h
et geometrie.c
), le but de cet exercice est de créer des paquetages. Appuyez-vous donc sur l'exemple du paquetage géométrie du cours dans la partie 9 pour comprendre ce qui vous est demandé dans cet exercice.
Maintenant que l'affichage de grilles fonctionne, nous allons le laisser de côté pour plus tard et nous concentrer sur le robot. Le but de cet exercice est de créer un paquetage « Robot », qui permet de représenter des robots qui se déplacent, verticalement ou horizontalement, sur un plan, selon des suites d'instructions de déplacements relatifs à la position courante provenant d'un fichier (avancer à gauche, à droite, en bas ou en haut).
Question 3.1 : Le fichier d'entête robot.h
Vous allez créer un fichier appelé robot.h
qui contiendra la définition de la structure de donnée Robot et les prototypes des fonctions pour manipuler cette structure. Un robot sera composé de sa position, de son nom et d'un fichier d'instructions :
int posX ;
int posY ;
char nom[256] ;
FILE *instructions ;
} Robot ;
Les prototypes des six fonctions de manipulation du robot seront les suivants :
void robot_initialiser (Robot *bot, int x, int y, char *name, char *filename) ;void robot_detruire (Robot *bot) ;
int robot_get_positionX (Robot *bot) ;
int robot_get_positionY (Robot *bot) ;
char robot_avancer (Robot *bot) ;
void robot_afficher (Robot *bot) ;
Attention de ne pas oublier les instructions préprocesseur #ifndef ROBOT_H
et #define ROBOT_H
au début du fichier et #endif
à la fin du fichier (comme fait dans l'exemple du paquetage de géométrie).
Question 3.2 : Le fichier dimensions.h
Pour définir les limites de déplacement du robot, les deux macro-constantes WIDTH
et HEIGHT
vont être définies dans le fichier dimensions.h
comme suit :
#define DIMENSIONS_H
#define WIDTH 30
#define HEIGHT 10
#endif /* DIMENSIONS_H */
Question 3.3 : Le fichier d'implantation robot.c
Créez le nouveau fichier robot.c
. Commencez par inclure le fichier d'entête au début de ce fichier en faisant #include "robot.h"
, ainsi que le fichier définissant les dimensions en faisant #include "dimensions.h"
Maintenant vous pouvez écrire le code des six fonctions :
- La fonction d'initialisation initialise la structure robot passée en paramètre avec la position et le nom donnés en paramètre (utiliser
strcpy()
pour recopiername
dansbot->nom
). Elle initialise le descripteurbot->instructions
du robot en ouvrant le fichier de nomfilename
avecfopen()
. En cas d'échec de l'ouverture du fichier, alors le programme sera stoppé. - La fonction de destruction du robot referme le descripteur de fichier
bot->instructions
du robot passé en paramètre en appelant la fonctionfclose()
. - Les deux fonctions « get » retournent la valeur de la position du robot (
bot->posX
oubot->posY
) passé en paramètre. En programmation ce type de fonction permettant d'accéder aux champs d'une structure s'appelle un « accesseur ». Cela fait partie des principes de bonne programmation (voir partie 11 du cours). - La fonction qui permet de faire avancer le robot lit avec
fscanf()
la prochaine instruction à effectuer grâce au descripteur de fichierbot->instructions
. Le caractère qui est lu détermine la direction dans laquelle le robot doit avancer (G, D, B ou H), comme par exemple le fichier instructionsE.txt. Attention que la position du robot reste dans les limites [0..WIDTH-1 ; 0..HEIGHT-1]. Enfin, pour que tout fonctionne bien, avant d'essayer de lire dans le fichier il faut commencer par tester si la fin de fichier n'a pas été atteinte avec la fonctionfeof()
. Si la fin de fichier est atteinte, alors la fonction qui devait faire avancer le robot ne fait rien et retourne0
. Par contre, si la fin de fichier n'est pas encore atteinte, alors la fonction fait effectivement ce qui a été décrit avant (lire d'un caractère et faire avancer le robot) et retourne1
. - La fonction qui permet d'afficher le robot affiche simplement avec un
printf()
le nom du robot entre deux crochets, puis sa position entre parenthèses, et provoque un retour à la ligne.
Malgré qu'un paquetage ne contienne pas de fonction main()
, il est tout de même possible d'essayer de le compiler :
gcc -c -Wall -ansi robot.c
Par contre, aucun exécutable ne sera créé. Si aucune erreur ne fait échouer compilation, un « fichier cible » robot.o
, contenant le code machine, va être généré. Ce principe s'appelle la « compilation séparée ».
Question 3.4 : Le programme principal
Vous allez maintenant créer le fichier exo3.c
qui contiendra la fonction main()
. Au début de ce fichier vous devrez inclure le fichier d'entête robot.h
. Dans ce programme, vous allez déclarer une variable bot1
de type robot. Ce robot sera initialisé pour s'appeler « Ewall », sa position de départ sera (4;2) et le nom de son fichier d'instructions sera "instructionsE.txt". Ensuite, ce robot sera affiché avec la fonction d'affichage prévue à cet effet dans le paquetage. Puis, dans une boucle do { ... } while ()
, la fonction pour faire avancer le robot sera appelée jusqu'à ce que le robot n'avance plus. À chaque fois que le robot avance il sera affiché grâce à la fonction d'affichage. Enfin, avant la fin du programme, ne pas oublier de détruire le robot bot1
en appelant la fonction de destruction de robots.
Comme précédemment, le principe de la compilation séparée permet de compiler le fichier exo3.c
indépendamment du paquetage :
gcc -c -Wall -ansi exo3.c
Si la compilation aboutie, un fichier cible exo3.c
va être créé, mais pas encore d'exécutable. Pour générer le fichier exécutable, il faut alors assembler les deux fichiers cibles avec cette commande :
gcc -Wall exo3.o robot.o -o exo3.exe
Bien entendu, avant de lancer l'exécution, vous devrez télécharger le fichier instructionsE.txt et le placer dans le même répertoire que votre programme. Voici ce que devrait afficher le programme lors de l'exécution :
Plutôt que de compiler séparément exo3.c
et robot.c
, il est possible de tout compiler en une seule fois avec cette commande :
gcc -Wall -ansi exo3.c robot.c -o exo3.exe