Projet : étape 4.2
Bactéries à grappin

Buts: Il s'agit ici d'introduire un nouveau type de bactéries se déplaçant au moyen d'un grappin.

Les cibles permettant de compiler et lancer cette partie sont gripTest et pilusMediatedTest. Il faut les décommenter le moment venu dans le CMakeLists.txt. Notez que Ctrl-F permet de faire une recherche dans l'éditeur de QtCreator (pour chercher où se trouve gripTest par exemple).

Le grappin de ce nouveau type de bactéries, nommées PilusMediatedBacterium, impactera sa façon  :

Une bactérie à grappin se divisera d'une façon analogue à une bactérie à flagelle unique; mais la division devra bien sûr produire une PilusMediatedBacterium. Il est recommandé de décaler un peu le clone et de diriger son grappin différemment pour une meilleure observation du clonage.

La bactérie à grappin ne se déplace plus librement dans la boite de culture. Son déplacement est uniquement régi par son grappin. Il n'y a donc pas de nécessité de modéliser une force régissant le déplacement comme cela a été le cas pour les bactéries à flagelle unique.

[Question Q4.6] Quel(s) lien(s) d'héritage proposez-vous de mettre en place pour intégrer les PilusMediatedBacterium à l'architecture existante ?

[Question Q4.7] En vous inspirant de ce que vous avez fait pour les bactéries à flagelle unique, et en observant le contenu du fichier de configuration app.json, comment proposez-vous d'accéder aux paramètres caractérisant ce type de bactéries (comme la longueur maximale de son grappin ou sa vitesse d'extension) ?

[Question Q4.8] Quelles méthodes déjà présentes dans la hiérarchie de classes des bactéries devrez-vous impérativement redéfinir dans PilusMediatedBacterium ?

Répondez à ces questions et justifiez vos choix dans votre fichier REPONSES.

Enfin, une PilusMediatedBacterium aura deux façons de perdre de l'énergie : en se déplaçant ou en déployant son grappin.

[Question Q4.9] Les facteurs de déperdition d'énergie permettant le calcul de la perte d'énergie dans chaque cas sont donnés par les valeurs associées à ["energy"]["consumption factor"]["move"] et ["energy"]["consumption factor"]["tentacle"] dans le fichier de configuration. Quel «getters» proposez-vous d'ajouter/redéfinir à/dans votre classe pour retrouver ces valeurs lorsque nécessaires ?

Répondez à cette question et justifiez vos choix dans votre fichier REPONSES

Programmez la classe PilusMediatedBacterium en utilisant les questions / réponses précédentes.

Vous laisserez vide ce qui touche au déplacement (méthode move) tout en l'anticipant, et commencerez par dessiner la bactérie comme une MonotrichousBacterium (mais sans duplication de code !).

Le constructeur de cette classe sera codé de façon analogue à celui des bactéries à flagelle unique (avec la position de la bactérie comme seul paramètre), il devra bien sûr s'adapter aux paramètres de configuration liés à "pilus mediated" dans le fichier de configuration.

La longueur maximale du grappin et sa vitesse seront consignés comme des paramètres mutables de type valeur numérique mutable positive (inspirez-vous directement de ce que vous avez fait pour les bactéries à flagelle unique au moment de leurs constructions).

Grapin

Pour modéliser le grappin, il suffit d'en modéliser l'extrêmité. C'est en effet le seul point qui nous intéresse puisqu'il va permettre à la bactérie de « s'aggriper » à des sources de nutriments.

Nous vous proposons donc d'implémenter une petite classe utilitaire Grip modélisant le grapin du grappin (c'est à dire l'extremité lui permettant de s'aggriper).

Un grapin sera construit au moyen d'une position et d'un rayon passé en paramètre.

La seule méthode utile à priori pour un grapin est une méthode permettant d'en déplacer la position (rappelez-vous de CircularBody::move).

Le grapin doit enfin bien sûr devenir un attribut de la bactérie à grappin.

