summaryrefslogtreecommitdiff
path: root/graphs/cpp/caste_or_cast/colony.cc
blob: 2c0697aab307918d6742a9d6e032e63d24dbad86 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include "colony.hh"

#include <iostream>

#include "nurturer.hh"
#include "provider.hh"

Colony::Colony(uint32_t passport)
    : passport_pheromone_(passport)
    , workers_()
{}
bool Colony::addAnt(const Ant& ant, std::shared_ptr<Colony> colony)
{
    auto q = dynamic_cast<const Queen*>(&ant);
    if (q)
    {
        if (colony->queen_ || q->get_stage() != DevelopmentStage::ADULT)
            return false;
        colony->queen_ = std::make_unique<Queen>(*q);
        return true;
    }
    auto n = dynamic_cast<const Nurturer*>(&ant);
    if (n)
    {
        colony->workers_.push_back(std::make_shared<Nurturer>(*n));
        return true;
    }
    auto p = dynamic_cast<const Provider*>(&ant);
    if (p)
    {
        colony->workers_.push_back(std::make_shared<Provider>(*p));
        return true;
    }
    return false;
}

void Colony::manageQueen()
{
    if (queen_ == nullptr)
        throw std::runtime_error("Cannot manage a colony without a Queen.");
    // check if the queen should lose health points
    if (queen_->food_level_ < 0)
        queen_->hp_ -= 1;
    if (queen_->hp_ <= 0)
    {
        queen_ = nullptr;
        throw std::runtime_error("The Queen died.");
    }
    // Append to workers_ all the new workers contained in the queen's
    // eggs_queue_
    while (!queen_->eggs_queue_.empty())
    {
        //! we insert eggs that were laid by the queen
        workers_.emplace_back(queen_->eggs_queue_.front());
        queen_->eggs_queue_.pop();
    }
}

void Colony::removeDeadWorkers()
{
    auto dead_count = std::erase_if(
        workers_, [](const std::shared_ptr<Worker> w) { return w->hp_ <= 0; });
    if (dead_count > 0)
    {
        std::cout << dead_count << " workers_ died.\n";
        // each dead worker decrease the cleanliness of the colony
        cleanliness -= 0.5 * dead_count;
    }
}

// this method can be considered as one round of management
void Colony::manageAnts()
{
    // We first manage the queen
    manageQueen();
    // We remove all dead workers contained in workers_
    removeDeadWorkers();
    std::cout << "-- THERE ARE " << workers_.size() << " WORKERS --\n";
    // We iterate over all workers
    for (auto worker : workers_)
    {
        if (worker->stage_ == DevelopmentStage::ADULT)
        {
            /*
             * Because work() is a virtual method, dynamic dispatch will be
             * used. Which means that the overridden work method of the true
             * type (either Nurturer or Provider) will actually be called
             * instead of Worker::work().
             */
            worker->work();
        }
        else
        {
            /*
             * We increment their food_level_ as if it is a ticking time,
             * EXCEPT for the larvae, as they are fed by nurturers.
             */
            if (worker->stage_ != DevelopmentStage::LARVA)
                worker->food_level_ += 1;
            if (worker->food_level_ >= 4.0)
            {
                /* FIXME : Make the worker change stage_ and reset their
                 * food_level_ to 0. HINT : This can take only 2/3 lines if
                 * you use a certain C++ cast instead of a switch.
                 */
                worker->food_level_ = 0;
                auto ant = static_cast<Ant*>(worker.get());
                ant->stage_ = static_cast<DevelopmentStage>(
                    static_cast<int>(ant->stage_) + 1);
            }
        }
    }
    queen_->food_level_ -= 0.2;
}

// FIXME : Implements addAnt() static method.