Skip to content

Commit

Permalink
add: simulation distances
Browse files Browse the repository at this point in the history
  • Loading branch information
AsPJT committed Aug 4, 2024
1 parent 03fe2d9 commit 6deadb7
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 18 deletions.
31 changes: 24 additions & 7 deletions Library/PAX_SAPIENTICA/Simulation/JapanProvinces.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ namespace paxs {
double immigrant_f64 = 0;
double increased_immigration = 0;
std::uint_least32_t mtdna_region_hash = 0;

std::uint_least32_t direction_min_distance = 100;
// std::array<double, 8> direction_weight{};
std::vector<double> direction_weight{};
std::discrete_distribution<> direction_dist{};
};

/// @brief A class that represents a prefecture in Japan.
Expand Down Expand Up @@ -257,22 +262,34 @@ namespace paxs {
sub_menu_v.size() <= getMenuIndex(menu, MurMur3::calcHash("max_pop_placed_per_cell")) ||
sub_menu_v.size() <= getMenuIndex(menu, MurMur3::calcHash("init_pop")) ||
sub_menu_v.size() <= getMenuIndex(menu, MurMur3::calcHash("immigrant")) ||
sub_menu_v.size() <= getMenuIndex(menu, MurMur3::calcHash("mtdna_region"))
sub_menu_v.size() <= getMenuIndex(menu, MurMur3::calcHash("mtdna_region")) ||
sub_menu_v.size() <= getMenuIndex(menu, MurMur3::calcHash("direction_min_distance")) ||
sub_menu_v.size() <= getMenuIndex(menu, MurMur3::calcHash("directions"))
) {
PAXS_WARNING("Failed to read Japan region TSV file: " + district_tsv_path + " at line " + std::to_string(i));
continue;
}
District district;
district.id = static_cast<std::uint_least8_t>(std::stoi(sub_menu_v[menu[MurMur3::calcHash("id")]]));
district.id = static_cast<std::uint_least8_t>(std::stoul(sub_menu_v[menu[MurMur3::calcHash("id")]]));
district.name = sub_menu_v[menu[MurMur3::calcHash("name")]];
district.region_id = static_cast<std::uint_least8_t>(std::stoi(sub_menu_v[menu[MurMur3::calcHash("region")]]));
district.settlement_population_min_ad200 = std::stoi(sub_menu_v[menu[MurMur3::calcHash("min_pop_placed_per_cell")]]);
district.settlement_population_max_ad200 = std::stoi(sub_menu_v[menu[MurMur3::calcHash("max_pop_placed_per_cell")]]);
district.init_pop = std::stoi(sub_menu_v[menu[MurMur3::calcHash("init_pop")]]);
district.immigrant = std::stoi(sub_menu_v[menu[MurMur3::calcHash("immigrant")]]);
district.region_id = static_cast<std::uint_least8_t>(std::stoul(sub_menu_v[menu[MurMur3::calcHash("region")]]));
district.settlement_population_min_ad200 = static_cast<std::uint_least32_t>(std::stoul(sub_menu_v[menu[MurMur3::calcHash("min_pop_placed_per_cell")]]));
district.settlement_population_max_ad200 = static_cast<std::uint_least32_t>(std::stoul(sub_menu_v[menu[MurMur3::calcHash("max_pop_placed_per_cell")]]));
district.init_pop = static_cast<std::uint_least32_t>(std::stoul(sub_menu_v[menu[MurMur3::calcHash("init_pop")]]));
district.immigrant = static_cast<std::uint_least32_t>(std::stoul(sub_menu_v[menu[MurMur3::calcHash("immigrant")]]));
district.immigrant_f64 = static_cast<double>(district.immigrant);
district.increased_immigration = std::stod(sub_menu_v[menu[MurMur3::calcHash("increased_immigration")]]);

district.direction_min_distance = static_cast<std::uint_least32_t>(std::stoul(sub_menu_v[menu[MurMur3::calcHash("direction_min_distance")]]));

std::vector<std::string> direction_split = paxs::StringExtensions::split(sub_menu_v[menu[MurMur3::calcHash("directions")]], '/');
for (std::size_t di = 0; di < direction_split.size() && di < 8; ++di) {
district.direction_weight.emplace_back(std::stod(direction_split[di]));
}
if(district.direction_weight.size() == 0) district.direction_weight.emplace_back(0.0);
// 方向の確率分布を生成
district.direction_dist = std::discrete_distribution<>(district.direction_weight.begin(), district.direction_weight.end());