Complétez votre code de sorte à l'y intégrer. Vous ajouterez à la classe PilusMediatedBacterium une méthode utilitaire void moveGrip(const Vec2d& delta) permettant de déplacer la position de son grapin.

Lors de sa création, toute bactérie à grappin aura un grapin occupant la même position qu'elle et un rayon plus petit, par exemple quatre fois moins grand. Le grappin sera ainsi (visuellement) complétement retracté au départ. Ceci est aussi valable pour les bactéries issues de la division.

Dessin complet d'une bactérie à grappin

Un bactérie à grappin se dessine jusqu'ici comme un simple cercle. Il s'agit maintenant d'ajouter à cette représentation, le dessin du grappin.

Il suffit pour cela de tracer un segment de droite entre la position de la bactérie et la position du grapin et de dessiner le grapin comme un petit cercle.

Pour dessiner un segment de droite avec SFML, vous pouvez utiliser la fonction utilitaire buildLine fournie dans src/Utility/Utility.hpp :

  auto line = buildLine(position1, position2, couleur, epaisseur);
  target.draw(line);
position1 et position2 sont les deux extrémités du segment, couleur une couleur SFML et epaisseur l'épaisseur du trait (1 par exemple).

Test 13 : Bactérie à grappin sans déplacement

Pour tester le code développé jusqu'ici vous pouvez utiliser le test fourni GraphicalTest/GripTest.cpp et qui peut être lancé au moyen de la cible gripTest (que vous aurez pris soin de décommenter dans le fichier CMakeLists.txt) .

Comme les bactéries à grappin ne peuvent pas encore se déplacer, il faut les créer à des endroits favorables à leur survie!

Laissez donc une source de nutriments se développer puis créez dessus une bactérie à grappin au moyen de la touche 'P'.

Vous devriez voir apparaître une bactérie avec un grappin déjà déployé (uniquement dans le cas de ce test car à sa création une bactérie doit normalement avoir un grappin rétracté : pour les curieux, regardez comment fonctionne le test fourni).

Vous devriez voir la bactérie se nourrir, se diviser et muter (sur sa couleur). La bactérie issue de la division ne doit pas avoir de grappin déployé.

←Libre à vous de jouer sur les paramètre du app.json opur rendre la division plus ou moins probable

Méthode de déplacement

Le mouvement d'une bactérie à grappin est un processus qui peut être modélisé par ce que l’on appelle un automate à état finis et dont voici une représentation graphique :

item

Ce graphique signifie que la bactérie se trouve au cours de son fonctionnement dans différents états (IDLE, DEPLOY etc.), que chaque état va nécessiter d’entreprendre un certain nombre d’actions et que la transition d’un état à un autre peut être déclenchée par un certain nombre d’événements.

Le texte associé aux flèches décrit la nature de l’événement. S'il n'y en a pas c'est que la transition d'un état à l'autre se fait sans condition, dès que l'ensemble des actions associées à un état est effectué.

La table ci-dessous complète la description de l'automate en décrivant les actions à entreprendre dans chaque état :

