Projet : étape 4.3
Bactéries avec déplacements groupés

Buts: Introduire un nouveau type de bactéries se déplaçant en groupe.

La cible permettant de compiler et lancer cette partie est groupMotilityTest. Il faut la 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 groupMotilityTest par exemple).

Le nouveau type de bactéries à coder à cette étape est caractérisé essentiellement par un mode de déplacement spécifique (en groupe) : la bactérie se rapprochant le plus de sources de nutriments exercera une force d'attraction sur les autres. Il s'agit donc d'un exemple où une force régissant le déplacement n'est pas le vecteur nul !

Il vous est demandé ici de:

  1. Modéliser un nouveau type de bactéries et son appartenance à un groupe (BacteriaGroup) de bactéries du même type.
  2. Faire en sorte que leur déplacement soit conditionné par une force représentant l'attraction exercée par la bactérie la mieux située.

Les bactéries de déplaçant en groupe seront représentées au moyen d'une classe générique GroupMotilityBacterium. Chacune d'elle appartiendra à un groupe (BacteriaGroup).

Il pourra y avoir plusieurs groupes dans une boite de culture. La différence entre un groupe et l'autre se fera au niveau:

  1. De la force exercée par la bactérie la plus proche des nutriments sur les autres.
  2. La couleur de ses bactéries.
Chaque GroupMotilityBacterium ne sera solidaire que de son BacteriaGroup.

Commençons par modéliser plus précisément la notion de groupe.

Prévoyez une coquille vide pour la classe GroupMotilityBacterium.

Groupe

Un groupe BacteriaGroup sera simplement caractérisé par :

Un BacteriaGroup sera un objet simulable dont la méthode update a pour rôle de mettre à jour la bactérie « leader » à chaque pas de simulation. Un BacteriaGroup n'est pas dessinable en tant que tel.

[Question Q4.11] : Une boite de culture contiendra désormais aussi des BacteriaGroup qu'elle doit faire évoluer. Sachant que nous souhaitons disposer d'une fonctionnalité Laboratory::addSwarm ajoutant un BacteriaGroup (vide de bactéries) dans chacune des boites de culture et invocable comme suit:

getEnv().addSwarm(id)); // id est la chaîne de caractères identifiant du groupe
Quelle(s) modification(s) faites-vous et à quelle(s) classe(s) pour intégrer cela ?

Répondez à cette question dans votre fichier REPONSES et implémentez ces modifications.

