Buts : Différencier les sources de nutriments et permettre leur génération automatique.
Avant d'introduire différents types de nutriments, nous allons revoir un peu la conception existante à la lumière des nouvelles notions vues en cours : à savoir, l'héritage et le polymorphisme.
class MaClasse : public Drawable, public Updatable(la classe MaClasse hérite de Drawable et de Updatable)
[Question Q3.1 ] : les classes fournies dans le répertoire Interface, à savoir Drawable et Updatable, fournissent deux méthodes polymorphiques drawOn et update. Quelles classes de votre conception actuelle serait-il bon de faire hériter de ces sous-classes ? Quel plus cela amène t-il à la conception ? Répondez à ces questions dans votre fichier REPONSES.
Faites les modifications ainsi suggérées.
Vous avez appris récemment que dans une hiérarchie polymorphique il était conseillé de programmer les destructeurs comme vituels... pensez-y!
On souhaite maintenant faire en sorte que la classe Nutrient se spécialise en deux sous-classes NutrientA et NutrientB.
Pour l'heure, ces deux sous-classes n'auront d'autre distinction que leur affichage graphique (les modalités de dessin restent les mêmes, seule la texture change).
Il vous est demandé maintenant de coder la hiérarchie de classes des nutriments en tenant compte des contraintes suivantes :
[Question Q3.2] : Qu'implique cette contrainte au niveau des définitions de drawOn et update. Répondez à cette question dans votre fichier REPONSES et procédez aux modifications suggérées.
[Question Q3.3] : Comment doit-être codée la méthode getConfig dans la hiérarchie de classes pour satisfaire cette contrainte ? Répondez à cette question dans votre fichier REPONSES et procédez aux modifications/codages suggérés.
[Question Q3.4] : Qu'est-ce qui fait que sans modifier les méthodes drawOn et update dans les sous-classes, l'affichage graphique peut faire usage de textures différentes (les couleurs pour NutrientA et NutrientB ne sont pas les mêmes) et la croissance dépend de conditions différentes ? Répondez à cette question dans votre fichier REPONSES.
Le test NutrientTest a été adapté pour cette étape : 'Shift N' permet de générer des NutrientA et la touche 'N' des NutrientB.
Lancez ce test comme vous l'avez fait à l'étape précédente, créez deux types de nutriments et "jouez" ensuite avec les conditions de températures, les deux types de nutriments doivent alors croître dans des conditions de température différentes :
Il peut être plus pratique et réaliste de permettre la génération automatique, à des espaces de temps réguliers, des sources nutriments. Par simplification, vous pouvez considérer que la génération automatique ne se fait que dans la boite courante (cela permet d'observer ce processus dans chaque boite, depuis son démarrage).
Créez une classe NutrientGenerator caractérisée par un compteur de type sf::Time, mesurant le temps écoulé depuis la précédente génération d'une source de nutriment. Le constructeur par défaut initialisera ce temps à sf::Time::Zero.
Pour faire évoluer ce compteur au cours du temps, il faut que la classe NutrientGenerator dispose d'une méthode update(sf::Time dt) gérant l'évolution de ses instances à chaque écoulement de pas de temps dt.
La méthode update va mettre en oeuvre l'algorithme suivant :
Pour finir, ajoutez à votre classe Laboratory un attribut de type NutrientGenerator qui va permettre d'y générer des sources de nutriments dans la boite courante.
[Question Q3.5] Quelle modification doit être faite dans Laboratory et dans quelle méthode pour permettre au générateur d'effectivement générer des sources de nutriments dans la boite de culture courante ? Répondez à ces questions dans votre fichier REPONSES.
Pour finir ajoutez à la classe NutrientGenerator une méthode reset permettant de réinitialiser son compteur de temps à sf::Time::Zero.
Le reset de Laboratory fera appel à cette méthode pour repartir de zéro lorsque l'on souhaite recommencer une autre simulation.
Le fichier de configuration de l'application app.json permet de jouer sur le temps de pause à observer entre deux générations spontanées de nutriment (["generator"]["nutrient"]["delay"]). Attribuez, par exemple, la valeur 2.5 à cette donnée. Lancez ensuite la cible nutrientTest; vous devriez voir apparaître spontanément des sources de nutriments (tantôt bleues, tantôt jaunes) dans l'environnement, comme dans la vidéo ci-dessous :
En jouant sur la température de la boite de culture, vous deviez pouvoir observer des conditions limites de croissance différentes pour les deux types de nutriments. Si vous avez fait les choses correctement, vous pourrez influer sur la probabilité de générer un type de nutriment plutôt qu'un autre. C'est donc le paramètre ["generator"]["nutrient"]["prob"] qui conditionne cela : pour une probabilité à 0 vous ne devriez avoir que des "bleues" et pour l'autre extrême, c'est-à-dire 1, que des "jaunes". Vous devriez aussi pouvoir voir se générer les sources de nutriments à intervalles de temps plus ou moins rapprochés en jouant sur le paramètre ["generator"]["nutrient"]["delay"].
[Question Q3.6] Quelles modifications devez-vous apporter au programme pour faire plafonner le nombre de sources de nutriments à une valeur paramétrable via les fichiers .json? Répondez à ces questions dans votre fichier REPONSES et implémentez cette spécification. Vérifiez au moyen du test précédent que cela fonctionne comme souhaité.