Etat Description Actions
IDLE
(la bactérie est dans cet état lors de sa création)
Grappin au repos Rien de particulier (juste passage à l'état suivant).
WAIT_TO_DEPLOY Grappin se préparant au déploiement
  • Choisir parmi N directions tirées au hasard celle avec le score maximal (vous pouvez pouvez vous inspirer de ce que vous avez fait pour le basculement des bactéries à flagelle unique);
  • Orienter la bactérie dans cette direction (elle se déplacera dans la même direction que son grappin) et passer à l'état suivant.
DEPLOY Grappin se déployant
  • Déplacer le grapin à la position : direction * vitesse_grappin * dt.asSeconds();direction est la direction de la bactérie (rappelez-vous qu'elle a déjà été orientée correctement dans l'état précédent) et vitesse_grappin est la valeur du fichier de configuration liée à "tentacle speed";
  • Faire perdre à la bactérie une quantité d'énergie proportionelle au déplacement de son grappin : f * vitesse_grappin * dt.asSeconds() , où f est le facteur de déperdition d'énergie lié au déploiement de la grappin (revoir vos «getters»);
  • Trouver s'il y a une source de nutriments en collision avec le grapin;
  • Choisir l'état suivant (ATTRACT ou RETRACT) selon qu'une source de nutriments est en contact avec le grapin ou pas.
    Si la bactérie de ne peut pas transiter en ATTRACT ou en RETRACT, alors elle reste en DEPLOY.
ATTRACT Grappin attirant la bactérie vers la nourriture
  • Si la bactérie est en collision avec cette source elle passe à l'état EAT sinon elle se déplace vers cette source de direction_grappin * vitesse_grappin * facteur_vitesse * dt.asSeconds() (pensez à CircularBody::move); facteur_vitesse est la valeur associée à ["speed factor"];
    • La direction du grappin peut se calculer comme la différence (normalisée) entre la position du grapin et la position de la bactérie.
    • Attention : la source de nutriments attirant la bactérie peut avoir disparu entre deux appels à update (mangée par d'autres bactéries).
  • Faire perdre à la bactérie une quantité d'énergie proportionelle à son déplacement : son déplacement sera multiplié par le facteur de déperdition d'énergie lié au déplacement («getters»);
  • Si la source de nutriment a disparu, la bactérie passe à l'état RETRACT.
RETRACT Grappin se rétractant
  • Si la distance entre la bactérie et le grapin est inférieure ou égale au rayon de la bactérie, cette dernière repasse à l'état IDLE (le grappin est entièrement rétracté);
  • Sinon, le grapin se déplace comme dans le cas du déploiement mais dans la direction inverse donnée par le vecteur position_bacterie - position_grapin normalisé (Vec2d propose une méthode normalised). La bactérie perdra de l'énergie de la même façon que dans le cas du déploiement du grappin.
EAT Bactérie en train de consommer de la nourriture
  • Si la bactérie n'est plus en collision avec un source de nourriture elle repasse à l'état IDLE
    (le reste du processus de consommation de nutriment est pris en charge par la méthode appelante update).

[Question Q4.10] Un type énuméré peut être une bonne solution pour répertorier les différents états cités plus haut. Comment proposeriez-vous d'en utiliser un pour mettre en oeuvre l'algorithme de mouvement ?

Répondez à cette question dans votre fichier REPONSES.

Complétez la méthode move implémentant l'automate à état fini décrit ci-dessus.

Test 14 : Déplacement d'une bactérie à grappin

Pour tester cette partie, vous pouvez utiliser le test fourni GraphicalTests/PilusMediatedTest.cpp qui peut être lancé au moyen de la cible pilusMediatedTest (que vous aurez pris soin de décommenter dans le fichier CMakeLists.txt) .

Ce test vous permet de créer des bactéries à grappin au moyen de la touche 'P'.

Retardez la génération des nutriments en jouant sur le paramètre ["generator"] ["nutriment delay"] et créez une ou plusieurs bactéries dans une assiette sans nutriments, proches des bords de la boite. Vous devriez pouvoir observer le fait que  :

  1. Que les grappins se déploient mais ne peuvent le faire au delà des limites de la boite.
  2. Que les grappins se retractent s'ils atteignent une certaine longueur ou s'ils touchent les bords de la boite.
  3. Qu'une fois des nutriments générés, les grappins se déploient plutôt vers l'intérieur de la boite (perception du gradient de nutriment).
  4. Que les bactéries qui déploient un certain nombre de fois leur grappins sans réussir à atteindre des sources de nutriments finissent par mourir et disparaître de la boite.
  5. Et que les grappins touchant les nutriments permettent aux bactéries auxquels ils appartiennent de s'en rapprocher et de s'en nourrir.
←Libre à vous de jouer sur les paramètre du app.json pour expérimenter différents paramètres liés aux bactéries à grappin

Retour à l'énoncé du projet (partie 4) Module suivant (partie 4.3)