Programmation C++ : TP séance 01
Rendu du TP
Pour rendre votre travail :
-
Créez un répertoire
progcpp-TPxx-NOM1-NOM2
, en replaçantxx
par le numéro de la séance,NOM1
par votre nom de famille,NOM2
par le nom de famille de votre binôme oumono
si vous êtes seul(e). Il ne doit y avoir aucun espace ou apostrophe dans le nom du répertoire. -
Recopiez tous vos fichiers sources dans ce répertoire, ainsi que le
Makefile
éventuel, mais pas les fichiers compilés !Dans chaque fichier il doit y avoir au début en commentaire : vos NOMS Prénoms ainsi que ceux de votre binôme éventuel.
-
Compressez le répertoire sous la forme d'une archive au format
tgz
puis téléversez l'archive sur la page Ametice, même si vous n'avez pas fini la planche de TP.
Dans le cas où le TP n'est achevé, il vous est demandé de le terminer chez vous, puis de re-téléverser l'archive dans sa version finale, sans changer son nom, avant le début de la séance suivante.
Compresser le répertoire
Pour compresser le répertoire, vous pouvez faire clic droit / compresser dans le gestionnaire de fichier, ou taper dans le terminal :
(cd .. && tar cvfz progcpp-TPxx-NOM1-NOM2.tgz --ignore-failed-read \
progcpp-TPxx-NOM1-NOM2/{Makefile,*.cpp,*.hpp} && ls)
Vous pouvez également recopier cette fonction dans le terminal, qui utilise directement le nom du répertoire courant comme nom de fichier :
mysvg() (
local p=$(pwd) # le chemin absolu
local d=${p##*/} # le répertoire courant
echo "Sauvegarde de '$d/' dans '$d.tgz' ..."
cd .. || return 1
tar cvfz "$d.tgz" --ignore-failed-read \
"$d"/{Makefile,*.cpp,*.hpp} 2>/dev/null
ls -ls "$d.tgz"
)
puis l'utiliser en tapant :
mysvg
Exercice 1. Dessins de dominos en SVG, entrées-sorties, arguments et paramètres
1.a. Dessin en SVG
Voici un exemple de dessin en SVG :
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="300" height="200">
<title>Exemple simple de figure SVG</title>
<desc>
Cette figure est constituée d'un rectangle,
d'un segment de droite et d'un cercle.
</desc>
<line x1="5" y1="5" x2="250" y2="95" stroke="red" />
<circle cx="110" cy="80" r="50" fill="blue" />
<rect width="100" height="80" x="10" y="80" rx="10" ry="10"
style="fill:rgb(200,200,200);stroke-width:2;stroke:black" />
<text x="180" y="60">Un texte</text>
</svg>
Recopier ce texte dans un fichier avec l'extension .svg
puis vérifier qu'on
peut l'ouvrir avec un navigateur, gimp ou inkscape (si installé).
Écrire un programme en C++ domino1.cpp
qui vérifie les arguments de la ligne de
commande1.
Si l'argument --exemple-svg
est présent, il génère un fichier dont le nom est
l'argument suivant, et écrit ligne à ligne dans le fichier, à l'aide de l'opérateur <<
,
le texte de l'exemple de dessin SVG ci-dessus2.
Si le second argument est manquant il y a un message d'erreur et le programme
échoue en renvoyant 1.
Exemple de sortie :
$ ./domino1
Usage: ./domino1 --help pour afficher l'aide
$ ./domino1 --help
Options :
--help affiche l'aide
--exemple-svg fichier écrit un exemple en SVG
$ ./domino1 --exemple-svg
Erreur: nom de fichier svg attendu
$ ./domino1 --exemple-svg image.svg
Génération de image.svg ...
$ inkscape image.svg &
Compléments de cours :
Tester les arguments
Cet exemple montre comment tester les arguments de la ligne de commande avec le module cstring :
#include <iostream>
#include <cstring>
int main (int argc, char *argv[])
{
if (argc == 1) {
std::cout << "Usage: " << argv[0] << " --help pour afficher l'aide\n";
}
else if (strcmp(argv[1], "--help") == 0) {
std::cout << "Options :\n"
<< " --help affiche l'aide\n";
}
}
Écrire dans un fichier
Cet exemple montre comment écrire dans un fichier :
#include <iostream>
#include <fstream>
int main() {
// Crée et ouvre un fichier en écriture
std::ofstream f {"exemple.txt"};
// Écrit dans le fichier
f << "Ceci est \"du texte\" sur\n"
<< "plusieurs lignes.\n";
// Ferme le fichier
f.close();
}
1.b. Dessin d'un domino
Les dominos sont au nombre de 28, et sont numérotés pour n allant de 0 à 6 : n|0, ..., n|n.
Un domino dont les points sont a|b est dessiné par un rectangle formé de 2 carrés séparés par un trait, au centre duquel il y a un petit cercle plein (le rivet) ; dans les carrés il y a un nombre a, respectivement b, de cercles bien disposés.
Rajouter dans le programme une fonction qui génère un fichier SVG, dans lequel
est dessiné un domino orienté verticalement, en fonction des
paramètres a
et b
. Elle sera appelée par
le programme principal pour les arguments --domino a b image.svg
,
avec les tests sur le nombre d'arguments.
Rappel : la fonction atoi()
permet de convertir un char*
en int
.
Taille des lignes de code
Pensez à limiter la taille de vos lignes de code à (environ) 80 caractères, en alignant lorsque nécessaire (par exemple des tests à rallonge) de manière à en faciliter la relecture.
1.c. Dessin des 28 dominos
Déclarer des constantes1 entières globales :
IMAGE_WIDTH
etIMAGE_HEIGHT
seront la taille en pixel de l'image SVG générée ;DOMINO_SIDE
sera la largeur en pixels du petit côté d'un domino, qui aura donc comme longueur2*DOMINO_SIDE
;
définir également des constantes pour les couleurs et épaisseurs des différents éléments d'un domino.
Écrire une fonction write_preamble_svg
qui reçoit par référence1 un
fichier f
déjà ouvert en écriture, puis écrit l'entête SVG nécessaire dans f
pour créer une image de taille IMAGE_WIDTH
et IMAGE_HEIGHT
.
Écrire une fonction write_postamble_svg
qui reçoit par référence un fichier
f
déjà ouvert en écriture, puis écrit la fin du fichier SVG.
Écrire une fonction write_domino_svg
qui reçoit les paramètres suivants,
puis dessine le domino dans le fichier :
- un fichier
f
déjà ouvert, par référence ; - les nombres de points
a
etb
du domino ; - l'orientation horizontale ou verticale (un booléen) ;
- les coordonnées
cx
,cy
du centre du domino dans l'image, en pixels.
Écrire une fonction draw_all_dominos_svg
qui reçoit en paramètre le
nom d'un fichier SVG, l'ouvre, écrit l'entête du fichier SVG, dessine
chacun des 28 dominos dans l'image en les positionnant
verticalement en 7 colonnes sur 4 lignes, écrit la fin du fichier
puis ferme le fichier.
Rajouter dans le main
un argument de la ligne de commande
--all-dominos image.svg
qui déclenchera l'appel de la fonction
draw_all_dominos_svg
.
Compléments de cours :
Déclaration de constantes
Pour définir une constante il suffit de précéder la déclaration
par const
, par exemple :
const int foo = 1;
Passage par référence
Le passage par référence d'un paramètre est indiqué à l'aide de
l'opérateur &
; le paramètre devient alors un alias de la variable
passée en paramètre. Exemple :
void foo (int& bar) // passage par référence
{
bar += 1;
}
int thud = 5;
foo(thud);
std::cout << thud << "\n"; // affiche : 6
1.d. Fichier de positions
Écrire un fichier texte de positions de dominos, où chaque ligne représente un domino avec la syntaxe suivante :
a b is_vertical grid_x grid_y
a
et b
représentent le nombre de points du domino, is_vertical
vaut 1 si
le domino est vertical, 0 sinon, enfin grid_x
et grid_y
sont les coordonnées
du centre du domino sur une grille de largeur et hauteur DOMINO_SIDE/2
.
Pourquoi ces coordonnées sur une grille ? Selon les règles de placement des dominos, un domino double n|n est obligatoirement placé perpendiculairement à un autre domino *|n. On considère donc cette grille où chaque domino occupe 2 par 4 cases, et le centre de chaque domino est situé sur un sommet de la grille.
Écrire une fonction read_positions_file
qui reçoit en paramètre le nom d'un
fichier de positions, et par référence un tableau de struct
1 de taille
indéterminée, dans lequel seront stockées les informations lues.
La fonction lit le fichier1 et stocke les informations lues pour chaque domino dans chaque case du tableau. Elle renvoie le nombre de positions lues.
Écrire une fonction
write_dominos_from_positions_svg
qui reçoit en paramètres le nom d'un
fichier de positions et le nom d'un fichier SVG.
Elle déclare un tableau de struct
de taille 28 ;
elle lit le fichier de positions, ouvre le fichier SVG, écrit l'entête,
puis dessine dans le fichier SVG chacun des dominos issus du fichier de positions,
enfin écrit la fin du fichier SVG puis le ferme.
Rajouter dans le main
un argument de la ligne de commande
--from-positions positions.txt image.svg
qui déclenchera l'appel de la
fonction write_dominos_from_positions_svg
.
Compléments de cours :
Déclaration d'un struct
Cet exemple montre comment déclarer un struct
:
struct MyStruct {
int foo;
double bar;
};
Utilisation :
MyStruct shme;
shme.foo += shme.bar;
Lire dans un fichier
Cet exemple montre comment lire dans un fichier constitué de lignes contenant chacune 2 entiers :
#include <iostream>
#include <fstream>
int main() {
// Ouvre un fichier en lecture
std::ifstream f {"exemple.txt"};
// Lectures dans le fichier de 2 entiers par itération
int a, b;
while (f >> a >> b) {
std::cout << "Lu : " << a << " et " << b << "\n";
}
// Ferme le fichier
f.close();
}