diff options
| author | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:08:27 +0200 |
|---|---|---|
| committer | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:08:27 +0200 |
| commit | c9b6b9a5ca082fe7c1b6f58d7713f785a9eb6a5c (patch) | |
| tree | 3e4f42f93c7ae89a364e4d51fff6e5cec4e55fa9 /graphs/cpp/caste_or_cast | |
add: graphs et rushs
Diffstat (limited to 'graphs/cpp/caste_or_cast')
| -rw-r--r-- | graphs/cpp/caste_or_cast/Makefile | 15 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/ant.cc | 87 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/ant.hh | 70 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/colony.cc | 116 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/colony.hh | 43 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/main_example.cc | 37 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/nurturer.cc | 98 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/nurturer.hh | 27 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/provider.cc | 47 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/provider.hh | 29 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/queen.cc | 30 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/queen.hh | 32 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/worker.cc | 28 | ||||
| -rw-r--r-- | graphs/cpp/caste_or_cast/worker.hh | 30 |
14 files changed, 689 insertions, 0 deletions
diff --git a/graphs/cpp/caste_or_cast/Makefile b/graphs/cpp/caste_or_cast/Makefile new file mode 100644 index 0000000..c49f282 --- /dev/null +++ b/graphs/cpp/caste_or_cast/Makefile @@ -0,0 +1,15 @@ +CXX ?= g++ +CXXFLAGS= -std=c++20 -Wall -Wextra -Werror -pedantic \ + -Wold-style-cast + +OBJS = ant.o worker.o nurturer.o provider.o queen.o colony.o main_example.o + +all: my_colony + +my_colony: $(OBJS) + $(CXX) -o $@ $^ + +clean: + $(RM) $(OBJS) my_colony +.PHONY: + clean diff --git a/graphs/cpp/caste_or_cast/ant.cc b/graphs/cpp/caste_or_cast/ant.cc new file mode 100644 index 0000000..2875815 --- /dev/null +++ b/graphs/cpp/caste_or_cast/ant.cc @@ -0,0 +1,87 @@ +#include "ant.hh" + +// The Colony class was forward declared in Ant header +// We need to include its header here so we know Colony implementation +#include "colony.hh" + +Ant::Ant(std::shared_ptr<Colony> colony, DevelopmentStage stage) + : stage_(stage) + , colony_(colony) +{} + +Ant::Ant(const Ant& o) + : stage_(o.stage_) + , colony_(o.colony_) + , hp_(o.hp_) + , food_level_(o.food_level_) +{} + +Ant& Ant::operator=(const Ant& o) +{ + stage_ = o.stage_; + colony_ = o.colony_; + hp_ = o.hp_; + food_level_ = o.food_level_; + return *this; +} + +std::shared_ptr<Colony> Ant::check_colony_access() +{ + std::shared_ptr<Colony> colony = colony_.lock(); + if (colony == nullptr) + throw std::runtime_error("The Colony pointer is expired."); + return colony; +} + +bool Ant::communicate(std::weak_ptr<Ant> wk_receiver) +{ + std::shared_ptr<Ant> receiver = wk_receiver.lock(); + if (receiver == nullptr || stage_ != DevelopmentStage::ADULT + || receiver->get_stage() != DevelopmentStage::ADULT) + return false; + if (receiver->get_passport_pheromone() != get_passport_pheromone()) + return attack(receiver); + return true; +} + +bool Ant::attack(std::weak_ptr<Ant> wk_ant) +{ + if (std::shared_ptr<Ant> ant = wk_ant.lock()) + { + ant->hp_ -= 1; + return true; + } + else + return false; +} + +uint32_t Ant::get_passport_pheromone() +{ + auto c = check_colony_access(); + return c->passport_pheromone_; +} + +DevelopmentStage Ant::get_stage() const +{ + return stage_; +} + +int Ant::get_hp() const +{ + return hp_; +} + +void Ant::set_hp(int hp) +{ + hp_ = hp; +} + +float Ant::get_food_level() const +{ + return food_level_; +} + +void Ant::increment_food_level_by(float value) +{ + food_level_ += value; +} diff --git a/graphs/cpp/caste_or_cast/ant.hh b/graphs/cpp/caste_or_cast/ant.hh new file mode 100644 index 0000000..6a0a0ee --- /dev/null +++ b/graphs/cpp/caste_or_cast/ant.hh @@ -0,0 +1,70 @@ +#pragma once + +#include <memory> + +//! forward declaration +class Colony; + +/* + * Enum Class representing the stage of life for + * an ant + */ +enum class DevelopmentStage : unsigned int +{ + // from the youngest to the oldest stage + EGG = 0, + LARVA, + COCOON, + ADULT +}; + +/* + * Base Class for every ant caste + */ +class Ant +{ +public: + //! delete constructor + Ant() = delete; + //! constructor + Ant(std::shared_ptr<Colony> colony, + DevelopmentStage stage = DevelopmentStage::EGG); + //! copy constructor + Ant(const Ant&); + //! copy assignement + Ant& operator=(const Ant&); + //! default virtual destructor + virtual ~Ant() = default; + //! communicate with another Ant + virtual bool communicate(std::weak_ptr<Ant> wk_receiver); + //! attack given Ant and check if it is dead + bool attack(std::weak_ptr<Ant> wk_ant); + + //! getter for passport_pheromone_ of Colony class + uint32_t get_passport_pheromone(); + //! getter for stage_ + DevelopmentStage get_stage() const; + //! getter for hp_ + int get_hp() const; + //! setter for hp_ + void set_hp(int hp); + //! getter for food_level_ + float get_food_level() const; + //! increment by value food_level_ + void increment_food_level_by(float value); + +protected: + //! return by value the colony shared_ptr if not expired else throw error + std::shared_ptr<Colony> check_colony_access(); + //! development stage + DevelopmentStage stage_; + //! Colony of this Ant + std::weak_ptr<Colony> colony_; + //! health points + int hp_ = 4; + //! represent the energy / food the ant ate for its + // current Development stage + float food_level_ = 0; + //! friend class + friend class Colony; +}; diff --git a/graphs/cpp/caste_or_cast/colony.cc b/graphs/cpp/caste_or_cast/colony.cc new file mode 100644 index 0000000..2c0697a --- /dev/null +++ b/graphs/cpp/caste_or_cast/colony.cc @@ -0,0 +1,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. diff --git a/graphs/cpp/caste_or_cast/colony.hh b/graphs/cpp/caste_or_cast/colony.hh new file mode 100644 index 0000000..917ebf8 --- /dev/null +++ b/graphs/cpp/caste_or_cast/colony.hh @@ -0,0 +1,43 @@ +#pragma once + +#include <vector> + +#include "queen.hh" +#include "worker.hh" + +//! forward declarations +class Provider; +class Nurturer; + +/* + * Colony class that acts as one entity and manage all of its ants + */ +class Colony +{ +public: + //! constructor + Colony(uint32_t passport); + //! static method that adds a COPY of the given ant to the given colony + static bool addAnt(const Ant& ant, std::shared_ptr<Colony> colony); + //! manage all the ants, can be understood as one round + void manageAnts(); + //! overall cleanliness of the colony + float cleanliness = 100; + +private: + //! manage the queen (is alive etc.) + void manageQueen(); + //! remove all the dead workers of the workers_ vector + void removeDeadWorkers(); + //! attribute used to recognise if an Ant is from the same colony + uint32_t passport_pheromone_; + //! vector of all workers of the colony, each worker is stored in a + //! shared_ptr + std::vector<std::shared_ptr<Worker>> workers_; + //! unique queen, only its colony have the ownership of it. + std::unique_ptr<Queen> queen_ = nullptr; + + //! friend classes + friend class Ant; + friend class Nurturer; +}; diff --git a/graphs/cpp/caste_or_cast/main_example.cc b/graphs/cpp/caste_or_cast/main_example.cc new file mode 100644 index 0000000..9708df0 --- /dev/null +++ b/graphs/cpp/caste_or_cast/main_example.cc @@ -0,0 +1,37 @@ +#include <iostream> + +#include "colony.hh" +#include "nurturer.hh" +#include "provider.hh" + +int main() +{ + std::shared_ptr<Colony> myColony = std::make_shared<Colony>(10); + + Queen queen(myColony, DevelopmentStage::ADULT); + queen.increment_food_level_by(3.4); + + std::cout << std::boolalpha << Colony::addAnt(queen, myColony) << " "; + + // create provider with luck_ = 1.32 + Provider provider(myColony, 1.32, DevelopmentStage::ADULT); + + // create nurturer with default luck and 54.289 food_stock_ + Nurturer nurturer(myColony, DevelopmentStage::ADULT); + nurturer.increment_food_stock_by(54.289); + + // create larva with food_level_ = 3 + Provider larva(myColony, DevelopmentStage::LARVA); + larva.increment_food_level_by(3); + + std::cout << std::boolalpha << Colony::addAnt(nurturer, myColony) << " "; + std::cout << std::boolalpha << Colony::addAnt(larva, myColony) << " "; + std::cout << std::boolalpha << Colony::addAnt(provider, myColony) << '\n'; + + for (size_t i = 0; i < 8; i++) + myColony->manageAnts(); + /* + * Don't forget to test the communication methods of your ants. + */ + return 0; +} diff --git a/graphs/cpp/caste_or_cast/nurturer.cc b/graphs/cpp/caste_or_cast/nurturer.cc new file mode 100644 index 0000000..09faa79 --- /dev/null +++ b/graphs/cpp/caste_or_cast/nurturer.cc @@ -0,0 +1,98 @@ +#include "nurturer.hh" + +#include <iostream> + +// The Colony class was forward declared in Ant header +// We need to include its header here so we know Colony implementation +#include "colony.hh" +#include "provider.hh" + +void Nurturer::feedLarvae() +{ + if (food_stock_ < 0.5) + return; + size_t count = 0; + std::shared_ptr<Colony> colony = check_colony_access(); + for (auto i = colony->workers_.begin(); i < colony->workers_.end(); i++) + { + // if it doesn't have food anymore, can't feed more larvae + if (food_stock_ < 0.5) + break; + std::shared_ptr<Worker> worker = *i; + // only feed if it is a larvae and if it is not already full (its + // food_level_ => 4) + if (DevelopmentStage::LARVA == worker->get_stage() + && worker->get_food_level() < 4) + { + worker->increment_food_level_by(0.5); + food_stock_ -= 0.5; + colony->cleanliness -= 0.3; + food_level_ -= 0.03; + count++; + } + } + std::cout << count << " larvae were fed by nurturer.\n"; +} + +void Nurturer::work() +{ + if (stage_ != DevelopmentStage::ADULT) + return; + if (food_stock_ > 0.5) + { + // eat before working + food_level_ += 0.5; + food_stock_ -= 0.5; + // complete its tasks + feedLarvae(); + feedQueen(); + cleanNest(); + } + else + // make the ant more hungry + food_level_ -= 0.042; + //! call base class work() method + Worker::work(); +} +bool Nurturer::communicate(std::weak_ptr<Ant> wk_receiver) +{ + if (wk_receiver.lock() == nullptr) + return false; + if (!Ant::communicate(wk_receiver)) + return false; + std::cout << "Nurturer initiates communication.\n"; + auto p = dynamic_cast<Provider*>(wk_receiver.lock().get()); + if (p) + { + p->transferFood(*this); + } + return true; +} +void Nurturer::feedQueen() +{ + if (food_stock_ < 1) + return; + std::cout << "Feeding Queen.\n"; + auto c = check_colony_access(); + c->queen_->increment_food_level_by(1); + food_stock_--; + if (static_cast<int>(c->queen_->get_food_level()) > 0 + && static_cast<int>(c->queen_->get_food_level()) % 6 == 0) + c->queen_->layEgg(); + c->cleanliness -= .2; +} + +void Nurturer::cleanNest() +{ + std::shared_ptr<Colony> colony = check_colony_access(); + if (colony->cleanliness < 100) + { + // clean the nest according to the luck of the Nurturer + std::cout << "Cleaning nest: gained " << luck_ << " of cleanliness.\n"; + auto cleanliness = colony->cleanliness + luck_; + colony->cleanliness = (cleanliness > 100) ? 100 : cleanliness; + } +} + +// FIXME : Implements communicate(std::weak_ptr<Ant>) virtual overridden method +// and feedQueen() diff --git a/graphs/cpp/caste_or_cast/nurturer.hh b/graphs/cpp/caste_or_cast/nurturer.hh new file mode 100644 index 0000000..af7eec7 --- /dev/null +++ b/graphs/cpp/caste_or_cast/nurturer.hh @@ -0,0 +1,27 @@ +#pragma once + +#include "worker.hh" + +/* + * Nurturers worker sub-caste + */ +class Nurturer : public Worker +{ +public: + //! inherit Worker Constructors + using Worker::Worker; + //! final override of the work() Worker virtual method + void work() override final; + + /*! + * @details final override of the communicate() Ant virtual method + * @return true if the communication succeeded + * */ + bool communicate(std::weak_ptr<Ant> wk_receiver) override final; + //! feed the queen + void feedQueen(); + //! feed larvae + void feedLarvae(); + //! clean the nest / colony + void cleanNest(); +}; diff --git a/graphs/cpp/caste_or_cast/provider.cc b/graphs/cpp/caste_or_cast/provider.cc new file mode 100644 index 0000000..5767743 --- /dev/null +++ b/graphs/cpp/caste_or_cast/provider.cc @@ -0,0 +1,47 @@ +// +// Created by martial.simon on 2/26/25. +// +#include "provider.hh" + +#include <iostream> + +#include "nurturer.hh" +#include "queen.hh" +void Provider::work() +{ + if (stage_ != DevelopmentStage::ADULT) + return; + food_level_ += food_stock_ - static_cast<int>(food_stock_); + food_stock_ -= food_stock_ - static_cast<int>(food_stock_); + harvestFood(); + Worker::work(); +} +void Provider::transferFood(Nurturer& nurturer) +{ + if (food_stock_ < 1) + return; + nurturer.increment_food_stock_by(static_cast<int>(food_stock_)); + food_stock_ -= static_cast<int>(food_stock_); + std::cout << "Transferring food.\n"; +} +void Provider::harvestFood() +{ + float harvest = luck_; + std::cout << "Harvested " << harvest << " food.\n"; + food_stock_ += harvest; + food_level_ -= (harvest - static_cast<int>(harvest)) * 0.5; +} +bool Provider::communicate(std::weak_ptr<Ant> wk_receiver) +{ + if (wk_receiver.lock() == nullptr) + return false; + if (!Ant::communicate(wk_receiver)) + return false; + std::cout << "Provider initiates communication.\n"; + auto p = dynamic_cast<Nurturer*>(wk_receiver.lock().get()); + if (p) + { + transferFood(*p); + } + return true; +}
\ No newline at end of file diff --git a/graphs/cpp/caste_or_cast/provider.hh b/graphs/cpp/caste_or_cast/provider.hh new file mode 100644 index 0000000..5076585 --- /dev/null +++ b/graphs/cpp/caste_or_cast/provider.hh @@ -0,0 +1,29 @@ +#pragma once + +#include "worker.hh" + +//! forward declaration +class Nurturer; + +/* + * Provider worker sub-caste : + * harvest Food in the Outside World and transmit it to + * Nurturers ants + */ +class Provider : public Worker +{ +public: + //! inherit Worker Constructors + using Worker::Worker; + //! final override of the work() Worker virtual method + void work() override final; + //! transfer food to Nurturer workers only + void transferFood(Nurturer& nurturer); + /*! + * @details final override of the communicate() Ant virtual method + * @return true if the communication succeeded + * */ + bool communicate(std::weak_ptr<Ant> wk_receiver) override final; + //! go to the outside world and harvest food + void harvestFood(); +}; diff --git a/graphs/cpp/caste_or_cast/queen.cc b/graphs/cpp/caste_or_cast/queen.cc new file mode 100644 index 0000000..d1a998f --- /dev/null +++ b/graphs/cpp/caste_or_cast/queen.cc @@ -0,0 +1,30 @@ +#include "queen.hh" + +#include <iostream> + +#include "colony.hh" +#include "nurturer.hh" +#include "provider.hh" + +void Queen::layEgg() +{ + std::cout << "Queen is laying an Egg.\n"; + // if the queen tries to lay an egg without enough food_level + // it loses a health point + if (food_level_ < 0) + hp_ -= 1; + // checking if the colony_ attribute is not expired + std::shared_ptr<Colony> colony = check_colony_access(); + // either create a new Provider or a new Nurturer + static bool choose = false; + if (choose) + eggs_queue_.emplace(std::make_shared<Provider>( + colony, food_level_ * 0.5 + 0.2, DevelopmentStage::EGG)); + else + eggs_queue_.emplace(std::make_shared<Nurturer>( + colony, food_level_ * 0.1 + 0.13, DevelopmentStage::EGG)); + choose = !choose; + // consequences of laying an egg + colony->cleanliness -= 0.6; + food_level_ -= 5.7; +} diff --git a/graphs/cpp/caste_or_cast/queen.hh b/graphs/cpp/caste_or_cast/queen.hh new file mode 100644 index 0000000..9192f4c --- /dev/null +++ b/graphs/cpp/caste_or_cast/queen.hh @@ -0,0 +1,32 @@ +#pragma once + +#include <queue> + +#include "ant.hh" + +//! forward declaration +class Worker; + +/* + * Class representing the Queen Caste + */ +class Queen : public Ant +{ +public: + //! inherit Ant Constructors + using Ant::Ant; + //! the queen will create either a new Provider or Nurturer and push it to + //! eggs_queue_ + void layEgg(); + +private: + /*! + * We should not modify the Colony::workers vector while we + * iterate over it (because in some cases it can lead to undefined behavior) + * To solve this problem, we use a queue so we can save the eggs that the + * queen lay in one round (i.e. one call of Colony::manageAnts) and insert + * them in workers_ vector after we finished iterating. + * */ + std::queue<std::shared_ptr<Worker>> eggs_queue_; + friend class Colony; +}; diff --git a/graphs/cpp/caste_or_cast/worker.cc b/graphs/cpp/caste_or_cast/worker.cc new file mode 100644 index 0000000..e5cb532 --- /dev/null +++ b/graphs/cpp/caste_or_cast/worker.cc @@ -0,0 +1,28 @@ +#include "worker.hh" + +Worker::Worker(std::shared_ptr<Colony> colony, float luck, + DevelopmentStage stage) + : Ant(colony, stage) + , luck_(luck) +{} + +void Worker::work() +{ + if (food_level_ < 0) + hp_ -= 0.5; +} + +float Worker::get_luck() const +{ + return luck_; +} + +float Worker::get_food_stock() const +{ + return food_stock_; +} + +void Worker::increment_food_stock_by(float value) +{ + food_stock_ += value; +} diff --git a/graphs/cpp/caste_or_cast/worker.hh b/graphs/cpp/caste_or_cast/worker.hh new file mode 100644 index 0000000..cb8c5ef --- /dev/null +++ b/graphs/cpp/caste_or_cast/worker.hh @@ -0,0 +1,30 @@ +#pragma once + +#include "ant.hh" + +/* + * Class representing the generic Worker Caste + */ +class Worker : public Ant +{ +public: + //! inherit Ant constructors + using Ant::Ant; + //! constructor + Worker(std::shared_ptr<Colony> colony, float luck, + DevelopmentStage stage = DevelopmentStage::EGG); + //! the Worker will do all of its tasks + virtual void work(); + //! getter for food_stock_ + float get_food_stock() const; + //! add given value to food_stock_ + void increment_food_stock_by(float value); + //! return the luck of the worker + float get_luck() const; + +protected: + //! current food that the worker store on her. + float food_stock_ = 0.0; + //! luck of the worker + float luck_ = 3.141592; +}; |