const std::string& mtdna_region_str = sub_menu_v[menu[MurMur3::calcHash("mtdna_region")]];
district.mtdna_region_hash = MurMur3::calcHash(mtdna_region_str.size(), mtdna_region_str.c_str());
district_list.emplace_back(district);
Expand Down
16 changes: 11 additions & 5 deletions Library/PAX_SAPIENTICA/Simulation/Settlement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ namespace paxs {
/// @brief Move.
/// @brief 移動
/// @return 集落グリッドを移動したかどうか
std::tuple<std::uint_least32_t, Vector2, Vector2> move(std::mt19937& engine) noexcept {
std::tuple<std::uint_least32_t, Vector2, Vector2> move(std::mt19937& engine, District& district_) noexcept {
Vector2 current_key;
Vector2 target_key;

Expand All @@ -327,17 +327,23 @@ namespace paxs {

// 座標を移動
// 移動距離0~max_move_distance
std::uniform_int_distribution<> move_dist(SimulationConstants::getInstance()->min_move_distance, SimulationConstants::getInstance()->max_move_distance);
std::uniform_real_distribution<float> theta_dist(0.0f, static_cast<float>(2.0 * M_PI));

Vector2 current_position = position;
Vector2 target_position = current_position;

int loop_count = 0; // 無限ループ回避用のループ上限値
// 小さい領域のシミュレーションでは無限ループする可能性がある
while (target_position == current_position || !environment->isLive(target_position)) {
float theta = theta_dist(engine);
int distance = move_dist(engine);
// 無限ループに陥った場合は無視
if(loop_count >= 100) return { 0, Vector2(), Vector2() };
int distance = SimulationConstants::getInstance()->move_dist(engine);

// 移動距離が偏りのある方向を指定する距離以上か判定し、方向を格納する
double theta = (distance >= static_cast<int>(district_.direction_min_distance)) ?
SimulationConstants::getInstance()->theta_dist_array[district_.direction_dist(engine)](engine) :
SimulationConstants::getInstance()->theta_dist(engine);
target_position = current_position + Vector2(static_cast<GridType>(std::cos(theta) * distance), static_cast<GridType>(std::sin(theta) * distance));
++loop_count;
}

current_key = current_position / SimulationConstants::getInstance()->grid_length;
Expand Down
18 changes: 12 additions & 6 deletions Library/PAX_SAPIENTICA/Simulation/SettlementSimulator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,22 @@ namespace paxs {
}

void moveSettlement(const std::uint_least32_t id, const Vector2 current_key, const Vector2 target_key) noexcept {
auto it = settlement_grids.find(target_key.to(SettlementGridsType{}));
const auto current_index = current_key.to(SettlementGridsType{});
const auto target_index = target_key.to(SettlementGridsType{});

// ターゲットの地域が登録されているか?
auto it = settlement_grids.find(target_index);
if (it != settlement_grids.end()) {
it->second.moveSettlementToThis(settlement_grids[current_key.to(SettlementGridsType{})].getSettlement(id));
// 登録されている場合はそのターゲット地域へ移動
it->second.moveSettlementToThis(settlement_grids[current_index].getSettlement(id));
}
else {
// 登録されていない場合は新しく地域を作成
SettlementGrid settlement_grid = SettlementGrid(target_key * SimulationConstants::getInstance()->grid_length, environment, gen);
settlement_grid.moveSettlementToThis(settlement_grids[current_key.to(SettlementGridsType{})].getSettlement(id));
settlement_grids[target_key.to(SettlementGridsType{})] = settlement_grid;
settlement_grid.moveSettlementToThis(settlement_grids[current_index].getSettlement(id));
settlement_grids[target_index] = settlement_grid;
}
settlement_grids[current_key.to(SettlementGridsType{})].deleteSettlement(id);
settlement_grids[current_index].deleteSettlement(id);
}

/// @brief Execute the simulation for the one step.
Expand Down Expand Up @@ -174,7 +180,7 @@ namespace paxs {
continue;
}

auto [target_id, current_key, target_key] = settlements[i].move(gen);
auto [target_id, current_key, target_key] = settlements[i].move(gen, japan_provinces->getDistrict(environment->template getData<std::uint_least8_t>(SimulationConstants::getInstance()->district_key, settlements[i].getPosition())));

if (target_id != 0) {
move_list.emplace_back(target_id, current_key, target_key);
Expand Down
20 changes: 20 additions & 0 deletions Library/PAX_SAPIENTICA/Simulation/SimulationConst.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
##########################################################################################*/

#include <array>
#include <cstdint>
#include <random>
#include <string>
Expand All @@ -38,6 +39,10 @@ namespace paxs {
constexpr std::uint_least8_t female_value = 0; // 女性
constexpr std::uint_least8_t male_value = 1; // 男性

constexpr double pi_per_4 = M_PI / 4.0; // π/4
constexpr double pi_per_8 = M_PI / 8.0; // π/8
// constexpr double pi_per_4m8 = pi_per_4 - pi_per_8; // π/4ーπ/8

// std::sqrt(2 * M_PI)
constexpr double sqrt_2_x_pi = static_cast<double>(2.506628275);

Expand Down Expand Up @@ -140,6 +145,20 @@ namespace paxs {
std::uniform_real_distribution<double> random_dist = std::uniform_real_distribution<double>( 0.0, 1.0 ); // 乱数分布
std::uniform_int_distribution<int> step_per_year_dist = std::uniform_int_distribution<int>( 0, 11 ); // 乱数分布

std::uniform_int_distribution<int> move_dist = std::uniform_int_distribution<int>(min_move_distance, max_move_distance);
std::uniform_real_distribution<double> theta_dist = std::uniform_real_distribution<double>(0.0, static_cast<double>(2.0 * M_PI));

std::array<std::uniform_real_distribution<double>, 8> theta_dist_array = {
std::uniform_real_distribution<double>(-pi_per_8, pi_per_8),
std::uniform_real_distribution<double>(pi_per_8, pi_per_8 + pi_per_4),
std::uniform_real_distribution<double>(pi_per_8 + pi_per_4, pi_per_8 + 2* pi_per_4),
std::uniform_real_distribution<double>(pi_per_8 + 2 * pi_per_4, pi_per_8 + 3 * pi_per_4),
std::uniform_real_distribution<double>(pi_per_8 + 3 * pi_per_4, pi_per_8 + 4 * pi_per_4),
std::uniform_real_distribution<double>(pi_per_8 + 4 * pi_per_4, pi_per_8 + 5 * pi_per_4),
std::uniform_real_distribution<double>(pi_per_8 + 5 * pi_per_4, pi_per_8 + 6 * pi_per_4),
std::uniform_real_distribution<double>(pi_per_8 + 7 * pi_per_4, pi_per_8 + 8 * pi_per_4)
};

private:
template<typename Func_>
void stoiFunc(KeyValueTSV<std::string>& key_value_tsv_, const std::uint_least32_t key_, Func_&& func_) {
Expand Down Expand Up @@ -213,6 +232,7 @@ namespace paxs {
stoiFunc(kvt, MurMur3::calcHash("max_hunter_gatherer_settlement_population"), [&](const std::string& str_) {max_hunter_gatherer_settlement_weight = 1.0 / static_cast<std::uint_least64_t>(std::stoul(str_)); });
stoiFunc(kvt, MurMur3::calcHash("min_move_distance"), [&](const std::string& str_) {min_move_distance = static_cast<std::uint_least32_t>(std::stoul(str_)); });
stoiFunc(kvt, MurMur3::calcHash("max_move_distance"), [&](const std::string& str_) {max_move_distance = static_cast<std::uint_least32_t>(std::stoul(str_)); });
move_dist = std::uniform_int_distribution<int>(min_move_distance, max_move_distance);

stoiFunc(kvt, MurMur3::calcHash("move_probability"), [&](const std::string& str_) {move_probability = std::stod(str_); });
stoiFunc(kvt, MurMur3::calcHash("child_agriculture_priority"), [&](const std::string& str_) {child_agriculture_priority = std::stod(str_); });
Expand Down

0 comments on commit 6deadb7

Please sign in to comment.