Project: Step 3.4
Spring is here!
Disclaimer: the automatically generated English translation is provided only for convenience and it may contain wording flaws. The original French document must be taken as reference!
Goals: Animals reproduce. Of course, we will apply the necessary segregation rules: we will not allow lizards to marry scorpions or cacti...
After coding the previous parts, you should have enough experience to have more freedom in coding this section.
The instructions are therefore less detailed than in the previous sections.
Who is interested in whom
Just as animals are selective about food, they are also selective in choosing a mate.
A "double dispatch" mechanism, similar to the one implemented for food, must be implemented for organic entities:
virtual bool matable(OrganicEntity const* other) const = 0; virtual bool canMate(Scorpion const* scorpion) const = 0; virtual bool canMate(Lizard const* lizard) const = 0; virtual bool canMate(Cactus const* food) const = 0;
The method matable should return true if this can have other as a reproductive partner.
For example, Lizard::matable(OrganicEntity const* other) const will return: other->canMate(this); (similar to what was done for food selection).
The method canMate(Type const* mate) should return true when this is the same type as mate, when this and mate are of opposite sexes, when mate is not pregnant or giving birth, when it has enough energy to reproduce, and when it is old enough to do so. All this must be done without type testing!
- The threshold values for energy are configurable and accessible via getAppConfig().lizard_energy_min_mating_female, getAppConfig().lizard_energy_min_mating_male (with equivalents for scorpions).
- The minimum age for reproduction is also configurable and is given by getAppConfig().lizard_min_age_mating and getAppConfig().scorpion_min_age_mating.
Test 20: Reproduction ("double dispatch")
A non-graphical test, similar to the one provided for food consumption, is available in the file MatableTest.cpp in the directory src/Tests/unitTests.
Open this test and examine it to understand what it does. Running it using the target matableTest should produce the following output:
./build/MatableTest
Using ./build/../res/app.json for configuration.
===============================================================================
All tests passed (38 assertions in 2 test cases)
Adjusting the updateState Method
Among the organic entities present in its field of vision, the animal must now also consider potential mates for reproduction.
So far, for food, the animal:
- Selects the nearest target to eat.
- If there is one:
- It switches to FEEDING mode and consumes it if in contact.
- Otherwise, it switches to FOOD_IN_SIGHT mode.
- If no food is in sight, it switches to WANDERING mode.
Now, something very similar needs to be done for mates:
- Select the nearest potential mate.
- If there is one:
- Switch to MATING mode if there is a meeting (i.e., collision) and ... handle the encounter (not very romantic, but it's computer science after all).
- Otherwise, switch to MATE_IN_SIGHT mode, registering the partner as a target.
- etc.
- Reproduction takes priority over food consumption. If the animal sees both food and a mate, it will prioritize the mate (switching to MATING or MATE_IN_SIGHT first).
- The updateState method must now handle multiple tasks: determining the nearest food source and the nearest mate. Later, it will also have to identify the closest enemy. As suggested before, it may be useful to program a method analyzeEnvironment to differentiate among the entities seen—determining which one is food, which one is a potential mate, and which one is an enemy. This information can be stored in the animal's "memory" as attributes.
If targets are at the same distance, the selection of which one to prioritize is left to your discretion.
Encounter
We mentioned earlier about "managing the encounter" ... here we are.
Simply put, we have a potential partner, mate, stored in an OrganicEntity* and we want to implement a meet method to handle the encounter between this and mate.
[Question Q3.12] How do you propose to use "double dispatch" to implement the meet method without using type testing? Answer this question in your REPONSES file.
The meet method should properly handle the encounter between an animal and any type of organic entity : only the meet method applied to partners of the same type should result in births.
The following algorithm will be implemented to handle the situation when two compatible animals meet :
- The female becomes pregnant (marked as such) with a given number of babies. She loses energy proportional to the number of babies carried (getAppConfig().lizard_energy_loss_female_per_child). This anticipates the energy loss during gestation. The number of babies will be randomly generated within two bounds (getAppConfig().lizard_min_children, getAppConfig().lizard_max_children for lizards, with similar parameters for scorpions).
- The male loses energy (getAppConfig().lizard_energy_loss_mating_male);
- The female remains pregnant for a gestation period specific to each animal type (getAppConfig().lizard_gestation_time).
[Question Q3.13] How do you propose to implement the gestation period? Answer this question in your REPONSES file.
It is also necessary to manage the end of the gestation period for pregnant females: when the gestation time is over, the female enters the GIVING_BIRTH state and gives birth to her babies.
Just as the animal had a pause period in the FEEDING state, it will also observe a pause period in the MATING and GIVING_BIRTH states (you can use the parameters getAppConfig().animal_mating_pause_time and getAppConfig().animal_delivery_pause_time).
[Question Q3.14] An animal can only give birth to animals of its type. How do you propose to implement the give_birth method (or equivalent) in the animal hierarchy? Answer this question in your REPONSES file.
[Question Q3.15] How do you store the number of expected babies (useful for implementing the birth process when the gestation period is over)? Answer this question in your REPONSES file.
Reproduction-specific Displays
To facilitate debugging, it is useful to display pregnant females in a special way. Adapt your display methods so that they appear in a specific way, for example (the color sf::Color::Magenta has been used here):
Test 21 : Reproduction
The test file Tests/GraphicalTest/ReproductionTest is provided to test these latest developments. The associated target is reproductionTest. A specific configuration file with favorable conditions for observing reproduction (long lifespan, very low minimum reproduction age, minimal energy loss during movement, etc.) is also provided. This file is reprod.json. This test allows you to:
- Create male lizards using the 'Ctrl-L' key and female lizards using the 'L' key
- Create male scorpions using the 'Ctrl-S' key and female scorpions using the 'S' key
Start by using this test similarly to test 14 (especially in "debugging" mode and by observing the displayed states) to ensure that:
- Lizards target each other for reproduction, scorpions do the same, but only animals of opposite sexes target each other;
- Other interactions only concern the search for food;
- Animals with too little energy or that are too young are not interested in reproduction (remember that you can configure the initial energy of animals or the energy thresholds needed for reproduction);
- Reproduction takes priority over the search for food (to test this, you can temporarily set the minimum reproduction age to zero in reprod.json).
Here is an example of a typical test scenario:
|
Reproduction partners take priority over food (the reproduction age must be set to zero to observe this; otherwise, the partners are too young and will first go towards food).
|
Here is another example of a possible test:
When two lizards of opposite sexes meet, the female becomes pregnant and carries her young for a certain period before giving birth. A pause period is observed during the encounter and at birth (in this case, the lizard gave birth to only one baby, but this is not a general rule). The babies start moving immediately while the mother remains momentarily still in the GIVING_BIRTH state. As a bonus, you are free to enhance the newborns' behavior to make it more realistic (they are smaller than adults, they stay near the mother for a while, etc.).
|
You should verify that the conditions required for reproduction are properly enforced (minimum age, energy levels, pregnant females, or females in labor, etc.). Note that it may be useful initially to make your animals sterile (set the minimum and maximum number of offspring to zero in the configuration file). It is easier to observe that state transitions and behaviors are correct when dealing with only one pair.