#include #include #include #include #include #include #include #include #include namespace ecs { namespace entity { using id = size_t; using entities = std::vector; } namespace component { using name = std::string; using is_male = bool; using detail_component = std::tuple; enum class type { algue, Mérou, Thon, PoissonClown, Sole, Bar, Carpe }; using point_vie = int8_t; using age = uint8_t; using type_component = std::tuple; } namespace system { using details = std::vector; using types = std::vector; } namespace internal { entity::entities _entities; system::details _details; system::types _types; std::random_device _random_device; std::default_random_engine _random_engine { _random_device() }; } bool is_algue(component::type t) { return (t == component::type::algue); } bool is_poisson(component::type t) { return !is_algue(t); } bool is_carnivore(component::type t) { return (t == component::type::Mérou || t == component::type::Thon || t == component::type::PoissonClown); } bool is_herbivore(component::type t) { return (t == component::type::Sole || t == component::type::Bar || t == component::type::Carpe); } bool is_algue_t(component::type_component const& t) { return is_algue(std::get<1>(t)); } bool is_poisson_t(component::type_component const& t) { return is_poisson(std::get<1>(t)); } bool is_carnivore_t(component::type_component const& t) { return is_carnivore(std::get<1>(t)); } bool is_herbivore_t(component::type_component const& t) { return is_herbivore(std::get<1>(t)); } component::point_vie& get_point_vie(component::type_component & t) { return std::get<2>(t); } component::age& get_age(component::type_component & t) { return std::get<3>(t); } bool random_sexe() { static std::uniform_int_distribution algue_distribution(0,1); return (algue_distribution(ecs::internal::_random_engine) == 0); } component::type random_race() { static std::uniform_int_distribution algue_distribution(0,6); return static_cast(algue_distribution(ecs::internal::_random_engine)); } std::string to_string(component::type t) { static const std::string types[] = { "Algue", "Mérou", "Thon", "Poisson-clown", "Sole", "Bar", "Carpe" }; const auto i = static_cast(t); return types[i]; } template std::vector get_entities(Predicat&& predicat) { std::vector entities; std::for_each(begin(internal::_types), end(internal::_types), [&entities, predicat](const auto type){ if (predicat(type)) { entities.push_back(std::get<0>(type)); } } ); return entities; } template typename Collection::iterator get_component(Collection & components, entity::id id) { auto it = find_if(begin(components), end(components), [id](auto t){ return (std::get<0>(t) == id); }); return it; } entity::id create_entity() { const auto id = internal::_entities.empty() ? 0 : internal::_entities.back() + 1; internal::_entities.push_back(id); return id; } entity::id add_algue(ecs::component::point_vie pv = 10) { const auto id = create_entity(); internal::_types.push_back(std::make_tuple(id, component::type::algue, pv, 0)); return id; } entity::id add_poisson(component::type t, component::name n, component::is_male m, ecs::component::point_vie pv = 10) { assert(is_poisson(t)); const auto id = create_entity(); internal::_types.push_back(std::make_tuple(id, t, pv, 0)); internal::_details.push_back(std::make_tuple(id, n, m)); return id; } void remove_entity(entity::id id) { const auto entities_it = std::remove(internal::_entities.begin(), internal::_entities.end(), id); internal::_entities.erase(entities_it, internal::_entities.end()); const auto details_it = std::remove_if(internal::_details.begin(), internal::_details.end(), [id](auto t){ return (std::get<0>(t) == id); }); internal::_details.erase(details_it, internal::_details.end()); const auto types_it = std::remove_if(internal::_types.begin(), internal::_types.end(), [id](auto t){ return (std::get<0>(t) == id); }); internal::_types.erase(types_it, internal::_types.end()); } void remove_entities(std::vector const& ids) { for (auto id: ids) remove_entity(id); } void print(size_t tour, size_t entites, size_t algues, size_t herbivores, size_t carnivores) { std::cout << tour << "\t\t" << entites << "\t\t" << algues << "\t\t" << herbivores << "\t\t" << carnivores << std::endl; } } int main() { std::cout << "Tour\t\tEntities\tAlgues\t\tHerbivores\tCarnivores" << std::endl; for (size_t i {}; i < 20; ++i) { const auto race = ecs::random_race(); if (ecs::is_algue(race)) ecs::add_algue(); else ecs::add_poisson(race, ecs::to_string(race), ecs::random_sexe()); } for (size_t tour {}; tour < 100; ++tour) { // update pv and age for (auto entity: ecs::internal::_entities) { const auto type = ecs::get_component(ecs::internal::_types, entity); // pv if (ecs::is_algue_t(*type)) { if (ecs::get_point_vie(*type) > 10) { ecs::get_point_vie(*type) /= 2; ecs::add_algue(ecs::get_point_vie(*type)); } else { ecs::get_point_vie(*type) += 1; } } else { ecs::get_point_vie(*type) -= 1; } // age ecs::get_age(*type) += 1; } const auto herbivores = ecs::get_entities(ecs::is_herbivore_t); const auto algues = ecs::get_entities(ecs::is_algue_t); ecs::print(tour, ecs::internal::_entities.size(), algues.size(), herbivores.size(), ecs::internal::_entities.size() - algues.size() - herbivores.size()); const auto poissons = ecs::get_entities(ecs::is_poisson_t); for (const auto poisson_id: poissons) { const auto type = ecs::get_component(ecs::internal::_types, poisson_id); if (type != end(ecs::internal::_types)) { const auto race = std::get<1>(*type); if (ecs::get_point_vie(*type) < 5) { // manger if (ecs::is_herbivore_t(*type) && !algues.empty()) { std::uniform_int_distribution algue_distribution(0, algues.size() - 1); const auto index { algue_distribution(ecs::internal::_random_engine) }; const auto algue_id = algues[index]; const auto herbivore_type = ecs::get_component(ecs::internal::_types, poisson_id); const auto algue_type = ecs::get_component(ecs::internal::_types, algue_id); if ((herbivore_type != end(ecs::internal::_types)) && (algue_type != end(ecs::internal::_types))) { ecs::get_point_vie(*herbivore_type) += 3; ecs::get_point_vie(*algue_type) -= 2; } } else { const auto bons_petits_plats = ecs::get_entities( [poisson_id, race](const auto _type){ const auto _id = std::get<0>(_type); const auto _race = std::get<1>(_type); return ( ecs::is_poisson(_race) && (_id != poisson_id) && (_race != race) ); } ); if (!bons_petits_plats.empty()) { std::uniform_int_distribution entities_distribution(0, bons_petits_plats.size() - 1); const auto index { entities_distribution(ecs::internal::_random_engine) }; const auto entity_id = bons_petits_plats[index]; const auto entity_type = ecs::get_component(ecs::internal::_types, entity_id); if (entity_type != end(ecs::internal::_types)) { if (ecs::is_algue_t(*entity_type)) { ecs::get_point_vie(*type) += 3; ecs::get_point_vie(*entity_type) -= 2; } else { ecs::get_point_vie(*type) += 5; ecs::get_point_vie(*entity_type) -= 4; } } } } } else { // bais... se reproduire std::uniform_int_distribution poissons_distribution(0, poissons.size() - 1); const auto index { poissons_distribution(ecs::internal::_random_engine) }; const auto poisson_2_id = poissons[index]; const auto poisson_sex = ecs::get_component(ecs::internal::_details, poisson_id); const auto poisson_2_sex = ecs::get_component(ecs::internal::_details, poisson_2_id); const auto poisson_2_race = ecs::get_component(ecs::internal::_types, poisson_2_id); if ((poisson_sex != end(ecs::internal::_details)) && (poisson_2_sex != end(ecs::internal::_details)) && (poisson_2_race != end(ecs::internal::_types)) && (std::get<2>(*poisson_sex) != std::get<2>(*poisson_2_sex)) && (race != std::get<1>(*poisson_2_race))) { ecs::add_poisson(race, "Bebe", ecs::random_sexe(), 5); } } } } // deads std::vector entities_to_remove; for (auto entity: ecs::internal::_entities) { const auto type = ecs::get_component(ecs::internal::_types, entity); if (type != end(ecs::internal::_types) && (ecs::get_point_vie(*type) <= 0 || ecs::get_age(*type) > 20)) { entities_to_remove.push_back(entity); } } for (auto entity: entities_to_remove) { ecs::remove_entity(entity); } } std::cout << "===== Fini ======" << std::endl; return 0; }