Un corrigé pédagogique pour comprendre et justifier vos réponses. Les conseils de rédaction ne constituent pas un barème officiel détaillé.
Application
Simulation de coccinelles, hasard et conditions d’arrêt
Un producteur introduit des coccinelles dans une serre pour limiter les pucerons. Le modèle du sujet simule la chasse, la reproduction, le vieillissement et la croissance des proies. Une Coccinelle possède age, esperance_de_vie, sexe (male ou femelle) et niv_nutrition. random.randint(a, b) inclut ses deux bornes ; random.random() renvoie une valeur de[0,1[. Les résultats d’une exécution varient avec le hasard : il faut contrôler les règles et les invariants, pas mémoriser une population finale unique.
Le dossier comporte le sujet et les fichiers listés dans les téléchargements. Les codes de départ sont reproduits ci-dessous. Travaillez sur une copie. Les appels professeur signalés dans les questions servent à présenter votre démarche ; vous pouvez aussi demander de l’aide en cas de difficulté.
Code fourni : coccinelles.py
import random
class Coccinelle:
def __init__(self, sexe, age, niv_nutrition):
self.age = age
self.esperance_de_vie = random.randint(200, 350)
self.sexe = sexe
self.niv_nutrition = niv_nutrition
def chasser(self, nb_proies, nb_coccinelles):
if nb_coccinelles == 0:
return nb_proies
proies_par_cocci = nb_proies / nb_coccinelles
if proies_par_cocci > 20:
consomme = random.randint(12, 20)
elif proies_par_cocci > 10:
consomme = random.randint(8, 15)
else:
consomme = random.randint(3, 8)
consomme = min(consomme, nb_proies)
if consomme >= 10:
self.niv_nutrition += 1
else:
self.niv_nutrition = max(0, self.niv_nutrition - 1)
return nb_proies - consomme
def reproduction(self):
"""
Une femelle avec un niveau de nutrition >= 2 engendre exactement
deux descendants : un mâle et une femelle.
"""
descendants = []
if self.sexe == "femelle" and self.niv_nutrition >= 2:
descendants.append(Coccinelle("male", 0, 0))
descendants.append(Coccinelle("femelle", 0, 0))
self.niv_nutrition = 0
return descendants
def a_survecu(self):
"""
Met à jour l'âge de la coccinelle et indique si elle est encore en vie.
"""
self.age = self.age + 1
return self.age < self.esperance_de_vie
def __repr__(self):
return f"Coccinelle {self.sexe}, âge: {self.age}/{self.esperance_de_vie}, niv_nutrition: {self.niv_nutrition}"
def evolution(population, nb_proies):
"""
Simule une journée dans l'écosystème :
- chasse des coccinelles
- reproduction
- vieillissement et mortalité
- croissance des pucerons
population est une liste d'instances de la classe Coccinelle
nb_proies est un entier indiquant le nombre de proies
Cette fonction renvoie un couple (population_suivante, nouveau_nb_proies) indiquant
la nouvelle population à la fin de la journée et le nombre de proies.
"""
population_suivante = []
nouveau_nes = []
nb_coccinelles = len(population)
for coccinelle in population:
nb_proies = coccinelle.chasser(nb_proies, nb_coccinelles)
if coccinelle.a_survecu():
population_suivante.append(coccinelle)
nouveau_nes += coccinelle.reproduction()
# Croissance naturelle des pucerons (augmentation de 20% par jour)
nb_proies = int(nb_proies * 1.2)
# Ajout des nouveau-nés en fin de journée
population_suivante += nouveau_nes
return population_suivante, nb_proies
#############################################################################
# Écrire ci-dessous le code pour les questions de l'énoncé #
#############################################################################
Question 1
#Créer trois coccinelles de 10 jours, de nutrition 2 : deux femelles et un mâle. Avec 200 pucerons, simuler cinq jours par une boucle en appelant evolution. Afficher à chaque fin de journée le nombre de coccinelles et de pucerons.
Indice
La fonction renvoie un couple de valeurs mises à jour.
Comprendre la correction
population = [Coccinelle('femelle', 10, 2),
Coccinelle('femelle', 10, 2), Coccinelle('male', 10, 2)]nb_proies = 200
for jour in range(1, 6):
population, nb_proies = evolution(population, nb_proies)
print(jour, len(population), nb_proies)Il faut réaffecter les deux valeurs renvoyées : evolution construit une nouvelle liste de population. Réutiliser sans changement la liste initiale ignorerait les naissances et les décès. Les compteurs sont affichés après l’appel, donc à la fin de la journée. Les objets sont mutables : recréer la population avant un autre essai.
Question 2
#Écrire simulation_simple(population, nb_proies), avec 30 jours maximum, arrêt dès que les coccinelles ou les pucerons tombent à zéro. Renvoyer (nombre final de coccinelles, nombre final de pucerons, jours simulés). Tester avec la population initiale précédente et 1000 pucerons.
Comprendre la correction
def simulation_simple(population, nb_proies):
jours = 0
while jours < 30 and len(population) > 0 and nb_proies > 0:
population, nb_proies = evolution(population, nb_proies)
jours += 1
return len(population), nb_proies, jourspopulation = [Coccinelle('femelle', 10, 2),
Coccinelle('femelle', 10, 2), Coccinelle('male', 10, 2)]print(simulation_simple(population, 1000))
assert simulation_simple([], 1000) == (0, 1000, 0)
assert simulation_simple([Coccinelle('male',10,2)], 0) == (1, 0, 0)La condition vérifie les deux populations avant chaque journée. Une population déjà nulle conduit donc à zéro jour simulé. La variable jours compte les appels effectivement terminés et non une limite théorique. Pour rendre une comparaison reproductible, appeler random.seed avec la même valeur avant chaque création de population, car le constructeur tire aussi l’espérance de vie.
Le compteur de jours doit décrire ce que le programme a réellement simulé. Avec une population déjà vide, la condition initiale est fausse et aucune journée ne passe. Avec des populations vivantes, on appelle le moteur, on récupère son nouvel état, puis on incrémente le compteur. La condition est réévaluée sur cet état pour décider du jour suivant. Faire le test d’extinction seulement après une boucle fixe de 30 jours ne respecterait pas l’arrêt prématuré. Inversement, retourner toujours 30 masquerait une extinction survenue plus tôt.
Question 3
#Écrire la documentation et les commentaires de chasser.
Comprendre la correction
def chasser(self, nb_proies, nb_coccinelles):
"""Simule la chasse d'une coccinelle et renvoie les proies restantes.
nb_proies est un entier positif ou nul ; nb_coccinelles aussi.
Modifie self.niv_nutrition sans jamais le rendre négatif.
Si aucune coccinelle n'est comptée, les proies restent inchangées.
"""
if nb_coccinelles == 0:
return nb_proies # éviter une division par zéro
proies_par_cocci = nb_proies / nb_coccinelles
if proies_par_cocci > 20:
consomme = random.randint(12, 20)
elif proies_par_cocci > 10:
consomme = random.randint(8, 15)
else:
consomme = random.randint(3, 8)
consomme = min(consomme, nb_proies) # ne pas manger plus que le stock
if consomme >= 10:
self.niv_nutrition += 1
else:
self.niv_nutrition = max(0, self.niv_nutrition - 1)
return nb_proies - consommeDécrire l’effet de bord sur la nutrition est indispensable. Le code n’enregistre pas exactement un nombre de jours consécutifs bien nourris : il décrémente le niveau d’un jour quand la ration est insuffisante, au lieu de le remettre directement à zéro. La documentation doit refléter le code réellement fourni, même si la présentation initiale utilise cette expression.
Question 4
#Modifier reproduction et a_survecu : reproduction seulement à partir de 20 jours ; une coccinelle de nutrition 0 a une chance sur 3 de mourir dans la journée. Tester à nouveau la simulation.
PythonProgrammer la maturité des coccinellesÉcrivez votre solution et mettez-la à l’épreuve
Modifiez reproduction : une femelle d’au moins 20 jours et de nutrition au moins 2 crée exactement deux Coccinelle, un mâle puis une femelle, tous deux d’âge et nutrition nuls. Après cette naissance, sa nutrition devient 0. Sinon renvoyez une liste vide sans changer son état. Cet entraînement isole la reproduction ; le vieillissement et le risque de famine sont traités séparément dans le corrigé.
class Coccinelle:
def __init__(self, sexe, age, niv_nutrition):
self.age = age
self.esperance_de_vie = random.randint(200, 350)
self.sexe = sexe
self.niv_nutrition = niv_nutrition
def reproduction(self):
# Complétez cette méthode
pass
Les cas de test proposés :
- Le jour exact de maturité : 20 jours et nutrition 2 suffisent ; les descendants sont de vrais objets.
- La veille est trop tôt : La nutrition ne remplace pas la condition d’âge.
- Un mâle mature : La condition sur le sexe reste nécessaire.
- Nutrition insuffisante : Un échec de reproduction ne doit pas consommer la nutrition.
- Pas de seconde naissance immédiate : La remise à zéro empêche une nouvelle portée sans récupération.
Indice
Ajouter une condition de maturité sans supprimer les conditions déjà présentes.
Comprendre la correction
def reproduction(self):
descendants = []
if (self.sexe == 'femelle' and self.niv_nutrition >= 2
and self.age >= 20):
descendants.append(Coccinelle('male', 0, 0))
descendants.append(Coccinelle('femelle', 0, 0))
self.niv_nutrition = 0
return descendantsdef a_survecu(self):
self.age += 1
if self.age >= self.esperance_de_vie:
return False
if self.niv_nutrition == 0 and random.random() < 1 / 3:
return False
return TrueL’âge 20 est inclus. Pour la famine, un tirage strictement inférieur à 1/3 couvre un tiers de[0,1[. Les autres coccinelles restent soumises à leur espérance de vie. L’ordre fourni appelle a_survecu avant reproduction : l’âge a donc déjà augmenté quand la maturité est testée. Il appelle aussi reproduction même après un décès ; ce défaut du moteur n’est pas demandé dans la question, mais une amélioration cohérente consiste à déplacer cet appel à l’intérieur du if de survie, et à expliquer ce changement supplémentaire.
# Amélioration cohérente dans evolution :
if coccinelle.a_survecu():
population_suivante.append(coccinelle)
nouveau_nes += coccinelle.reproduction()Comparer plusieurs exécutions ou utiliser une graine fixe. Une seule simulation ne permet pas de mesurer une probabilité. Pour les tests unitaires, imposer des tirages de 0 et de 0,9 permet de vérifier les deux issues sans test aléatoire instable.
Pour vérifier la probabilité sans attendre des milliers d’expériences, testez les branches du code avec des tirages imposés : une coccinelle affamée doit mourir pour un tirage 0,2 et survivre au risque de famine pour 0,9. Une coccinelle nourrie ne doit pas mourir de cette cause, quelle que soit cette valeur. Vérifiez séparément le vieillissement à l’espérance de vie. Ces tests contrôlent les décisions exactes ; ils ne prétendent pas prouver que le générateur aléatoire produit la bonne distribution. La comparaison de simulations globales constitue un autre niveau de validation.
Prévoir une transitionUn atelier pour expérimenter
Choisissez une réponse puis confrontez votre intuition à l’explication. Vous pouvez modifier vos choix.
Lire les réponses et leurs explications
- Femelle de 19 jours, nutrition 2 : appelée directement, reproduction renvoie…
Une liste vide.. L’âge interdit encore la reproduction.
- Nutrition 0 et tirage 0,2 : que fait le test tirage<1/3 ?
Décès lié au manque de nourriture.. Le seuil vaut environ 0,3333.
Appuyez votre explication sur les valeurs et les conditions exactes du programme.
Tester les règles sans subir le hasardUn atelier pour expérimenter
Réglez l’âge après vieillissement, la nutrition et le tirage. L’atelier isole les règles de maturité et de famine pour les rendre reproductibles ; l’espérance de vie est fixée à 250 jours.
Lire le résultat de l’expérience initiale
La femelle survit et peut avoir 2 descendants.
Cette projection utilise le moteur amélioré : seules les survivantes se reproduisent. Le contrôle de maturité porte sur l’âge après vieillissement.
| Condition | Résultat |
|---|---|
| Âge <250 | true |
| Nutrition0 et tirage<1/3 | false |
| Âge≥20 et nutrition≥2 | true |
Un simulateur aléatoire devient testable quand on isole ses décisions et impose les tirages.
Revoir les notions de cet exercice
Du sujet à la méthode
Votre prochaine séance de révision
- Recréer les objets pour chaque expérience.
- Tester les probabilités par leurs seuils avant d’observer une simulation complète.
Retrouver ces notions dans d’autres sujets
Toutes les annales de NSI · Le guide pour préparer le bac NSI 2027
Énoncé : sujet 26_BCG_NSI_7 (PDF). Corrigé et explications pédagogiques proposés par Sofien.
