Ceci est une ancienne révision du document !
Sujet et exemples de realisation :
Notes :
#include <iostream> #include <vector> #include <string> #include <algorithm> #include <numeric> #include <iterator> namespace ecs { namespace entity { using id = size_t; using entities = std::vector<id>; } namespace component { using name = std::string; using is_male = bool; using detail = std::pair<name, is_male>; using detail_component = std::pair<entity::id, detail>; enum class type { algue, poisson }; using type_component = std::pair<entity::id, type>; } namespace system { using details = std::vector<component::detail_component>; using types = std::vector<component::type_component>; } namespace internal { entity::entities _entities; system::details _details; system::types _types; } entity::id create_entity() { const auto id = internal::_entities.empty() ? 1 : internal::_entities.back() + 1; internal::_entities.push_back(id); return id; } void add_algue() { const auto id = create_entity(); internal::_types.push_back(std::make_pair(id, component::type::algue)); } void add_poisson(component::name n, component::is_male m) { const auto id = create_entity(); internal::_types.push_back(std::make_pair(id, component::type::poisson)); internal::_details.push_back(std::make_pair(id, make_pair(n, m))); } void print_algues() { const auto count = std::count_if(begin(internal::_types), end(internal::_types), [](auto p){ return (p.second == component::type::algue); }); std::cout << "algues: " << count; } void print_poissons() { std::cout << "poissons: "; std::transform(begin(internal::_details), end(internal::_details), std::ostream_iterator<std::string>(std::cout, ", "), [](auto p){ return (p.second.first + " [" + (p.second.second ? 'M' : 'F') + ']'); }); } void print() { print_algues(); std::cout << ". "; print_poissons(); std::cout << std::endl; } } int main() { ecs::add_algue(); ecs::add_algue(); ecs::add_poisson("toto", true); ecs::add_algue(); ecs::add_poisson("titi", false); ecs::add_poisson("tata", true); ecs::add_algue(); ecs::print(); return 0; }
affiche :
algues: 4. poissons: toto [M], titi [F], tata [M],
Mauvaise encapsulation = pas de garanties fortes sur les comportements.
int main() { ecs::internal::_entities.push_back(0); ecs::internal::_entities.push_back(0); }
#include <iostream> #include <vector> #include <string> #include <algorithm> #include <numeric> #include <iterator> #include <cassert> namespace ecs { namespace entity { using id = size_t; using entities = std::vector<id>; } namespace component { using name = std::string; using is_male = bool; using detail = std::pair<name, is_male>; using detail_component = std::pair<entity::id, detail>; enum class type { algue, Mérou, Thon, PoissonClown, Sole, Bar, Carpe }; using type_component = std::pair<entity::id, type>; bool is_algue(type t) { return (t == type::algue); } bool is_poisson(type t) { return !is_algue(t); } bool is_carnivore(type t) { return (t == type::Mérou || t == type::Thon || t == type::PoissonClown); } bool is_herbivore(type t) { return (t == type::Sole || t == type::Bar || t == type::Carpe); } std::string to_string(type t) { static const std::string types[] = { "Algue", "Mérou", "Thon", "Poisson-clown", "Sole", "Bar", "Carpe" }; const auto i = static_cast<size_t>(t); return types[i]; } } namespace system { using details = std::vector<component::detail_component>; using types = std::vector<component::type_component>; } namespace internal { entity::entities _entities; system::details _details; system::types _types; } entity::id create_entity() { const auto id = internal::_entities.empty() ? 1 : 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_pair(id, component::type::algue)); 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_pair(id, t)); internal::_details.push_back(std::make_pair(id, make_pair(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 p){ return (p.first == id); }); internal::_details.erase(details_it, internal::_details.end()); const auto types_it = std::remove_if(internal::_types.begin(), internal::_types.end(), [id](auto p){ return (p.first == id); }); internal::_types.erase(types_it, internal::_types.end()); } void eat(entity::id eater, entity::id target) { assert(eater != target); const auto eater_it = std::find_if(begin(internal::_types), end(internal::_types), [eater](auto p){ return (p.first == eater); }); const auto target_it = std::find_if(begin(internal::_types), end(internal::_types), [target](auto p){ return (p.first == target); }); assert(is_poisson(eater_it->second)); assert(is_carnivore(eater_it->second) || (is_herbivore(eater_it->second) && is_algue(target_it->second))); remove_entity(target); //eat } void print_algues() { const auto count = std::count_if(begin(internal::_types), end(internal::_types), [](auto p){ return (p.second == component::type::algue); }); std::cout << "algues: " << count; } void print_poissons() { std::cout << "poissons: "; std::transform(begin(internal::_details), end(internal::_details), std::ostream_iterator<std::string>(std::cout, ", "), [](auto p){ return (p.second.first + " [" + (p.second.second ? 'M' : 'F') + ']'); }); } void print() { print_algues(); std::cout << ". "; print_poissons(); std::cout << std::endl; } } int main() { ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); const auto algue = ecs::add_algue(); const auto carnivore = ecs::add_poisson(ecs::component::type::Mérou, "toto", true); const auto poisson = ecs::add_poisson(ecs::component::type::Mérou, "titi", false); const auto herbivore = ecs::add_poisson(ecs::component::type::Mérou, "tata", true); ecs::add_poisson(ecs::component::type::Mérou, "tuto", false); ecs::add_poisson(ecs::component::type::Mérou, "tyty", true); ecs::print(); ecs::remove_entity(poisson); ecs::print(); ecs::eat(herbivore, algue); ecs::eat(carnivore, herbivore); ecs::print(); return 0; }
affiche :
algues: 8. poissons: toto [M], titi [F], tata [M], tuto [F], tyty [M], algues: 8. poissons: toto [M], tata [M], tuto [F], tyty [M], algues: 7. poissons: toto [M], tuto [F], tyty [M],
typage fort
enum class type { algue, Mérou, Thon, PoissonClown, Sole, Bar, Carpe }; void add_poisson(component::name n, component::is_male m, component::type t) { assert(is_poisson(t)); ... } enum class type { algue, poisson }; enum class race { Mérou, Thon, PoissonClown, Sole, Bar, Carpe }; void add_poisson(component::name n, component::is_male m, component::race r) { // assert(is_poisson(t)); pas necessaire ... }
idem:
void eat(entity::id eater, entity::id target) { const auto eater_it = std::find(begin(internal::_types), end(internal::_types), [eater](auto p){ return (p.first == eater); }); const auto target_it = std::find(begin(internal::_types), end(internal::_types), [target](auto p){ return (p.first == target); }); assert(is_poisson(eater_it->second)); assert(is_carnivore(eater_it->second) || (is_herbivore(eater_it->second) && is_poisson(target_it->second))); remove_entity(target); //eat }
#include <iostream> #include <vector> #include <string> #include <algorithm> #include <numeric> #include <iterator> #include <cassert> #include <random> namespace ecs { namespace entity { using id = size_t; using entities = std::vector<id>; } namespace component { using name = std::string; using is_male = bool; using detail = std::pair<name, is_male>; using detail_component = std::pair<entity::id, detail>; enum class type { algue, Mérou, Thon, PoissonClown, Sole, Bar, Carpe }; using type_component = std::pair<entity::id, type>; bool is_algue(type t) { return (t == type::algue); } bool is_poisson(type t) { return !is_algue(t); } bool is_carnivore(type t) { return (t == type::Mérou || t == type::Thon || t == type::PoissonClown); } bool is_herbivore(type t) { return (t == type::Sole || t == type::Bar || t == type::Carpe); } std::string to_string(type t) { static const std::string types[] = { "Algue", "Mérou", "Thon", "Poisson-clown", "Sole", "Bar", "Carpe" }; const auto i = static_cast<size_t>(t); assert(true); return types[i]; } } namespace system { using details = std::vector<component::detail_component>; using types = std::vector<component::type_component>; } namespace internal { entity::entities _entities; system::details _details; system::types _types; std::random_device _random_device; std::default_random_engine _random_engine { _random_device() }; } entity::id create_entity() { const auto id = internal::_entities.empty() ? 1 : 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_pair(id, component::type::algue)); 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_pair(id, t)); internal::_details.push_back(std::make_pair(id, make_pair(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 p){ return (p.first == id); }); internal::_details.erase(details_it, internal::_details.end()); const auto types_it = std::remove_if(internal::_types.begin(), internal::_types.end(), [id](auto p){ return (p.first == id); }); internal::_types.erase(types_it, internal::_types.end()); } void eat(entity::id eater, entity::id target) { assert(eater != target); const auto eater_it = std::find_if(begin(internal::_types), end(internal::_types), [eater](auto p){ return (p.first == eater); }); const auto target_it = std::find_if(begin(internal::_types), end(internal::_types), [target](auto p){ return (p.first == target); }); assert(is_poisson(eater_it->second)); assert(is_carnivore(eater_it->second) || (is_herbivore(eater_it->second) && is_algue(target_it->second))); remove_entity(target); //eat } entity::id random_entity() { std::uniform_int_distribution<size_t> distribution(0, internal::_entities.size() - 1); const auto index = distribution(internal::_random_engine); return internal::_entities[index]; } entity::id random_poisson() { std::uniform_int_distribution<size_t> distribution(0, internal::_details.size() - 1); const auto index = distribution(internal::_random_engine); return internal::_details[index].first; } void print_algues() { const auto count = std::count_if(begin(internal::_types), end(internal::_types), [](auto p){ return (p.second == component::type::algue); }); std::cout << "algues: " << count; } void print_poissons() { std::cout << "poissons: "; std::transform(begin(internal::_details), end(internal::_details), std::ostream_iterator<std::string>(std::cout, ", "), [](auto p){ return (p.second.first + " [" + (p.second.second ? 'M' : 'F') + ']'); }); } void print() { print_algues(); std::cout << ". "; print_poissons(); std::cout << std::endl; } } int main() { ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_poisson(ecs::component::type::Mérou, "toto", true); ecs::add_poisson(ecs::component::type::Mérou, "titi", false); ecs::add_poisson(ecs::component::type::Mérou, "tata", true); ecs::add_poisson(ecs::component::type::Mérou, "tuto", false); ecs::add_poisson(ecs::component::type::Mérou, "tyty", true); ecs::print(); for (size_t i {}; i < 50; ++i) { std::uniform_int_distribution<size_t> distribution(0, ecs::internal::_types.size() - 1); auto index = distribution(ecs::internal::_random_engine); const auto eater = ecs::internal::_types[index]; index = distribution(ecs::internal::_random_engine); const auto target = ecs::internal::_types[index]; if (eater.first == target.first) continue; if (is_algue(eater.second)) continue; if (is_herbivore(eater.second) && is_poisson(target.second)) continue; std::cout << " " << eater.first << " mange " << target.first << std::endl; ecs::remove_entity(target.first); // eat ecs::print(); } return 0; }
affiche :
algues: 8. poissons: toto [M], titi [F], tata [M], tuto [F], tyty [M], 13 mange 3 algues: 7. poissons: toto [M], titi [F], tata [M], tuto [F], tyty [M], 12 mange 6 algues: 6. poissons: toto [M], titi [F], tata [M], tuto [F], tyty [M], 10 mange 12 algues: 6. poissons: toto [M], titi [F], tata [M], tyty [M], 13 mange 10 algues: 6. poissons: toto [M], tata [M], tyty [M], 13 mange 7 algues: 5. poissons: toto [M], tata [M], tyty [M], 13 mange 4 algues: 4. poissons: toto [M], tata [M], tyty [M], 13 mange 9 algues: 4. poissons: tata [M], tyty [M], 11 mange 2 algues: 3. poissons: tata [M], tyty [M], 11 mange 5 algues: 2. poissons: tata [M], tyty [M], 13 mange 11 algues: 2. poissons: tyty [M], 13 mange 8 algues: 1. poissons: tyty [M], 13 mange 1 algues: 0. poissons: tyty [M],
#include <iostream> #include <vector> #include <string> #include <algorithm> #include <numeric> #include <iterator> #include <cassert> #include <random> #include <tuple> namespace ecs { namespace entity { using id = size_t; using entities = std::vector<id>; } namespace component { using name = std::string; using is_male = bool; using detail = std::pair<name, is_male>; using detail_component = std::pair<entity::id, detail>; enum class type { algue, Mérou, Thon, PoissonClown, Sole, Bar, Carpe }; using pv = size_t; using type_component = std::tuple<entity::id, type, pv>; bool is_algue(type t) { return (t == type::algue); } bool is_poisson(type t) { return !is_algue(t); } bool is_carnivore(type t) { return (t == type::Mérou || t == type::Thon || t == type::PoissonClown); } bool is_herbivore(type t) { return (t == type::Sole || t == type::Bar || t == type::Carpe); } std::string to_string(type t) { static const std::string types[] = { "Algue", "Mérou", "Thon", "Poisson-clown", "Sole", "Bar", "Carpe" }; const auto i = static_cast<size_t>(t); assert(true); return types[i]; } } namespace system { using details = std::vector<component::detail_component>; using types = std::vector<component::type_component>; } namespace internal { entity::entities _entities; system::details _details; system::types _types; std::random_device _random_device; std::default_random_engine _random_engine { _random_device() }; } entity::id create_entity() { const auto id = internal::_entities.empty() ? 1 : 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)); 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)); internal::_details.push_back(std::make_pair(id, make_pair(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 p){ return (p.first == id); }); internal::_details.erase(details_it, internal::_details.end()); const auto types_it = std::remove_if(internal::_types.begin(), internal::_types.end(), [id](auto p){ return (std::get<0>(p) == id); }); internal::_types.erase(types_it, internal::_types.end()); } void eat(entity::id eater, entity::id target) { assert(eater != target); const auto eater_it = std::find_if(begin(internal::_types), end(internal::_types), [eater](auto p){ return (std::get<0>(p) == eater); }); const auto target_it = std::find_if(begin(internal::_types), end(internal::_types), [target](auto p){ return (std::get<0>(p) == target); }); assert(is_poisson(std::get<1>(*eater_it))); assert(is_carnivore(std::get<1>(*eater_it)) || (is_herbivore(std::get<1>(*eater_it)) && is_algue(std::get<1>(*target_it)))); remove_entity(target); //eat } entity::id random_entity() { std::uniform_int_distribution<size_t> distribution(0, internal::_entities.size() - 1); const auto index = distribution(internal::_random_engine); return internal::_entities[index]; } entity::id random_poisson() { std::uniform_int_distribution<size_t> distribution(0, internal::_details.size() - 1); const auto index = distribution(internal::_random_engine); return internal::_details[index].first; } void print_algues() { const auto count = std::count_if(begin(internal::_types), end(internal::_types), [](auto p){ return (std::get<1>(p) == component::type::algue); }); std::cout << "algues: " << count; } void print_poissons() { std::cout << "poissons: "; std::transform(begin(internal::_details), end(internal::_details), std::ostream_iterator<std::string>(std::cout, ", "), [](auto p){ return (p.second.first + " [" + (p.second.second ? 'M' : 'F') + ']'); }); } void print() { print_algues(); std::cout << ". "; print_poissons(); std::cout << std::endl; } } int main() { ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_algue(); ecs::add_poisson(ecs::component::type::Mérou, "toto", true); ecs::add_poisson(ecs::component::type::Mérou, "titi", false); ecs::add_poisson(ecs::component::type::Mérou, "tata", true); ecs::add_poisson(ecs::component::type::Mérou, "tuto", false); ecs::add_poisson(ecs::component::type::Mérou, "tyty", true); ecs::print(); for (size_t i {}; i < 50; ++i) { std::uniform_int_distribution<size_t> distribution(0, ecs::internal::_types.size() - 1); auto index = distribution(ecs::internal::_random_engine); const auto eater = ecs::internal::_types[index]; index = distribution(ecs::internal::_random_engine); auto & target = ecs::internal::_types[index]; if (std::get<0>(eater) == std::get<0>(target)) continue; if (is_algue(std::get<1>(eater))) continue; if (is_herbivore(std::get<1>(eater)) && is_poisson(std::get<1>(target))) continue; std::get<2>(target) -= 2; // eat std::cout << " " << std::get<0>(eater) << " mange " << std::get<0>(target) << " reste " << std::get<2>(target) << std::endl; ecs::print(); } return 0; }