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!

Warning The proposed implementation of matable only checks if this can reproduce with other and not the other way around. Two partners p1 and p2 can only reproduce if p1->matable(p2) and p2->matable(p1) (one call alone is not enough to confirm mutual agreement :-/).

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)

  
It is not yet possible to verify that pregnant potential partners should not be considered as valid targets. Testing this situation would require coding a "setter" to force some females to be recorded as pregnant, allowing "conceptions" without an actual father. We do not want to get into theological debates or break encapsulation. The case of pregnant females will therefore be tested later (with a graphical test).

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:

  1. Selects the nearest target to eat.
  2. If there is one:
    1. It switches to FEEDING mode and consumes it if in contact.
    2. Otherwise, it switches to FOOD_IN_SIGHT mode.
  3. If no food is in sight, it switches to WANDERING mode.

Now, something very similar needs to be done for mates:

  1. Select the nearest potential mate.
  2. If there is one:
    1. 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).
    2. Otherwise, switch to MATE_IN_SIGHT mode, registering the partner as a target.
  3. etc.

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 meet method should have no effect when applied to pairs of organic entities that are not compatible for reproduction.

The following algorithm will be implemented to handle the situation when two compatible animals meet :

  1. 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).
  2. The male loses energy (getAppConfig().lizard_energy_loss_mating_male);
  3. The female remains pregnant for a gestation period specific to each animal type (getAppConfig().lizard_gestation_time).
The syntax uniform(min, max) allows random generation of a positive integer between the min and max bounds. The uniform function is defined in the provided material in the Random/ directory.

[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.

Once the babies are born, they must, of course, be integrated into the environment.

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):

Model

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:

Start by using this test similarly to test 14 (especially in "debugging" mode and by observing the displayed states) to ensure that:

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.


Return to the project statement (part 3) Next module (part 3.5)