class Petale:
"""
Une classe que l'on utilise pour représenter des pétales de fleurs
Leur durée de vie est de 20 jours et ils fanent au bout de 15.
On s'intéresse aussi à leur couleur
...
Attributes
----------
age : int
un entier qui représente l'age du pétale, initiallement nul.
Methods
-------
vieillir()
On incrémente l'age du pétale de 1.
Si le pétale est toujours accroché, renvoit vrai.
Sinon, renvoit faux.
couleur()
Il s'agit de la couleur du pétale :
- rouge si il est non fané
- marron si il l'est
"""
def __init__(self,age=0):
"""
Parameters
----------
Age : int
L'age du pétale
"""
self.age = age
def vieillir(self):
"""
Fait vieillir le pétale de 1 en incrémentant son age.
Retourne vrai ou faux selon l'age du pétal :
- Si le pétale possède un age supérieur à 20, retourne faux car le pétale se détache
- Sinon, il renvoit vrai.
"""
self.age+=1
if self.age >= 20 :
return(False)
return(True)
def couleur(self):
"""
Retourne la couleur du pétale en fonction de son âge :
- Marron si il est fané (age>15)
- Rouge si il ne l'est pas (age<15)
"""
if self.age>=15:
return("marron")
return("rouge")
import random
from petale import Petale
class Fleur:
"""
Une classe que l'on utilise pour représenter les fleurs
On s'intéresse à leur age en jours et a leur statut de fécondité qui determine leur état :
— âge jusqu’à 15 jours : en fleur
— âge entre 16 et 20 jours : fanant
— âge entre 21 et 30 jours, et fécondée : fruit
— âge plus de 21 jours non fécondée, ou plus de 31 jours : tombée
...
Attributes
----------
age : int
un entier qui représente l'age de la fleur, initiallement nul.
fecondee : bool
Un booléen qui determine si la fleur a été fécondée
Methods
-------
est_fanant()
Permet de savoir si la fleur est en train de faner ou non.
est_fruit()
Permet de savoir si la fleur est au stade de fruit ou non.
vieillir()
Permet d'incrémenter l'age de la fleur de 1 jour.
"""
def __init__(self, age = 0, fecondee = False, probaf = 10, probat = 0.1):
"""
Parameters
----------
age : int
L'age de la fleur
fecondee: bool
La fleur est elle fécondée ?
probaf : float
La probabilité qu'une fleur soit butinée (et donc qu'elle devienne fécondée) en pourcentage
probat : float
La probabilité qu'une fleur tombe spontanément de l'arbre (Vent,animal...) en pourcentage
"""
self.age = age
self.fecondee = fecondee
self.probaf = probaf
self.probat = probat
self.__petales = [Petale() for k in range(10)]
def est_fanant(self):
"""
Donne l'état de la fleur (est-elle fanante ou non ?)
"""
return(15<self.age<21)
def est_fruit(self):
"""
Détermine si la fleur est à l'état de fruit (suffisament agée et fécondée)
"""
return(21<self.age and self.fecondee)
def vieillir(self, probaf = 10, probat = 0.1):
"""
Incrémente l'age de la fleur de une journée et modifie son état en conséquence (Mise à jour du statut des pétales)
Selon les probabilités choisies, le statut de la fleur sera aussi influencé :
- elle peut tomber si son age dépasse 32 ou spontanément
- elle peut rester fécondée ou le devenir avec une probabilité définie
On peut mettre à jour ces probabilités en début de cette méthode ou conserver les probabilitées existantes
Parameters
----------
probaf:
La nouvelle probabilité d'être butinée (Vaut initiallement l'ancienne) (en pourcentage)
probat :
La nouvelle probabilité de tomber spontanément (Vaut initiallement l'ancienne) (en pourcentage)
------
"""
self.probaf = probaf
self.probat = probat
if self.age < 32 :
self.age += 1
for k in range(10) :
Petale.vieillir(self.__petales[k])
self.fecondee = (self.fecondee or (self.age<15 and (random.random() < self.probaf/100)))
if random.random() < (self.probat/100) :
self.age = 32
return((self.age<22) or (self.age<32 and self.fecondee))
def couleur(self):
"""
Retourne un dictionnaire qui contient les couleurs de la fleur
Si c'est un fruit : il est orange, on met 1 dans orange
Sinon, on renvoit les couleurs pétale par pétale avec la formule suivante :
le coeur : 1/(1+nb_petales)
les pétales : nb_petales/(1+ nb_petales)
Le total des valeurs du dictionnaire est donc toujours égal à 1 (des proportions)
"""
if 21<self.age<32 and self.fecondee :
return {"orange": 1}
return({"jaune": 1/(1+len(self.__petales)), Petale.couleur(self.__petales[0]): len(self.__petales)/(1+len(self.__petales))})
import random
class Feuille:
"""
Cette classe permet de représenter une feuille de l'arbre
On s'intéresse à l'age et à la couleur
Le statut détermine si la feuille est séchante (et depuis combien de temps) ou vivante
...
Attributes
----------
sechant : int
Le nombre de jour pendant lesquels la feuille a séché sur la branche en automne
Methods
-------
statut()
renvoie "vivante" si la feuille est accrochée et ne sèche pas, "séchante" sinon.
vieillir()
Renvoie vrai ou faux selon si la feuille est encore attachée à la branche
couleur()
renvoie "vert" si la feuille est vivante, "jaune" si elle sèche depuis au plus 5 jours, "marron" sinon.
"""
def __init__(self,sechant=0):
"""
Parameters
----------
sechant: int
Le nombre de jour pendant lequel la feuille a sèché
"""
self.sechant = sechant
def statut(self):
"""
renvoie "vivante" si la feuille est accrochée et ne sèche pas, "séchante" sinon.
"""
if self.sechant == 0 :
return('vivante')
return('séchante')
def vieillir(self,saison, hiv = 100, pri = 0, ete = 0, aut = 5) :
"""
Renvoie vrai si la feuille est toujours accrochée, faux sinon
De manière aléatoire : la feuille peut commencer à sécher avec des probabilités determinables. (en pourcentage)
Parameters
----------
Saison : int
Les saisons dans l'ordre de 0 à 3 : Hiver, printemps, été, automne
hiv : float, optional
La probabilité que la feuille commence à sécher spontanément en hiver
pri : float, optional
La probabilité que la feuille commence à sécher spontanément au printemps
ete : float, optional
La probabilité que la feuille commence à sécher spontanément en été
aut : float, optional
La probabilité que la feuille commence à sécher spontanément en automne
"""
proba_sais = [hiv,pri,ete,aut]
#Continuer à sécher :
if 0<self.sechant<11 :
self.sechant += 1
#Commencer à sécher :
elif random.random() < proba_sais[saison]/100 :
self.sechant = 1
#Tomber naturellement :
if random.random()< 0.05/100 :
self.sechant += 1
return(self.sechant<11)
def couleur(self):
"""
renvoie "vert" si la feuille est vivante
"jaune" si elle sèche depuis au plus 5 jours
"marron" sinon
"""
if self.sechant == 0 :
return('vert')
if self.sechant < 6 :
return('jaune')
return('marron')
from petale import Petale
from fleur import Fleur
from feuille import Feuille
import random
class Branche:
"""
Une classe utilisée pour représenter une branche et ses caractéristiques
On s'intéresse à son épaisseur et à son angle par rapport à la branche mère
...
Attributes
----------
epaisseur : float
L'épaisseur de la branche qui vaut 5 à l'origine
angle : float
L'angle par rapport à la branche parente
Methods
-------
nb_branches()
retourne le nombre de branches filles
nb_feuilles()
retourne le nombre de feuilles de la branche, ou de ses branches filles (et de leurs branches filles, etc.)
nb_fleurs()
retourne le nombre de fleurs (qui ne sont pas des fruits) de la branche, ou de ses branches filles (et de leurs branches filles, etc.)
nb_fruits()
retourne le nombre de fruits de la branche, ou de ses branches filles (et de leurs branches filles, etc.)
vieillir(saison)
renvoie vrai si la branche est encore accrochée, faux sinon. Retourne aussi le nombre de fruits tombés au sol.
"""
def __init__(self,angle,epaisseur=5,__feuille = [Feuille()],__fleur = [],__branche = []):
"""
Parameters
----------
angle : float
L'angle formé avec la branche mère
epaisseur : float
L'épaisseur initiale de la branche
feuille : list
La liste des feuille de la branche
fleur : list
La liste des fleurs de la branche
branche : list
La liste des branches filles de cette branche
"""
self.epaisseur = 5
self.angle = angle
self.__feuille = [Feuille()]
self.__fleur = []
self.__branche = []
def nb_branches(self):
"""
Retourne le nombre de branches filles attachées à cette branche
"""
return(len(self.__branche))
def nb_feuilles(self):
"""
Retourne le nombre de feuilles attachées à cette branche
Soit il n'y a pas de branches filles, on ne rentre pas dans la boucle et on renvoit le nombre de feuilles
Soit il y a des branches filles, (qui peuvent elle même en avoir, etc), et on rentre dans l'algorithme récursif
On va descendre la structure d'arbre afin d'aller récupérer l'information des branches inférieures et remonter en sommant toutes les feuilles
"""
s = 0
for branche_fille in self.__branche :
s = s + branche_fille.nb_feuilles()
return(len(self.__feuille) + s )
def nb_fleurs(self):
"""
Retourne le nombre de fleurs (qui ne sont pas des fruits) attachées à cette branche
Soit il n'y a pas de branches filles, on ne rentre pas dans la boucle et on renvoit le nombre de feuilles
Soit il y a des branches filles, (qui peuvent elle même en avoir, etc), et on rentre dans l'algorithme récursif
On va descendre la structure d'arbre afin d'aller récupérer l'information des branches inférieures et remonter en sommant les fleurs
C'est la même procédure que pour compter les feuilles avec les fleurs.
"""
s = 0
for branche_fille in self.__branche :
s = s + branche_fille.nb_fleurs()
return(len([f for f in self.__fleur if not(Fleur.est_fruit(f))]) + s)
def nb_fruits(self):
"""
Retourne le nombre de fruits attachés à cette branche
Soit il n'y a pas de branches filles, on ne rentre pas dans la boucle et on renvoit le nombre de feuilles
Soit il y a des branches filles, (qui peuvent elle même en avoir, etc), et on rentre dans l'algorithme récursif
On va descendre la structure d'arbre afin d'aller récupérer l'information des branches inférieures et remonter en sommant les fleurs
C'est la même procédure que pour compter les feuilles avec les fruits.
"""
s = 0
for branche_fille in self.__branche :
s = s + branche_fille.nb_fruits()
return(len([f for f in self.__fleur if f.est_fruit()]) + s)
def vieillir(self,saison, casse = 0.1, fleurp = 1.5, feuillep = 3):
"""
La branche a une probabilité de casser qui dépend de l'épaisseur, on retourne alors faux et le nombre de fruits sur la branche et ses branches filles (tuple en Python).
Sinon, l'épaisseur grossit de 0.015.
Les feuilles vieillissent, et si elles tombent, elles sont retirées de la liste correspondante.
Les fleurs vieillissent, et si un fruit tombe, il est comptabilisé pour retourner le nombre de fruits tombés.
Chaque jour, les branches filles vieillissent, et les fruits tombés de ces branches sont comptabilisés. Si une branche fille casse, elle est retirée de la liste correspondante.
Au printemps, si la branche n’a ni feuille, ni fleur, ni branche fille, alors entre 2 et 5 branches sont créées, avec des angles aléatoires.
Au printemps, si la branche a au moins une feuille, la branche peut voir pousser des feuilles et des fleurs. Une feuille est ajoutée avec probabilité feuillep (en pourcentage). Une fleur est ajoutée avec une probabilité fleurp (en pourcentage)
Parameters
----------
saison : int
La saison en cours (de 0 pour hiver à 3 pour l'automne)
casse : float, optional
Un paramètre qui permet de changer la probabilité de casser la branche spontanément
fleurp : float, optional
La probabilité de voir pousser une fleur au printemps
feuillep : float, optional
La probabilité de voir pousser une feuille au printemps
"""
probac = 0.1 / self.epaisseur
#Si on casse :
if random.random()< probac/100:
return(False,Branche.nb_fruits(self) + sum([Branche.nb_fruits(b) for b in self.__branche]))
#Sinon, on grossit :
self.epaisseur+=0.015
#On fait vieillir les feuilles et on retire celles mortes :
j=0
for k in range(len(self.__feuille)) :
if len(self.__feuille) == 0 :
break
if not(Feuille.vieillir(self.__feuille[k-j],saison)) :
del self.__feuille[k-j]
j+=1
#On fait vieillir les fleurs et on compte les fruits si ils tombent
F = 0
j=0
for k in range(len(self.__fleur)) :
if len(self.__fleur) == 0 :
break
B1 = self.__fleur[k-j].vieillir()
if not(B1) and self.__fleur[k-j].est_fruit() :
F += 1
if not(B1) :
del self.__fleur[k-j]
j+=1
#On fait vieillir les branches filles qui peuvent casser et on compte leurs fruits
j=0
for k in range(len(self.__branche)) :
if len(self.__branche) == 0 :
break
L1 = self.__branche[k-j].vieillir(saison)
if not(L1[0]) :
F += L1[1]
del self.__branche[k-j]
j+=1
# Des nouvelles branches/feuilles/fleurs peuvent pousser au printemps:
if saison == 1 and self.nb_feuilles() == 0 and self.nb_fleurs() == 0 and self.nb_branches() == 0:
for k in range(random.randint(2,5)):
self.__branche.append(Branche(random.randint(-90,90)))
if (saison == 1) and (Branche.nb_feuilles != 0) :
if random.random()< (feuillep/100) :
self.__feuille.append(Feuille())
if random.random() < (fleurp/100) :
self.__fleur.append(Fleur())
return(True,F)
def couleur(self) :
"""
Renvoit un dictionnaire contenant la proportion de chaque couleur sur la branche
Utilise la fonction somme_dic pour sommer deux dictionnaires ayant des clés communes (ou non).
"""
def somme_dic(d1,d2) :
for key in d2 :
if key in d1 :
d1.update({ key : d1[key] + d2[key] })
else :
d1.update({key : d2[key]})
dic = {"marron" : 0,"orange" : 0,"jaune" : 0,"rouge" : 0,"vert" : 0}
nbranches = len(self.__branche) + 1
nfeuilles = len(self.__feuille)
nfleurs = len(self.__fleur)
N = nbranches + nfeuilles + nfleurs
#Pour les branches filles
dicbs = {"marron" : self.epaisseur/5,"orange" : 0,"jaune" : 0,"rouge" : 0,"vert" : 0}
for k in range(nbranches-1):
dicb = Branche.couleur(self.__branche[k])
somme_dic(dicbs,dicb)
#Un dictionnaire contenant la proportion de branches de chaque couleur
s=0
for key in dicbs :
s = s + dicbs[key]
for key in dicbs :
dicbs.update({key : dicbs[key]/s})
#Pour les feuilles :
dicfes = {"marron" : 0,"orange" : 0,"jaune" : 0,"rouge" : 0,"vert" : 0}
for k in range(nfeuilles):
keyfe = Feuille.couleur(self.__feuille[k])
dicfes.update({keyfe : dicfes[keyfe]+1})
#Un dictionnaire contenant la proportion de feuilles de chaque couleur
for key in dicfes :
if not(nfeuilles == 0) :
dicfes.update({key : dicfes[key]/nfeuilles})
else :
dicfes.update({key : 0})
#Pour les fleurs :
dicfls = {"marron" : 0,"orange" : 0,"jaune" : 0,"rouge" : 0,"vert" : 0}
for k in range(nfleurs):
dicfl = Fleur.couleur(self.__fleur[k])
somme_dic(dicfls,dicfl)
for key in dicfls :
dic.update({key : dicfls[key]})
#On somme ensuite les proportions sur la branche:
for key in dic :
dic.update({ key : (nbranches*dicbs[key] + nfeuilles*dicfes[key] + nfleurs*dicfls[key])/N})
return(dic)
from feuille import Feuille
from branche import Branche
class Arbre(Branche):
"""
Une classe qui représente un arbre composé de branches
On s'intéresse à son angle et à ses coordonées
...
Attributes
----------
angle : float
l'angle de la branche initiale
coordonees : tuple
la position de l'arbre dans la forêt
"""
def __init__(self,coordonnees,angle=0,epaisseur=5,__feuille = [Feuille()],__fleur = [],__branche = []):
"""
Parameters
----------
angle : float
l'angle de la branche
coordones: tuple
Les coordonees géographiques de l'arbre
"""
self.angle = 0
self.coordonnees = coordonnees
super().__init__(epaisseur,__feuille,__fleur,__branche)
from branche import Branche
from arbre import Arbre
import random
class Foret:
"""
Une classe pour représenter les arbres dans une forêt
...
Attributes
----------
saison : int
Permet de définir la saison (0 pour Hiver à 3 pour Automne)
jour_saison: int
De 0 à 91, définit quel est le jour de la saison
nb_graines : str
Le nombre de fruits tombés l'année précédente à la même époque
Methods
-------
__add__()
Permet de faire vieillir la forêt d'un nombre de jour donné en utilisant le symbole +
couleur()
Permet d'obtenir les proportions de chaque couleur dans la forêt
"""
def __init__(self, graines, nb_arbres,__arbres = [],fruits = 0,jour = 1, saisonf = 1,probga = 0.1):
"""
Parameters
----------
saisonf : int
La saison en cours (de 0 pour l'hiver à 3 pour l'automne)
jour : str, optional
Le jour actuel (de 0 à 91)
graines : int, optional
Le nombre de graines
nb_arbres : int, optional
Le nombre d'arbres
probga : float
La probabilité qu'une graine donne un arbre
fruits : int
Le nombre de fruits dans la forêt
"""
self.fruits = fruits
self.saison = saisonf
self.jour = jour
self.graines = graines
self.nb_arbres = nb_arbres
self.probga = probga
self.__arbres = [Arbre((random.random(),random.random())) for i in range(self.nb_arbres)]
def __add__(self,jours=1) :
"""
Permet de faire vieillir la forêt d'un certain nombre de jours en une seule commande
Parameters
----------
jours : int, optional
Le nombre de jours dont la forêt vieilli
"""
#on fait vieillir les arbres et on compte les fruits
for k in range(jours) :
F=0
j=0
for k in range(len(self.__arbres)) :
if len(self.__arbres) == 0 :
break
L1 = Branche.vieillir(self.__arbres[k-j],self.saison)
if not(L1[0]):
del self.__arbres[k-j]
F+=L1[1]
j+=1
if L1[0]:
F+=L1[1]
self.graines += F
#on fait pousser les graines au début du printemps
if (0<self.jour<16 and self.saison == 1):
for g in range(self.graines):
if random.random()<self.probga :
self.graines -= 1
self.nb_arbres += 1
self.__arbres.append(Arbre((random.random(),random.random())))
#on change de jour et de saison si besoin
self.jour += 1
if self.jour == 91 :
self.jour = 1
self.saison += 1
if self.saison == 4:
self.saison = 0
self.fruits = F
def couleur(self):
"""
Permet de calculer les proportions des couleurs dans la forêt à un instant donné
On utilise la somme des dictionnaires avant de recalculer une moyenne pondéré.
Une feuille possède le même poids qu'une branche et qu'une fleur (ainsi qu'un fruit).
"""
def somme_dic(d1,d2) :
for key in d2 :
if key in d1 :
d1.update({ key : d1[key] + d2[key] })
else :
d1.update({key : d2[key]})
dic = {"marron" : 0,"orange" : 0,"jaune" : 0,"rouge" : 0,"vert" : 0}
narbres = len(self.__arbres)
for k in range(narbres):
dica = Branche.couleur(self.__arbres[k])
somme_dic(dic,dica)
for key in dic :
dic.update({key : dic[key]/narbres})
return dic
def __str__(self):
"""
permet un affichage des informations de la forêt
"""
Tb=0
Tfe=0
Tfl=0
n=len(self.__arbres)
for k in range(len(self.__arbres)):
Tb += Branche.nb_branches(self.__arbres[k])
Tfe += Branche.nb_feuilles(self.__arbres[k])
Tfl += Branche.nb_fleurs(self.__arbres[k])
Tb = Tb/n
Tfe = Tfe/n
Tfl = Tfl/n
dic = Foret.couleur(self)
modele = '\n'.join([
'{}',
' saison : {}',
' jour : {}',
' fruits du jour : {}',
' nombre d arbres : {}',
' moyenne du nombre de branches par arbre : {}',
' moyenne du nombre de feuilles par arbre: {}',
' moyenne du nombre de fleurs par arbre: {}',
' marron : {}',
' orange : {}',
' jaune : {}',
' rouge : {}',
' vert : {}'])
return modele.format(
type(self).__name__,
self.saison,
self.jour,
self.fruits,
self.nb_arbres,
Tb,
Tfe,
Tfl,
dic["marron"],
dic["orange"],
dic["jaune"],
dic["rouge"],
dic["vert"])
from petale import Petale
from fleur import Fleur
from feuille import Feuille
from branche import Branche
from arbre import Arbre
from foret import Foret
#test des classes
a=Petale()
f=Fleur()
b=Branche(2)
fe=Feuille(11)
A=Arbre(0,1)
F=Foret(20,20)
#test de l'évolution d'une forêt sur 100 jours
for i in range (2000):
F + 1
if F.fruits != 0 :
print(F)
print(i)