Les fonctionnalités qu'il est raisonnable d'anticiper pour la BacteriaGroup sont :

  1. Des méthodes permettant d'y ajouter ou retrancher une GroupMotilityBacterium* donnée.
  2. Une méthode retournant la position de la bactérie « leader ».
  3. Un «getter» retournant la couleur de départ des bactéries du BacteriaGroup, via le fichier de configuration (valeur associée à ["swarms"][mId]["color"] pour le BacteriaGroup ayant l'identificateur mId).
  4. Et bien sûr la méthode update évoquée plus haut.

Libre à vous d'ajouter d'autres méthodes si cela s'avère nécessaire.

La classe GroupMotilityBacterium

Complétons maintenant la classe GroupMotilityBacterium ébauchée précédemment. Une GroupMotilityBacterium est une Bacterium (elle a toutes les caractéristiques génériques des bactéries). On considère pour simplifier qu'elle a connaissance du BacteriaGroup auquel elle appartient.

Si l'on part cette hypothèse, il y aura une dépendance circulaire entre les classes GroupMotilityBacterium et BacteriaGroup. Pour casser cette dépendance, vous pouvez prédéclarer GroupMotilityBacterium dans BacteriaGroup.hpp.

[Question Q4.12] : Une GroupMotilityBacterium doit disposer d'une force régissant son déplacement, exactement comme les bactéries simples. Quels liens mettez-vous en place pour modéliser cette force ?

Répondez à cette question dans votrte fichier REPONSES et codez la coquille vide de la classe GroupMotilityBacterium en mettant en place ces liens d'héritage.

Une GroupMotilityBacterium se divise comme une Bacterium, mais doit produire une GroupMotilityBacterium (appartenant au même groupe que la bactérie d'origine).

Finalement, pour simplifier, les GroupMotilityBacterium n'ont pas d'autres caractéristiques mutables que leur couleur.

[Question Q4.13] Au vu de ce qui précède, quelles méthodes déjà présentes dans la hiérarchie de classes des bactéries devrez-vous impérativement redéfinir dans GroupMotilityBacterium ?

Répondez à cette question dans votre fichier REPONSES.

Dessin

Une GroupMotilityBacterium sera dessinée comme une Bacterium. S'il s'agit du « leader », faites aussi en sorte qu'en mode «debug» (fonctionnalité isDebugOn de Application.hpp), un anneau rouge se dessine autour d'elle (voir les vidéos ci-dessous).

Vous avez déjà dessiné des anneaux dans CultureDish par exemple.

Construction/Destruction

Le constructeur d'une GroupMotilityBacterium prendra en paramètre sa position et un pointeur sur le BacteriaGroup auquel elle doit appartenir.

Les valeurs utiles à l'initialisation sont bien sûr à trouver dans le fichier de configuration (sous ["group motility"] ).

Le constructeur sera en charge d'ajouter la bactérie à son BacteriaGroup.

Nous créerons les GroupMotilityBacterium en appuyant sur les touches numériques du clavier (1, 2 ou 3). Appuyer sur la touche 1 par exemple créera une bactérie appartenant au BacteriaGroup ayant 1 pour identifiant. Ces groupes sont créés au début de la simulation. Ouvrez le fichier de test GraphicalTests/GroupMotilityTest et examinez les méthodes onSimulationStart et onEvent pour comprendre comment tout cela se met en place. Il y a donc toujours 3 groupes dans la boite mais ils resteront vides tant que l'on n'y a pas mis de bactéries au moyen des touches appropriées. Attention cependant, votre code doit être conçu de façon générale, c'est à dire sans présupposer qu'il n'existera toujours que les identifiants 1, 2 et 3.

[Question Q4.14] Si vous examinez la méthode onEvent dans l'exemple de programme précédent, vous verrez que le placement d'une GroupMotilityBacterium nécessite de recourir à l'appel getEnv().addBacteriumToSwarm(id, const Vec2d& position);. Cette dernière a pour but d'ajouter une GroupMotilityBacterium à la boite courante en l'intégrant au groupe d'identificateur id de cette boite. Que devez-vous ajouter à votre code et où pour mettre en place cette fonctionnalité ?

[Question Q4.15] Une GroupMotilityBacterium est donc ajoutée à la boite comme toutes les autres (elle fait partie de la collection de bactéries de la boite). Le destructeur de BacteriaGroup doit-il faire quelque chose selon vous ?

[Question Q4.16] Lorsqu'une GroupMotilityBacterium meurt, elle ne doit plus être recensée dans son BacteriaGroup. Que devez-vous ajoutez à votre code et où pour que cette contrainte soit respectée ?

Répondez à ces questions dans votre fichier REPONSES en justifiant vos choix.

En vous inspirant de ce que vous avez fait jusqu'ici pour les autres bactéries et en tenant compte de la description faite ci-dessus, complétez toutes les fonctionnalités des BacteriaGroup hormis celle liée au déplacement (méthode move).

Test 15 : bactéries avec comportements de groupe

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

Ce test vous permet de créer des bactéries avec comportement de groupe au moyen des touches '1' à '3'.

Lorsqu'une première source de nutriments apparaît, créez une bactérie, au moyen de la touche '1' par exemple, en la positionnant sur la source de nutriments. Cette bactérie devrait d'emblée apparaître comme étant le « leader » et commencer à se nourrir.

Créez d'autres bactéries du même BacteriaGroup (en utilisant toujours la même touche) sur d'autres sources de nutriments. Vous devriez pouvoir aussi observer des changements de « leadership » en fonction de la proximité des sources de nutriments ainsi que des phénomènes de division et de mutation de la couleur.

← Ici c'est d'abord la touche 1 qui est utilisée (bactéries vertes) puis la 2. Le changement de «leadership» en fonction de la proximité des nutriments doit être visible. Des changements de couleurs sont observables suite aux divisions (favorisées par la création préalable de nutriments en abondance).

Déplacement groupé

La méthode move se codera de façon analogue à ce que vous avez fait dans MonotrichousBacterium.

Les différences résideront dans les deux points suivants:

  1. La force ne sera plus le vecteur nul mais le vecteur coeff_force_swarm * (position_leader - position)position est la position de la bactérie, position_leader est la position du « leader » de son groupe et coeff_force_swarm est un coefficient d'attraction du leader, specifique à chaque BacteriaGroup (valeur liée à ["swarms"][idBacteriaGroup]["force factor"] dans le fichier de configuration).
  2. Si la bactérie est le « leader », une fois la mise à jour de sa position faite, elle choisira au hasard une nouvelle direction : parmi 20 tirées au hasard, elle prendra celle avec le meilleure score.
  3. Pour un comportement de groupe aisément visualisable, il est recommandé de garder une vitesse constante (getAppConfig()["group motility"])["speed"]["initial"].toDouble()) Le calcul du vecteur vitesse sera alors simplement cette vitesse constante multipliée par le vecteur direction.

Test 16 : Déplacement groupé

Pour tester cette partie, vous pouvez utiliser le même test que précédemment.

Ce test vous permet de créer des bactéries avec comportement de groupe au moyen des touches '1' à '2'.

Retardez la génération des nutriments en jouant sur le paramètre ["generator"] ["nutriment delay"], puis  :

  1. Lorsqu'une première source de nutriments apparaît, créez une bactérie, au moyen de la touche '1' par exemple, en la positionnant proche de la source de nutriments. Cette bactérie devrait d'emblée apparaître comme étant le « leader » et se diriger vers la source.
  2. Créez ensuite d'autres bactéries du même BacteriaGroup (en utilisant toujours la même touche). Elle devraitent suivre le « leader ».

Vous devriez pouvoir aussi observer des changements de « leadership » en fonction de la proximité des sources de nutriments ainsi que tous les autres comportement attendus (disparition, division, mutation de la couleur etc.)

← Ici c'est d'abord la touche 1 qui est utilisée (bactéries vertes) puis la 2. La simulation est ralentie, avec relativement peu de nutriments, pour permettre de mieux observer la dynamique des déplacements. Avec des conditions plus rapides et d'avantages de nutriments, les divisions devraient être observables, comme dans la vidéo précédente.

Retouches finales

Vous avez appris récemment que les destructeurs doivent être virtuels en cas d'utilisation polymorphique.

Re-examinez les destructeurs existants dans votre code à la lumière de ce conseil (si vous ne voyez pas l'utilité de la chose posez nous des questions ;-))


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