From 8cb2b8bcdf5b1d17d4184a065c0a3114b131811f Mon Sep 17 00:00:00 2001 From: wanotaitei Date: Fri, 24 May 2024 23:30:33 +0900 Subject: [PATCH] add: Created a simulation function for the Yayoi period. --- Library/PAX_MAHOROBA/LocationPoint.hpp | 4 +- .../PAX_SAPIENTICA/Simulation/Chromosome.hpp | 4 +- Library/PAX_SAPIENTICA/Simulation/Genome.hpp | 2 +- .../Simulation/JapanProvinces.hpp | 9 +- .../PAX_SAPIENTICA/Simulation/Settlement.hpp | 28 +++++-- .../Simulation/SettlementAgent.hpp | 33 ++++---- .../Simulation/SettlementSimulator.hpp | 82 +++++++++++-------- .../Simulation/SimulationConst.hpp | 8 ++ .../PAX_SAPIENTICA/UniqueIdentification.hpp | 2 +- 9 files changed, 104 insertions(+), 68 deletions(-) diff --git a/Library/PAX_MAHOROBA/LocationPoint.hpp b/Library/PAX_MAHOROBA/LocationPoint.hpp index fd5e8528f..12bd9622d 100644 --- a/Library/PAX_MAHOROBA/LocationPoint.hpp +++ b/Library/PAX_MAHOROBA/LocationPoint.hpp @@ -678,9 +678,9 @@ namespace paxs { // if (lli.lpe == MurMur3::calcHash("agent1")) { // const std::size_t pop_original = settlement.getFarmingPopulation(); // settlement.getPopulation(); - const float pop_original = settlement.getFarmingPopulation() / float(settlement.getPopulation()) * 80.0f; // settlement.getPopulation(); + const float pop_original = settlement.getFarmingPopulation() / float(settlement.getPopulation()) * 75.0f; // settlement.getPopulation(); - const std::uint_least8_t pop = (pop_original >= 80) ? 80 : static_cast(pop_original); + const std::uint_least8_t pop = (pop_original >= 75) ? 75 : static_cast(pop_original); paxg::Circle(draw_pos, 1.0f + (settlement.getPopulation() / 40.0f)//2.0f ).draw(getColor(pop)); diff --git a/Library/PAX_SAPIENTICA/Simulation/Chromosome.hpp b/Library/PAX_SAPIENTICA/Simulation/Chromosome.hpp index 72704da6e..c782416ee 100644 --- a/Library/PAX_SAPIENTICA/Simulation/Chromosome.hpp +++ b/Library/PAX_SAPIENTICA/Simulation/Chromosome.hpp @@ -27,7 +27,7 @@ namespace paxs { /// @brief 染色体 class Chromosome { public: - static constexpr std::uint_least8_t chromosome_length = 46; + static constexpr std::uint_least8_t chromosome_length = 2;// 46; Chromosome() = default; std::uint_least8_t get(const std::uint_least8_t index) const noexcept { @@ -53,7 +53,7 @@ namespace paxs { return os; } - std::uint_least8_t getGender() const noexcept { + constexpr std::uint_least8_t getGender() const noexcept { return gender; } diff --git a/Library/PAX_SAPIENTICA/Simulation/Genome.hpp b/Library/PAX_SAPIENTICA/Simulation/Genome.hpp index 1718edd21..7ef0acac4 100644 --- a/Library/PAX_SAPIENTICA/Simulation/Genome.hpp +++ b/Library/PAX_SAPIENTICA/Simulation/Genome.hpp @@ -54,7 +54,7 @@ namespace paxs { yDNA = value; } - std::uint_least8_t getGender() const noexcept { + constexpr std::uint_least8_t getGender() const noexcept { return chromosome.getGender(); } diff --git a/Library/PAX_SAPIENTICA/Simulation/JapanProvinces.hpp b/Library/PAX_SAPIENTICA/Simulation/JapanProvinces.hpp index e51314740..ffbe26963 100644 --- a/Library/PAX_SAPIENTICA/Simulation/JapanProvinces.hpp +++ b/Library/PAX_SAPIENTICA/Simulation/JapanProvinces.hpp @@ -40,8 +40,7 @@ namespace paxs { std::uint_least8_t region_id; // 対応する地方区分ID std::uint_least32_t settlement_population_min_ad200; std::uint_least32_t settlement_population_max_ad200; - std::uint_least32_t population_ad200; - std::uint_least32_t population_ad725; + std::uint_least32_t population[4]; }; /// @brief A class that represents a prefecture in Japan. @@ -79,8 +78,8 @@ namespace paxs { ryoseikoku.region_id = static_cast(std::stoi(ryoseikoku_tsv[i][2])); ryoseikoku.settlement_population_min_ad200 = std::stoi(ryoseikoku_tsv[i][3]); ryoseikoku.settlement_population_max_ad200 = std::stoi(ryoseikoku_tsv[i][4]); - ryoseikoku.population_ad200 = std::stoi(ryoseikoku_tsv[i][5]); - ryoseikoku.population_ad725 = std::stoi(ryoseikoku_tsv[i][6]); + ryoseikoku.population[0/*ad200*/] = std::stoi(ryoseikoku_tsv[i][5]); + ryoseikoku.population[1/*ad725*/] = std::stoi(ryoseikoku_tsv[i][6]); ryoseikoku_list.emplace_back(ryoseikoku); } catch (const std::invalid_argument&) { PAXS_WARNING("Failed to read Ryoseikoku TSV file: " + ryoseikoku_tsv_path + " at line " + std::to_string(i)); @@ -133,7 +132,7 @@ namespace paxs { std::uint_least32_t getRyoseikokuPopulationAd200(const std::uint_least8_t id) const noexcept { for (const auto& ryoseikoku : ryoseikoku_list) { if (ryoseikoku.id == id) { - return ryoseikoku.population_ad200; + return ryoseikoku.population[0/*ad200*/]; } } PAXS_WARNING("Failed to get Ryoseikoku population: " + std::to_string(id)); diff --git a/Library/PAX_SAPIENTICA/Simulation/Settlement.hpp b/Library/PAX_SAPIENTICA/Simulation/Settlement.hpp index 623ba4bbb..03020d04a 100644 --- a/Library/PAX_SAPIENTICA/Simulation/Settlement.hpp +++ b/Library/PAX_SAPIENTICA/Simulation/Settlement.hpp @@ -168,6 +168,8 @@ namespace paxs { // 結婚可能かどうか if (agents[i].isAbleToMarriage() && agents[i].getGender() == SimulationConstants::getInstance()->female) { if (!isMarried(agents[i].getAge())) continue; + // 妊娠していたら婚姻しない(婚姻可能と定義すると再婚者のデータで上書きされ子供への継承が不自然になる) + if (agents[i].getBirthIntervalCount() > 0) continue; marriageable_female_index.emplace_back(i); } @@ -273,7 +275,7 @@ namespace paxs { /// @brief 事前更新 void preUpdate(KanakumaLifeSpan& kanakuma_life_span, std::uint_least64_t& count) noexcept { birth(kanakuma_life_span); - emigration(kanakuma_life_span, count); + //emigration(kanakuma_life_span, count); } /// @brief On update. @@ -399,18 +401,26 @@ namespace paxs { if (agent.getBirthIntervalCount() > 0) { std::uint_least8_t count = agent.decrementBirthIntervalCount(); if (count == 0) { - // 死産 - if (random_dist(*gen) < 0.11f) continue; + // 死産率 100 %の場合は出産しない + if (SimulationConstants::getInstance()->stillbirth_rate >= 1.0f) continue; + else if (SimulationConstants::getInstance()->stillbirth_rate > 0.0f) { + // 死産 + if (random_dist(*gen) < SimulationConstants::getInstance()->stillbirth_rate) continue; + } // TODO: 直す - if (!agent.isMarried()) continue; + //if (!agent.isMarried()) continue; Genome genome = Genome::generateFromParents(agent.cgetGenome(), agent.cgetPartnerGenome()); children.emplace_back(Agent( - UniqueIdentification::generate(), - 0, // TODO: 名前ID + UniqueIdentification::generate(), + //0, // TODO: 名前ID 0, kanakuma_life_span.setLifeSpan(genome.getGender(), *gen), genome, - (((*gen)() % 2) == 0) ? agent.cgetFarming() : agent.cgetPartnerFarming(), + (agent.cgetFarming() > 0 && agent.cgetPartnerFarming() > 0) ? 255 :( + (agent.cgetFarming() == 0 && agent.cgetPartnerFarming() == 0) ? 0 : ( + (random_dist(*gen) < SimulationConstants::getInstance()->child_agriculture_priority) ? 255 : 0 + )), + //(((*gen)() % 2) == 0) ? agent.cgetFarming() : agent.cgetPartnerFarming(), (((*gen)() % 2) == 0) ? agent.cgetHunterGatherer() : agent.cgetPartnerHunterGatherer() )); } @@ -439,8 +449,8 @@ namespace paxs { static_cast(set_lifespan - 1) }; // 性別の乱数分布 agents.emplace_back(Agent( - UniqueIdentification::generate(), - 0, // TODO: 名前ID + UniqueIdentification::generate(), + //0, // TODO: 名前ID lifespan_dist(*gen), set_lifespan, genome, diff --git a/Library/PAX_SAPIENTICA/Simulation/SettlementAgent.hpp b/Library/PAX_SAPIENTICA/Simulation/SettlementAgent.hpp index f92ca8467..9b6dff6a1 100644 --- a/Library/PAX_SAPIENTICA/Simulation/SettlementAgent.hpp +++ b/Library/PAX_SAPIENTICA/Simulation/SettlementAgent.hpp @@ -37,17 +37,18 @@ namespace paxs { SettlementAgent() = default; - explicit SettlementAgent(const std::uint_least64_t id, const std::uint_least32_t& name_id, + explicit SettlementAgent(const std::uint_least32_t id, //const std::uint_least32_t& name_id, const std::uint_least32_t age, const std::uint_least32_t life_span, const Genome& genome, std::uint_least8_t farming_, // 農耕文化 std::uint_least8_t hunter_gatherer_ // 狩猟採集文化 ) noexcept - : id(id), name_id(name_id), gender(genome.getGender()), age(age), life_span(life_span), genome(genome), + : id(id), //name_id(name_id), + age(age), life_span(life_span), genome(genome), farming(farming_), hunter_gatherer(hunter_gatherer_) {} /// @brief Get the id. /// @brief idを取得 - constexpr std::uint_least64_t getId() const noexcept { return id; } + constexpr std::uint_least32_t getId() const noexcept { return id; } /// @brief Is the agent dead? /// @brief エージェントが死んでいるかどうかを返す @@ -61,7 +62,7 @@ namespace paxs { /// @brief Get the agent's age. /// @brief エージェントの性別を取得する - constexpr std::uint_least8_t getGender() const noexcept { return gender; } + constexpr std::uint_least8_t getGender() const noexcept { return genome.getGender(); } /// @brief Increment the agent's age. /// @brief エージェントの年齢をインクリメントする @@ -91,8 +92,8 @@ namespace paxs { constexpr bool operator==(const SettlementAgent& a) const noexcept { return id == a.id && - name_id == a.name_id && - gender == a.gender && + //name_id == a.name_id && + //gender == a.gender && age == a.age && life_span == a.life_span && genome == a.genome && @@ -108,7 +109,7 @@ namespace paxs { /// @brief Set the agent's marriage status. /// @brief 結婚する - void marry(const std::uint_least64_t partner_id_, const Genome& partner_genome_, + void marry(const std::uint_least32_t partner_id_, const Genome& partner_genome_, std::uint_least8_t partner_farming_, // 結婚相手の農耕文化 std::uint_least8_t partner_hunter_gatherer_ // 結婚相手の狩猟採集文化 ) noexcept { @@ -123,10 +124,10 @@ namespace paxs { /// @brief エージェントが結婚可能かどうかを返す bool isAbleToMarriage() const noexcept { float age_f = static_cast(age) / SimulationConstants::getInstance()->steps_per_year; - return age_f > (gender ? + return age_f > (genome.getGender() ? SimulationConstants::getInstance()->male_marriageable_age_min : SimulationConstants::getInstance()->female_marriageable_age_min) && - age_f < (gender ? + age_f < (genome.getGender() ? SimulationConstants::getInstance()->male_marriageable_age_max : SimulationConstants::getInstance()->male_marriageable_age_max) && !is_married; @@ -142,7 +143,7 @@ namespace paxs { /// @brief Get the partner's ID. /// @brief 結婚相手のIDを取得 - std::uint_least64_t getPartnerId() const noexcept { return partner_id; } + std::uint_least32_t getPartnerId() const noexcept { return partner_id; } /// @brief Divorce. /// @brief 離婚 @@ -150,8 +151,8 @@ namespace paxs { is_married = false; partner_id = 0; // partner_genome = nullptr; - partner_farming = 0; - partner_hunter_gatherer = 0; + //partner_farming = 0; + //partner_hunter_gatherer = 0; } std::uint_least8_t getBirthIntervalCount() const noexcept { return birth_interval_count; } @@ -160,7 +161,7 @@ namespace paxs { protected: bool is_married = false; // 結婚しているかどうか - std::uint_least8_t gender; // 性別: 0 -> 女性, 1 -> 男性 + //std::uint_least8_t gender; // 性別: 0 -> 女性, 1 -> 男性 std::uint_least8_t birth_interval_count = 0; // 出産の間隔のカウント std::uint_least8_t farming = 0; // 農耕文化 @@ -170,10 +171,10 @@ namespace paxs { std::uint_least32_t age; // 年齢 std::uint_least32_t life_span; // 寿命 - std::uint_least32_t name_id; // 名前のID + //std::uint_least32_t name_id; // 名前のID - std::uint_least64_t id; // ID - std::uint_least64_t partner_id = 0; // 結婚相手のID + std::uint_least32_t id; // ID + std::uint_least32_t partner_id = 0; // 結婚相手のID Genome genome; // ゲノム Genome partner_genome; // 結婚相手のゲノム diff --git a/Library/PAX_SAPIENTICA/Simulation/SettlementSimulator.hpp b/Library/PAX_SAPIENTICA/Simulation/SettlementSimulator.hpp index 90cd24ec6..e46e283a6 100644 --- a/Library/PAX_SAPIENTICA/Simulation/SettlementSimulator.hpp +++ b/Library/PAX_SAPIENTICA/Simulation/SettlementSimulator.hpp @@ -76,7 +76,8 @@ namespace paxs { /// @details 集落をクリアし、地域ごとに指定されたエージェント数になるようにランダムに配置する void init() { settlement_grids.clear(); - randomizeSettlements(); + initRandomizeSettlements(); + randomizeSettlements(0, 0, 255); } /// @brief Run the simulation for the specified number of steps. @@ -130,6 +131,8 @@ namespace paxs { } } + randomizeSettlements(1, 255, 0); + auto delete_agent = [this](const std::uint_least64_t agent_id, const std::uint_least32_t settlement_id, const Vector2 key) { auto it = settlement_grids.find(key.toU64()); if (it != settlement_grids.end()) { @@ -203,31 +206,34 @@ namespace paxs { std::uint_least64_t emigration_count = 0; - /// @brief Randomly place settlements. - /// @brief 集落をランダムに配置する - void randomizeSettlements() noexcept { + // 陸の位置のリストを取得 + std::vector land_positions; + + struct Live { + // 可住地重みリスト + std::vector live_probabilities; + // 可住地の位置 + std::vector habitable_land_positions; + + void emplaceBack(const int live_probabilities_, const std::uint64_t habitable_land_positions_) { + live_probabilities.emplace_back(live_probabilities_); + habitable_land_positions.emplace_back(habitable_land_positions_); + } + }; + std::unique_ptr> live_list; + + /// @brief () + /// @brief 集落をランダムに配置する前の初期化処理 + bool initRandomizeSettlements() { std::cout << "Randomize settlements..." << std::endl; - // 陸の位置のリストを取得 - std::vector land_positions; environment->getLandPositions(land_positions); - struct Live { - // 可住地重みリスト - std::vector live_probabilities; - // 可住地の位置 - std::vector habitable_land_positions; + live_list = std::unique_ptr>(new std::array()); - void emplaceBack(const int live_probabilities_, const std::uint64_t habitable_land_positions_) { - live_probabilities.emplace_back(live_probabilities_); - habitable_land_positions.emplace_back(habitable_land_positions_); - } - }; - - std::unique_ptr> live_list(new std::array()); if (live_list.get() == nullptr) { std::cout << "Low memory" << std::endl; - return; // 処理失敗 + return false; // 処理失敗 } for (const std::uint64_t land_position : land_positions) { @@ -259,14 +265,24 @@ namespace paxs { (*live_list)[ryoseikoku_id].emplaceBack(live_probability, land_position); } } + return true; + } + + /// @brief Randomly place settlements. + /// @brief 集落をランダムに配置する + void randomizeSettlements( + std::size_t ad200, + std::uint_least8_t farming, + std::uint_least8_t hunter_gatherer + ) noexcept { // 令制国と人口のマップ std::unordered_map ryoseikoku_population_map; for (auto& ryoseikoku : japan_provinces->cgetRyoseikokuList()) { - if (ryoseikoku.population_ad200 == 0) { + if (ryoseikoku.population[ad200/*ad200*/] == 0) { continue; } - ryoseikoku_population_map[ryoseikoku.id] = ryoseikoku.population_ad200; + ryoseikoku_population_map[ryoseikoku.id] = ryoseikoku.population[ad200/*ad200*/]; } int all_population = 0; @@ -329,14 +345,15 @@ namespace paxs { std::uniform_int_distribution<> lifespan_dist{ 0, static_cast(set_lifespan - 1) }; // 性別の乱数分布 - settlement.setAgent(Agent(UniqueIdentification::generate(), - 0, // TODO: 名前ID + settlement.setAgent(Agent(UniqueIdentification::generate(), + //0, // TODO: 名前ID lifespan_dist(gen), set_lifespan, genome, - 0, // ((gen() % 2) == 0) ? agent.cgetFarming() : agent.cgetPartnerFarming(), - 255 // ((gen() % 2) == 0) ? agent.cgetHunterGatherer() : agent.cgetPartnerHunterGatherer() + farming, // ((gen() % 2) == 0) ? agent.cgetFarming() : agent.cgetPartnerFarming(), + hunter_gatherer // ((gen() % 2) == 0) ? agent.cgetHunterGatherer() : agent.cgetPartnerHunterGatherer() ), static_cast(i)); + if (farming > 0) ++emigration_count; // 農耕カウント } // 令制国の人口を減らす @@ -356,8 +373,8 @@ namespace paxs { live.habitable_land_positions.pop_back(); } } - StatusDisplayer::displayProgressBar(all_population, all_population); - std::cout << std::endl; + //StatusDisplayer::displayProgressBar(all_population, all_population); + //std::cout << std::endl; // 令制国の人口が残っている場合は、ランダムに配置 for (auto& ryoseikoku_population : ryoseikoku_population_map) { @@ -382,20 +399,21 @@ namespace paxs { std::uniform_int_distribution<> lifespan_dist{ 0, static_cast(set_lifespan - 1) }; // 性別の乱数分布 agents[i] = Agent( - UniqueIdentification::generate(), - 0, // TODO: 名前ID + UniqueIdentification::generate(), + //0, // TODO: 名前ID lifespan_dist(gen), set_lifespan, genome, - 0, // ((gen() % 2) == 0) ? agent.cgetFarming() : agent.cgetPartnerFarming(), - 255 // ((gen() % 2) == 0) ? agent.cgetHunterGatherer() : agent.cgetPartnerHunterGatherer() + farming, // ((gen() % 2) == 0) ? agent.cgetFarming() : agent.cgetPartnerFarming(), + hunter_gatherer // ((gen() % 2) == 0) ? agent.cgetHunterGatherer() : agent.cgetPartnerHunterGatherer() ); + if (farming > 0) ++emigration_count; // 農耕カウント } settlement.addAgents(agents); } } - std::cout << "Done." << std::endl; + //std::cout << "Done." << std::endl; } /// @brief 指定した令制国のIDの集落グリッドを取得 diff --git a/Library/PAX_SAPIENTICA/Simulation/SimulationConst.hpp b/Library/PAX_SAPIENTICA/Simulation/SimulationConst.hpp index 2f95a9e85..7e34a9c36 100644 --- a/Library/PAX_SAPIENTICA/Simulation/SimulationConst.hpp +++ b/Library/PAX_SAPIENTICA/Simulation/SimulationConst.hpp @@ -89,6 +89,12 @@ namespace paxs { // 移動確率の正規化係数 int move_probability_normalization_coefficient = 1000; + // 片親が農耕文化を持ち、もう一方の片親が農耕文化を持たない時の農耕文化継承の優先度 + float child_agriculture_priority = 0.7f; + + // 死産率 + float stillbirth_rate = 0.1f; + private: template void stoiFunc(KeyValueTSV& key_value_tsv_, const std::uint_least32_t key_, Func_&& func_) { @@ -150,6 +156,8 @@ namespace paxs { stoiFunc(kvt, MurMur3::calcHash("min_move_probability"), [&](const std::string& str_) {min_move_probability = std::stoi(str_); }); stoiFunc(kvt, MurMur3::calcHash("max_move_probability"), [&](const std::string& str_) {max_move_probability = std::stoi(str_); }); stoiFunc(kvt, MurMur3::calcHash("move_probability_normalization_coefficient"), [&](const std::string& str_) {move_probability_normalization_coefficient = std::stoi(str_); }); + stoiFunc(kvt, MurMur3::calcHash("child_agriculture_priority"), [&](const std::string& str_) {child_agriculture_priority = std::stof(str_); }); + stoiFunc(kvt, MurMur3::calcHash("stillbirth_rate"), [&](const std::string& str_) {stillbirth_rate = std::stof(str_); }); } diff --git a/Library/PAX_SAPIENTICA/UniqueIdentification.hpp b/Library/PAX_SAPIENTICA/UniqueIdentification.hpp index 60e1db088..e190c1e80 100644 --- a/Library/PAX_SAPIENTICA/UniqueIdentification.hpp +++ b/Library/PAX_SAPIENTICA/UniqueIdentification.hpp @@ -34,7 +34,7 @@ namespace paxs { PAXS_WARNING("The counter has reached the maximum value. Resetting the counter."); reset(); } - return counter++; + return ++counter; } /// @brief Reset the counter.