TD06 : Implémentation du Jeu (V1)
Maintenant que nous avons programmé les tests de la bibliothèque game, nous
allons nous concentrer sur l'implémentation de cette bibliothèque, et plus
précisément de l'implémentation dans les fichier game.c
et game_aux.c
de
toutes les fonctions spécifiées respectivement dans game.h
et game_aux.h
.
La description de ces fonctions est également disponible dans la documentation officielle du jeu, générée avec l'outil Doxygen.
Préambule
Au cours de ce travail, gardez à l’esprit cette citation de Donald Knuth :
Premature optimization is the root of all evil (or at least most of it) in programming.
Ou en version longue :
There is no doubt that the grail of efficiency leads to abuse. Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%. A good programmer will not be lulled into complacency by such reasoning, he will be wise to look carefully at the critical code; but only after that code has been identified.
Gardez à l’esprit également que votre code doit être maintenable, et qu’il devra s’adapter aux caprices du client (V2) !
Comme vous rentrez dans une phase de codage plus intensive, il devient important d’utiliser un environnement de développement plus ergonomique. Parmi les fonctionnalités qui vous feront gagner le plus de temps, on trouve : la mise en forme automatique de votre code, la vérification de votre code à la volée (ou linter), la complétion automatique, l’intégration d’un déboggeur, l’intégration de Git, ... Un IDE comme VS Code offre toutes ces fonctionnalités. En outre, il est impératif d'apprendre à vous servir efficacement des outils de debogage.
-
Un guide sur l'utilisation de VS Code est à votre disposition sur moodle.
-
En guise d'activité préliminaire, regardez sur MediaPod la vidéo sur l'art du déboguage.
Exercice 0 : avant d'attaquer une nouvelle version du code
Avant d'attaquer une nouvelle version du code (la version v1
), il vous est
demandé de créer dans votre dépôt Git une branche v0
pour marquer cette
version dans l'historique de Git. Ainsi, on utilisera la branche principale
(main
) pour développer la nouvelle version du code.
$ git branch v0 # création de la branche locale v0
$ git push -u origin v0 # publication de la branche v0 --> origin/v0
Nota Bene : Attention, la création de la branche v0
et sa publication ne
doit être fait que par un seul utilisateur. Les autres utilisateurs se
contenteront de récupérer la branche, comme ceci...
$ git pull # on synchronise le dépôt Git (y compris les branches distantes)
$ git branch -a # on affiche toutes les branches (locales et distantes)
$ git switch v0 # si besoin, on bascule sur la branche locale v0
$ git switch main # on revient dans la branche principale
Notez qu'il est également possible de continuer à améliorer vos tests en
travaillant explicitement dans la branche v0
. Ajoutons par exemple un nouveau
test dans la branche v0
:
$ git switch v0
$ git add ...
$ git commit -m "add new test"
$ git push
Ce faisant, vous avez ajouté un nouveau test dans la branche v0
, mais qui
n'est pas pour l'instant disponible dans la branche principale. Afin de
rappatrier les modifications apportées dans la branche v0
vers la branche
principale, il va être nécessaire de réaliser une fusion de branches avec la
commande git merge.
$ git switch main # je me positionne dans la branche main
$ git merge v0 # je fusionne la branche v0 dans main
$ git log # on voit maintenant le commit du test dans la branche main (en local uniquement)
$ git push # on publie ce nouveau commit vers origin/main
Attention, néanmoins aux conflits qui peuvent survenir lors de la fusion des deux branches, si des modifications portent sur des portions identiques du code !
Exercice 1 : une coquille vide pour game.c
Ce travail débute par une phase de réflexion sur la définition de la structure
de données struct game_s
, qui sera au coeur de votre projet. Cette phase là
est importante, car elle va grandement conditionner la suite de votre travail en
équipe.
Nota Bene : Pour rappel, le type struct game_s
est un type opaque, qui
doit être défini dans votre fichier game.c
, mais dont la définition n'est pas
exposée dans game.h
. Cette structure est uniquement manipulée dans l'interface
game.h
par l'intermédiaire d'un pointeur (types game
ou cgame
).
L'utilisation du type cgame
(pointeur constant) dans un fonction (comme par
exemple game_get_xxxx()
) indique au compilateur (et au programmeur) que la
fonction ne va/doit pas modifier les champs de la structure, mais juste les
consulter. A l'inverse, les fonctions (comme par exemple game_set_xxxx()
)
utilisent un pointeur de type game
car elles modifient l'état de la structure.
Pour ce premier rendu en équipe, on vous demande :
- de supprimer le fichier
libgame.a
de votre dépôt GitLab et d'ajouter en remplacement les fichiersgame.c
etgame_aux.c
, qui vont servir à générer cette bibliothèque ; - de mettre à jour votre fichier
CMakeLists.txt
; - de définir dans
game.c
votre structurestruct game_s
; - de mettre en place dans
game.c
etgame_aux.c
une coquille vide pour toutes les fonctions degame.h
etgame_aux.h
respectivement ; - d'ajouter un fichier
.gitignore
afin d'ignorer dans Git le répertoirebuild
, ainsi que différents les fichiers produits par CMake ou Make ; - d'ajouter un fichier
.clang-format
pour gérer automatiquement une mise en forme cohérente de votre code au sein de l'équipe (voir les consignes en Annexe) ; - d'ajouter un fichier
README.md
avec un description minimale du projet et le nom des auteurs ; - d'ajouter un nouveau jalon
V1
dans GitLab et d'y associer un nouveau ticket pour chaque fonction à implémenter, sans oublier de vous répartir ces tickets ; - d'effectuer le rendu initial sur Moodle (en équipe).
A ce niveau, votre projet doit compiler sans warnings ni erreurs la
bibliothèque game ainsi que tous les exécutables (game_text
, vos tests).
Bien évidemment, cette version ne doit pas (encore) passer vos tests !
Exercice 2 : implémentation de game.c
Une fois tous les tickets ajoutés dans GitLab et répartis entre tous les membres
de l'équipe, commencez au plus tôt à travailler sur ce rendu, qui vous demandera
pas mal d'effort ! En aucun, vous ne devez modifier les fichiers game.h
ou
game_aux.h
.
Idéalement, votre projet CMake doit compiler sans erreurs ni warnings les programmes suivants :
- la bibliothèque
libgame.a
, - l'exécutable
game_text
, - l'ensemble de vos tests.
Ces programmes doivent fonctionner correctement. En particulier, votre
implémentation de la bibliothèque game (fonctions de game.h
et game_aux.h
)
doit passer tous vos tests, ainsi que tous les tests des enseignants. De plus,
votre code ne doit comporter aucune fuite mémoire (ou memory leak). L'outil
Valgrind, qui est intégré au framework CMake, permet de détecter les fuites
mémoires dans vos tests de la manière suivante :
make # compilation
make test # exécution normale des tests
make ExperimentalMemCheck # exécution des tests avec Valgrind
Nota Bene : Ne pas oublier d'ajouter include(CTest)
dans votre fichier
CMakeLists.txt
pour disposer de la cible ExperimentalMemCheck
.
Par ailleurs, on demande de produire un code mis en forme correctement (indentation, nommage des variables, ...) avec un style de programmation uniforme sur tout le projet. De manière générale, il est demandé de respecter des conventions de codage cohérentes, afin de faciliter la lisibilité de votre code. Afin d'éviter d'inutiles conflits das Git, il est nécessaire que tous les programmeurs d'une même équipe respectent ces conventions ! En outre, votre code devra être suffisament commenté. On évitera aussi toute redondance de code inutile.
- Effectuez votre rendu final en équipe sur Moodle.