Guillaume Rivière 2012 – 2024

Le logo de la CCI Bayonne Pays Basque

Programmation Procédurale en langage C

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 WIDTH 30
#define HEIGHT 10

Ensuite continuez d'écrire le programme, en déclarant une matrice de caractères (char) dans la fonction main() comme suit :

char grille1[WIDTH][HEIGHT] ;
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 :

void initialiser (char m[WIDTH][HEIGHT]) ;

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 :

void afficher (char m[WIDTH][HEIGHT]) ;

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

Capture affichage ABCD
Figure 1.4.1
Question 1.5 : Affichage d'une courbe

Nous allons essayer d'afficher modestement la sinusoïdale y = 3 + 3 * sin (x).

  1. Après le premier affichage de la grille, appelez de nouveau la fonction d'initialisation (écrite précédemment) pour réinitialiser la grille.
  2. Puis, en faisant varier un indice x de 0 à WIDTH-1, affectez les cases [x][3+3*sin(x)] avec le caractère minuscule 'o'
  3. Enfin, demandez à nouveau d'afficher la grille, en utilisant la fonction d'affichage (écrite précédemment).
Capture affichage courbe
Figure 1.5.1

Exercice 2 • Lecture d'un fichier de coordonnées et affichage sur une grille

ATTENTION 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 :

  1. Initialisation de la grille
  2. Ouverture en lecture du fichier coordonnees.txt
  3. Lecture des coordonnées dans le fichier et affectation de la grille avec la lettre associée au point
  4. Fermeture du fichier
  5. Affichage de la grille
Capture affichage coordonnées
Figure 2.1

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

ATTENTION 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 :

typedef struct robot {
  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 :

#ifndef DIMENSIONS_H
#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 :

  1. 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 recopier name dans bot->nom). Elle initialise le descripteur bot->instructions du robot en ouvrant le fichier de nom filename avec fopen(). En cas d'échec de l'ouverture du fichier, alors le programme sera stoppé.
  2. La fonction de destruction du robot referme le descripteur de fichier bot->instructions du robot passé en paramètre en appelant la fonction fclose().
  3. Les deux fonctions « get » retournent la valeur de la position du robot (bot->posX ou bot->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).
  4. La fonction qui permet de faire avancer le robot lit avec fscanf() la prochaine instruction à effectuer grâce au descripteur de fichier bot->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 fonction feof(). Si la fin de fichier est atteinte, alors la fonction qui devait faire avancer le robot ne fait rien et retourne 0. 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 retourne 1.
  5. 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 :

Capture robot simple
Figure 3.4.1

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