#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); } 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() { const auto id = create_entity(); internal::_types.push_back(std::make_tuple(id, component::type::algue, 10, 0)); return id; } entity::id add_poisson(component::type t, component::name n, component::is_male m) { assert(is_poisson(t)); const auto id = create_entity(); internal::_types.push_back(std::make_tuple(id, t, 10, 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() { if (internal::_types.empty()) { std::cout << "Aucune entite" << std::endl; return; } std::cout << internal::_types.size() << " entites: " << std::endl; std::cout << "\tid\ttype\tpv" << std::endl; auto print = [](auto t){ return ('\t' + std::to_string(std::get<0>(t)) + '\t' + to_string(std::get<1>(t)) + '\t' + std::to_string(std::get<2>(t))); }; std::transform(begin(internal::_types), end(internal::_types) - 1, std::ostream_iterator(std::cout, "\n"), print); std::cout << print(internal::_types.back()) << std::endl; } } int main() { for (size_t i {}; i < 5; ++i) ecs::add_algue(); for (size_t i {}; i < 2; ++i) ecs::add_poisson(ecs::component::type::Sole, "Sole", false); for (size_t i {}; i < 2; ++i) ecs::add_poisson(ecs::component::type::Mérou, "Mérou", false); ecs::print(); for (size_t tour {}; tour < 21; ++tour) { std::cout << "===== Tour " << tour << " ======" << std::endl; // 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)) { ecs::get_point_vie(*type) += 1; } else { ecs::get_point_vie(*type) -= 1; } // age ecs::get_age(*type) += 1; } // eat const auto herbivores = ecs::get_entities(ecs::is_herbivore_t); const auto algues = ecs::get_entities(ecs::is_algue_t); if (!algues.empty()) { for (const auto herbivore: herbivores) { const auto herbivore_type = ecs::get_component(ecs::internal::_types, herbivore); if (herbivore_type != end(ecs::internal::_types) && ecs::get_point_vie(*herbivore_type) < 5) { std::uniform_int_distribution algue_distribution(0, algues.size() - 1); const auto index { algue_distribution(ecs::internal::_random_engine) }; const auto algue = algues[index]; const auto algue_type = ecs::get_component(ecs::internal::_types, algue); ecs::get_point_vie(*herbivore_type) += 3; ecs::get_point_vie(*algue_type) -= 2; } } } const auto carnivores = ecs::get_entities(ecs::is_carnivore_t); for (const auto carnivore_id: carnivores) { const auto carnivore_type = ecs::get_component(ecs::internal::_types, carnivore_id); if (carnivore_type != end(ecs::internal::_types) && ecs::get_point_vie(*carnivore_type) < 5) // a faim ? { const auto carnivore_race = std::get<1>(*carnivore_type); const auto bons_petits_plats = ecs::get_entities( [carnivore_id, carnivore_race](const auto type){ const auto id = std::get<0>(type); const auto race = std::get<1>(type); return ( ecs::is_poisson(race) && (id != carnivore_id) && (race != carnivore_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(*carnivore_type) += 3; ecs::get_point_vie(*entity_type) -= 2; } else { ecs::get_point_vie(*carnivore_type) += 5; ecs::get_point_vie(*entity_type) -= 4; } } } } } // 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); } ecs::print(); } std::cout << "===== Fini ======" << std::endl; return 0; }