mirror of
https://github.com/gsi-upm/soil
synced 2024-11-14 15:32:29 +00:00
104 lines
3.0 KiB
Python
104 lines
3.0 KiB
Python
|
import logging
|
||
|
from soil.agents import NetworkAgent, FSM, state, default_state, BaseAgent
|
||
|
from enum import Enum
|
||
|
from random import random, choice
|
||
|
from itertools import islice
|
||
|
|
||
|
logger = logging.getLogger(__name__)
|
||
|
|
||
|
class Genders(Enum):
|
||
|
male = 'male'
|
||
|
female = 'female'
|
||
|
|
||
|
|
||
|
class RabbitModel(NetworkAgent, FSM):
|
||
|
|
||
|
defaults = {
|
||
|
'age': 0,
|
||
|
'gender': Genders.male.value,
|
||
|
'mating_prob': 0.001,
|
||
|
'offspring': 0,
|
||
|
}
|
||
|
|
||
|
sexual_maturity = 4*30
|
||
|
life_expectancy = 365 * 3
|
||
|
gestation = 33
|
||
|
pregnancy = -1
|
||
|
max_females = 10
|
||
|
|
||
|
@default_state
|
||
|
@state
|
||
|
def newborn(self):
|
||
|
self['age'] += 1
|
||
|
|
||
|
if self['age'] >= self.sexual_maturity:
|
||
|
return self.fertile
|
||
|
|
||
|
@state
|
||
|
def fertile(self):
|
||
|
self['age'] += 1
|
||
|
if self['age'] > self.life_expectancy:
|
||
|
return self.dead
|
||
|
|
||
|
if self['gender'] == Genders.female.value:
|
||
|
return
|
||
|
|
||
|
# Males try to mate
|
||
|
females = self.get_agents(state_id=self.fertile.id, gender=Genders.female.value, limit_neighbors=False)
|
||
|
for f in islice(females, self.max_females):
|
||
|
r = random()
|
||
|
if r < self['mating_prob']:
|
||
|
self.impregnate(f)
|
||
|
break # Take a break
|
||
|
|
||
|
def impregnate(self, whom):
|
||
|
if self['gender'] == Genders.female.value:
|
||
|
raise NotImplementedError('Females cannot impregnate')
|
||
|
whom['pregnancy'] = 0
|
||
|
whom['mate'] = self.id
|
||
|
whom.set_state(whom.pregnant)
|
||
|
logger.debug('{} impregnating: {}. {}'.format(self.id, whom.id, whom.state))
|
||
|
|
||
|
@state
|
||
|
def pregnant(self):
|
||
|
self['age'] += 1
|
||
|
if self['age'] > self.life_expectancy:
|
||
|
return self.dead
|
||
|
|
||
|
self['pregnancy'] += 1
|
||
|
logger.debug('Pregnancy: {}'.format(self['pregnancy']))
|
||
|
if self['pregnancy'] >= self.gestation:
|
||
|
|
||
|
state = {}
|
||
|
state['gender'] = choice(list(Genders)).value
|
||
|
child = self.env.add_node(self.__class__, state)
|
||
|
self.env.add_edge(self.id, child.id)
|
||
|
self.env.add_edge(self['mate'], child.id)
|
||
|
# self.add_edge()
|
||
|
logger.info("A rabbit has been born: {}. Total: {}".format(child.id, len(self.global_topology.nodes)))
|
||
|
self['offspring'] += 1
|
||
|
self.env.get_agent(self['mate'])['offspring'] += 1
|
||
|
del self['mate']
|
||
|
self['pregnancy'] = -1
|
||
|
return self.fertile
|
||
|
|
||
|
@state
|
||
|
def dead(self):
|
||
|
logger.info('Agent {} is dying'.format(self.id))
|
||
|
if 'pregnancy' in self and self['pregnancy'] > -1:
|
||
|
logger.info('A mother has died carrying a baby!: {}!'.format(self.state))
|
||
|
self.die()
|
||
|
return
|
||
|
|
||
|
|
||
|
class RandomAccident(BaseAgent):
|
||
|
|
||
|
def step(self):
|
||
|
logger.debug('Killing some rabbits!')
|
||
|
prob_death = self.env.get('prob_death', -1)
|
||
|
for i in self.env.network_agents:
|
||
|
r = random()
|
||
|
if r < prob_death:
|
||
|
logger.info('I killed a rabbit: {}'.format(i.id))
|
||
|
i.set_state(i.dead)
|