From d8baf57d46539da9edba5952f73089bf9a54bdaf Mon Sep 17 00:00:00 2001 From: hop311 Date: Thu, 18 Jul 2024 23:25:38 +0100 Subject: Unit position/country/leader handling + more use of unit branch templates --- src/openvic-simulation/country/CountryInstance.cpp | 106 ++++----- src/openvic-simulation/country/CountryInstance.hpp | 19 +- src/openvic-simulation/map/ProvinceInstance.cpp | 41 ++-- src/openvic-simulation/map/ProvinceInstance.hpp | 27 +-- src/openvic-simulation/military/Deployment.cpp | 15 +- src/openvic-simulation/military/Deployment.hpp | 54 ++--- src/openvic-simulation/military/Leader.hpp | 4 +- src/openvic-simulation/military/UnitInstance.cpp | 16 ++ src/openvic-simulation/military/UnitInstance.hpp | 11 +- .../military/UnitInstanceGroup.cpp | 254 ++++++++++++++------- .../military/UnitInstanceGroup.hpp | 151 +++--------- src/openvic-simulation/military/UnitType.hpp | 13 ++ 12 files changed, 354 insertions(+), 357 deletions(-) (limited to 'src') diff --git a/src/openvic-simulation/country/CountryInstance.cpp b/src/openvic-simulation/country/CountryInstance.cpp index 3e21bab..8d2955b 100644 --- a/src/openvic-simulation/country/CountryInstance.cpp +++ b/src/openvic-simulation/country/CountryInstance.cpp @@ -88,89 +88,63 @@ bool CountryInstance::remove_reform(Reform const* reform_to_remove) { return true; } -void CountryInstance::add_general(General&& new_general) { - generals.emplace(std::move(new_general)); -} - -bool CountryInstance::remove_general(General const* general_to_remove) { - const auto it = generals.get_iterator(general_to_remove); - if (it != generals.end()) { - generals.erase(it); +template +bool CountryInstance::add_unit_instance_group(UnitInstanceGroup& group) { + if (get_unit_instance_groups().emplace(static_cast*>(&group)).second) { return true; + } else { + Logger::error( + "Trying to add already-existing ", Branch == UnitType::branch_t::LAND ? "army" : "navy", " ", + group.get_name(), " to country ", get_identifier() + ); + return false; } - - Logger::error( - "Trying to remove non-existent general ", general_to_remove != nullptr ? general_to_remove->get_name() : "NULL", - " from country ", get_identifier() - ); - return false; } -void CountryInstance::add_admiral(Admiral&& new_admiral) { - admirals.emplace(std::move(new_admiral)); -} - -bool CountryInstance::remove_admiral(Admiral const* admiral_to_remove) { - const auto it = admirals.get_iterator(admiral_to_remove); - if (it != admirals.end()) { - admirals.erase(it); +template +bool CountryInstance::remove_unit_instance_group(UnitInstanceGroup& group) { + if (get_unit_instance_groups().erase(static_cast*>(&group)) > 0) { return true; - } - - Logger::error( - "Trying to remove non-existent admiral ", admiral_to_remove != nullptr ? admiral_to_remove->get_name() : "NULL", - " from country ", get_identifier() - ); - return false; -} - -bool CountryInstance::add_leader(LeaderBase const& new_leader) { - using enum UnitType::branch_t; - - switch (new_leader.get_branch()) { - case LAND: - add_general({ new_leader }); - return true; - - case NAVAL: - add_admiral({ new_leader }); - return true; - - default: + } else { Logger::error( - "Trying to add leader ", new_leader.get_name(), " to country ", get_identifier(), " with invalid branch ", - static_cast(new_leader.get_branch()) + "Trying to remove non-existent ", Branch == UnitType::branch_t::LAND ? "army" : "navy", " ", + group.get_name(), " from country ", get_identifier() ); return false; } } -bool CountryInstance::remove_leader(LeaderBase const* leader_to_remove) { - if (leader_to_remove == nullptr) { - Logger::error("Trying to remvoe null leader from country ", get_identifier()); - return false; - } - - using enum UnitType::branch_t; +template bool CountryInstance::add_unit_instance_group(UnitInstanceGroup&); +template bool CountryInstance::add_unit_instance_group(UnitInstanceGroup&); +template bool CountryInstance::remove_unit_instance_group(UnitInstanceGroup&); +template bool CountryInstance::remove_unit_instance_group(UnitInstanceGroup&); - switch (leader_to_remove->get_branch()) { - case LAND: - remove_general(static_cast(leader_to_remove)); - return true; +template +void CountryInstance::add_leader(LeaderBranched&& leader) { + get_leaders().emplace(std::move(leader)); +} - case NAVAL: - remove_admiral(static_cast(leader_to_remove)); +template +bool CountryInstance::remove_leader(LeaderBranched const* leader) { + plf::colony>& leaders = get_leaders(); + const auto it = leaders.get_iterator(leader); + if (it != leaders.end()) { + leaders.erase(it); return true; - - default: - Logger::error( - "Trying to add leader ", leader_to_remove->get_name(), " to country ", get_identifier(), " with invalid branch ", - static_cast(leader_to_remove->get_branch()) - ); - return false; } + + Logger::error( + "Trying to remove non-existent ", Branch == UnitType::branch_t::LAND ? "general" : "admiral", " ", + leader != nullptr ? leader->get_name() : "NULL", " from country ", get_identifier() + ); + return false; } +template void CountryInstance::add_leader(LeaderBranched&&); +template void CountryInstance::add_leader(LeaderBranched&&); +template bool CountryInstance::remove_leader(LeaderBranched const*); +template bool CountryInstance::remove_leader(LeaderBranched const*); + bool CountryInstance::apply_history_to_country(CountryHistoryEntry const* entry) { if (entry == nullptr) { Logger::error("Trying to apply null country history to ", get_identifier()); diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index 885a5fd..1eaf398 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -54,6 +54,11 @@ namespace OpenVic { plf::colony PROPERTY(generals); plf::colony PROPERTY(admirals); + ordered_set PROPERTY(armies); + ordered_set PROPERTY(navies); + + UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies); + UNIT_BRANCHED_GETTER(get_leaders, generals, admirals); CountryInstance( CountryDefinition const* new_country_definition, decltype(technologies)::keys_t const& technology_keys, @@ -70,13 +75,15 @@ namespace OpenVic { bool add_reform(Reform const* new_reform); bool remove_reform(Reform const* reform_to_remove); - void add_general(General&& new_general); - bool remove_general(General const* general_to_remove); - void add_admiral(Admiral&& new_admiral); - bool remove_admiral(Admiral const* admiral_to_remove); + template + bool add_unit_instance_group(UnitInstanceGroup& group); + template + bool remove_unit_instance_group(UnitInstanceGroup& group); - bool add_leader(LeaderBase const& new_leader); - bool remove_leader(LeaderBase const* leader_to_remove); + template + void add_leader(LeaderBranched&& leader); + template + bool remove_leader(LeaderBranched const* leader); bool apply_history_to_country(CountryHistoryEntry const* entry); }; diff --git a/src/openvic-simulation/map/ProvinceInstance.cpp b/src/openvic-simulation/map/ProvinceInstance.cpp index 1792fe0..6b20cd2 100644 --- a/src/openvic-simulation/map/ProvinceInstance.cpp +++ b/src/openvic-simulation/map/ProvinceInstance.cpp @@ -104,41 +104,36 @@ void ProvinceInstance::tick(Date today) { } } -bool ProvinceInstance::add_army(ArmyInstance& army) { - if (armies.emplace(&army).second) { +template +bool ProvinceInstance::add_unit_instance_group(UnitInstanceGroup& group) { + if (get_unit_instance_groups().emplace(static_cast*>(&group)).second) { return true; } else { - Logger::error("Trying to add already-existing army ", army.get_name(), " to province ", get_identifier()); + Logger::error( + "Trying to add already-existing ", Branch == UnitType::branch_t::LAND ? "army" : "navy", " ", + group.get_name(), " to province ", get_identifier() + ); return false; } } -bool ProvinceInstance::remove_army(ArmyInstance& army) { - if (armies.erase(&army) > 0) { +template +bool ProvinceInstance::remove_unit_instance_group(UnitInstanceGroup& group) { + if (get_unit_instance_groups().erase(static_cast*>(&group)) > 0) { return true; } else { - Logger::error("Trying to remove non-existent army ", army.get_name(), " from province ", get_identifier()); + Logger::error( + "Trying to remove non-existent ", Branch == UnitType::branch_t::LAND ? "army" : "navy", " ", + group.get_name(), " from province ", get_identifier() + ); return false; } } -bool ProvinceInstance::add_navy(NavyInstance& navy) { - if (navies.emplace(&navy).second) { - return true; - } else { - Logger::error("Trying to add already-existing navy ", navy.get_name(), " to province ", get_identifier()); - return false; - } -} - -bool ProvinceInstance::remove_navy(NavyInstance& navy) { - if (navies.erase(&navy) > 0) { - return true; - } else { - Logger::error("Trying to remove non-existent navy ", navy.get_name(), " from province ", get_identifier()); - return false; - } -} +template bool ProvinceInstance::add_unit_instance_group(UnitInstanceGroup&); +template bool ProvinceInstance::add_unit_instance_group(UnitInstanceGroup&); +template bool ProvinceInstance::remove_unit_instance_group(UnitInstanceGroup&); +template bool ProvinceInstance::remove_unit_instance_group(UnitInstanceGroup&); bool ProvinceInstance::setup(BuildingTypeManager const& building_type_manager) { if (buildings_are_locked()) { diff --git a/src/openvic-simulation/map/ProvinceInstance.hpp b/src/openvic-simulation/map/ProvinceInstance.hpp index 4398cd4..ec06e0c 100644 --- a/src/openvic-simulation/map/ProvinceInstance.hpp +++ b/src/openvic-simulation/map/ProvinceInstance.hpp @@ -58,6 +58,8 @@ namespace OpenVic { ordered_set PROPERTY(armies); ordered_set PROPERTY(navies); + UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies); + std::vector PROPERTY(pops); Pop::pop_size_t PROPERTY(total_population); IndexedMap PROPERTY(pop_type_distribution); @@ -89,31 +91,10 @@ namespace OpenVic { void update_gamestate(Date today); void tick(Date today); - bool add_army(ArmyInstance& army); - bool remove_army(ArmyInstance& army); - bool add_navy(NavyInstance& navy); - bool remove_navy(NavyInstance& navy); - template - bool add_unit_instance_group(UnitInstanceGroup& group) { - if constexpr (Branch == UnitType::branch_t::LAND) { - return add_army(static_cast(group)); - } else if constexpr (Branch == UnitType::branch_t::NAVAL) { - return add_navy(static_cast(group)); - } else { - OpenVic::utility::unreachable(); - } - } + bool add_unit_instance_group(UnitInstanceGroup& group); template - bool remove_unit_instance_group(UnitInstanceGroup& group) { - if constexpr (Branch == UnitType::branch_t::LAND) { - return remove_army(static_cast(group)); - } else if constexpr (Branch == UnitType::branch_t::NAVAL) { - return remove_navy(static_cast(group)); - } else { - OpenVic::utility::unreachable(); - } - } + bool remove_unit_instance_group(UnitInstanceGroup& group); bool setup(BuildingTypeManager const& building_type_manager); bool apply_history_to_province(ProvinceHistoryEntry const* entry); diff --git a/src/openvic-simulation/military/Deployment.cpp b/src/openvic-simulation/military/Deployment.cpp index 9c89690..bd176be 100644 --- a/src/openvic-simulation/military/Deployment.cpp +++ b/src/openvic-simulation/military/Deployment.cpp @@ -5,20 +5,17 @@ using namespace OpenVic; using namespace OpenVic::NodeTools; -RegimentDeployment::RegimentDeployment( +UnitDeployment::UnitDeployment( std::string_view new_name, RegimentType const& new_type, ProvinceDefinition const* new_home ) : name { new_name }, type { new_type }, home { new_home } {} -ShipDeployment::ShipDeployment(std::string_view new_name, ShipType const& new_type) +UnitDeployment::UnitDeployment(std::string_view new_name, ShipType const& new_type) : name { new_name }, type { new_type } {} -ArmyDeployment::ArmyDeployment( - std::string_view new_name, ProvinceDefinition const* new_location, std::vector&& new_regiments -) : name { new_name }, location { new_location }, regiments { std::move(new_regiments) } {} - -NavyDeployment::NavyDeployment( - std::string_view new_name, ProvinceDefinition const* new_location, std::vector&& new_ships -) : name { new_name }, location { new_location }, ships { std::move(new_ships) } {} +template +UnitDeploymentGroup::UnitDeploymentGroup( + std::string_view new_name, ProvinceDefinition const* new_location, std::vector<_Unit>&& new_units +) : name { new_name }, location { new_location }, units { std::move(new_units) } {} Deployment::Deployment( std::string_view new_path, std::vector&& new_armies, std::vector&& new_navies, diff --git a/src/openvic-simulation/military/Deployment.hpp b/src/openvic-simulation/military/Deployment.hpp index 9a1d2ee..a53f101 100644 --- a/src/openvic-simulation/military/Deployment.hpp +++ b/src/openvic-simulation/military/Deployment.hpp @@ -5,13 +5,18 @@ #include #include "openvic-simulation/military/Leader.hpp" +#include "openvic-simulation/military/UnitType.hpp" #include "openvic-simulation/types/HasIdentifier.hpp" #include "openvic-simulation/utility/Getters.hpp" namespace OpenVic { struct ProvinceDefinition; - struct RegimentDeployment { + template + struct UnitDeployment; + + template<> + struct UnitDeployment { friend struct DeploymentManager; private: @@ -19,57 +24,52 @@ namespace OpenVic { RegimentType const& PROPERTY(type); ProvinceDefinition const* PROPERTY(home); - RegimentDeployment(std::string_view new_name, RegimentType const& new_type, ProvinceDefinition const* new_home); + UnitDeployment(std::string_view new_name, RegimentType const& new_type, ProvinceDefinition const* new_home); public: - RegimentDeployment(RegimentDeployment&&) = default; + UnitDeployment(UnitDeployment&&) = default; }; - struct ShipDeployment { + using RegimentDeployment = UnitDeployment; + + template<> + struct UnitDeployment { friend struct DeploymentManager; private: std::string PROPERTY(name); ShipType const& PROPERTY(type); - ShipDeployment(std::string_view new_name, ShipType const& new_type); + UnitDeployment(std::string_view new_name, ShipType const& new_type); public: - ShipDeployment(ShipDeployment&&) = default; + UnitDeployment(UnitDeployment&&) = default; }; - struct ArmyDeployment { - friend struct DeploymentManager; - - private: - std::string PROPERTY(name); - ProvinceDefinition const* PROPERTY(location); - std::vector PROPERTY(regiments); + using ShipDeployment = UnitDeployment; - ArmyDeployment( - std::string_view new_name, ProvinceDefinition const* new_location, std::vector&& new_regiments - ); - - public: - ArmyDeployment(ArmyDeployment&&) = default; - }; - - struct NavyDeployment { + template + struct UnitDeploymentGroup { friend struct DeploymentManager; + using _Unit = UnitDeployment; + private: std::string PROPERTY(name); ProvinceDefinition const* PROPERTY(location); - std::vector PROPERTY(ships); + std::vector<_Unit> PROPERTY(units); - NavyDeployment( - std::string_view new_name, ProvinceDefinition const* new_location, std::vector&& new_ships + UnitDeploymentGroup( + std::string_view new_name, ProvinceDefinition const* new_location, std::vector<_Unit>&& new_units ); public: - NavyDeployment(NavyDeployment&&) = default; + UnitDeploymentGroup(UnitDeploymentGroup&&) = default; }; + using ArmyDeployment = UnitDeploymentGroup; + using NavyDeployment = UnitDeploymentGroup; + struct Deployment : HasIdentifier { friend struct DeploymentManager; @@ -85,6 +85,8 @@ namespace OpenVic { public: Deployment(Deployment&&) = default; + + UNIT_BRANCHED_GETTER_CONST(get_unit_deployment_groups, armies, navies); }; struct DefinitionManager; diff --git a/src/openvic-simulation/military/Leader.hpp b/src/openvic-simulation/military/Leader.hpp index 3f8603e..8a272e7 100644 --- a/src/openvic-simulation/military/Leader.hpp +++ b/src/openvic-simulation/military/Leader.hpp @@ -37,7 +37,7 @@ namespace OpenVic { LeaderBase(LeaderBase&&) = default; }; - struct CountryInstance; + struct UnitInstanceManager; template struct UnitInstanceGroup; @@ -48,7 +48,7 @@ namespace OpenVic { template struct LeaderBranched : LeaderBase { - friend struct CountryInstance; + friend struct UnitInstanceManager; friend bool UnitInstanceGroup::set_leader(LeaderBranched* new_leader); private: diff --git a/src/openvic-simulation/military/UnitInstance.cpp b/src/openvic-simulation/military/UnitInstance.cpp index 1f49205..d9f12b9 100644 --- a/src/openvic-simulation/military/UnitInstance.cpp +++ b/src/openvic-simulation/military/UnitInstance.cpp @@ -2,6 +2,22 @@ using namespace OpenVic; +template +UnitInstance::UnitInstance(std::string_view new_unit_name, _UnitType const& new_unit_type) + : unit_name { new_unit_name }, + unit_type { new_unit_type }, + organisation { new_unit_type.get_default_organisation() }, + morale { 0 }, + strength { new_unit_type.get_max_strength() } {} + +template +void UnitInstance::set_unit_name(std::string_view new_unit_name) { + unit_name = new_unit_name; +} + +template struct OpenVic::UnitInstance; +template struct OpenVic::UnitInstance; + UnitInstanceBranched::UnitInstanceBranched( std::string_view new_name, RegimentType const& new_regiment_type, Pop* new_pop ) : UnitInstance { new_name, new_regiment_type }, pop { new_pop } {} diff --git a/src/openvic-simulation/military/UnitInstance.hpp b/src/openvic-simulation/military/UnitInstance.hpp index 1480591..5ff4503 100644 --- a/src/openvic-simulation/military/UnitInstance.hpp +++ b/src/openvic-simulation/military/UnitInstance.hpp @@ -22,19 +22,12 @@ namespace OpenVic { fixed_point_t PROPERTY_RW(strength); protected: - UnitInstance(std::string_view new_unit_name, _UnitType const& new_unit_type) : - unit_name { new_unit_name }, - unit_type { new_unit_type }, - organisation { new_unit_type.get_default_organisation() }, //TODO: modifiers - morale { 0 }, //TODO: modifiers - strength { new_unit_type.get_max_strength() } {} + UnitInstance(std::string_view new_unit_name, _UnitType const& new_unit_type); public: UnitInstance(UnitInstance&&) = default; - void set_unit_name(std::string_view new_unit_name) { - unit_name = new_unit_name; - } + void set_unit_name(std::string_view new_unit_name); }; struct Pop; diff --git a/src/openvic-simulation/military/UnitInstanceGroup.cpp b/src/openvic-simulation/military/UnitInstanceGroup.cpp index 46fb992..80ca3a9 100644 --- a/src/openvic-simulation/military/UnitInstanceGroup.cpp +++ b/src/openvic-simulation/military/UnitInstanceGroup.cpp @@ -15,100 +15,179 @@ MovementInfo::MovementInfo() : path {}, movement_progress {} {} MovementInfo::MovementInfo(ProvinceInstance const* starting_province, ProvinceInstance const* target_province) : path { starting_province, target_province }, movement_progress { 0 } {} -UnitInstanceGroupBranched::UnitInstanceGroupBranched( - std::string_view new_name, - std::vector&& new_units, - _Leader* new_leader, - CountryInstance* new_country -) : UnitInstanceGroup { new_name, std::move(new_units), new_leader, new_country } {} +template +UnitInstanceGroup::UnitInstanceGroup( + std::string_view new_name, std::vector<_UnitInstance*>&& new_units +) : name { new_name }, + units { std::move(new_units) }, + leader { nullptr }, + position { nullptr }, + country { nullptr } {} + +template +size_t UnitInstanceGroup::get_unit_count() const { + return units.size(); +} -UnitInstanceGroupBranched::UnitInstanceGroupBranched( - std::string_view new_name, - std::vector&& new_units, - _Leader* new_leader, - CountryInstance* new_country -) : UnitInstanceGroup { new_name, std::move(new_units), new_leader, new_country } {} +template +bool UnitInstanceGroup::empty() const { + return units.empty(); +} -bool UnitInstanceManager::generate_regiment(RegimentDeployment const& regiment_deployment, RegimentInstance*& regiment) { - // TODO - get pop from Province regiment_deployment.get_home() - RegimentInstance& regiment_instance = - *regiments.insert({ regiment_deployment.get_name(), regiment_deployment.get_type(), nullptr }); +template +size_t UnitInstanceGroup::get_unit_category_count(UnitType::unit_category_t unit_category) const { + return std::count_if(units.begin(), units.end(), [unit_category](_UnitInstance const* unit) { + return unit->get_unit_type().get_unit_category() == unit_category; + }); +} - regiment = ®iment_instance; +template +UnitType const* UnitInstanceGroup::get_display_unit_type() const { + if (units.empty()) { + return nullptr; + } - return true; -} + fixed_point_map_t weighted_unit_types; -bool UnitInstanceManager::generate_ship(ShipDeployment const& ship_deployment, ShipInstance*& ship) { - ShipInstance& ship_instance = *ships.insert({ ship_deployment.get_name(), ship_deployment.get_type() }); + for (_UnitInstance const* unit : units) { + UnitType const& unit_type = unit->get_unit_type(); + weighted_unit_types[&unit_type] += unit_type.get_weighted_value(); + } - ship = &ship_instance; + return get_largest_item_tie_break( + weighted_unit_types, + [](UnitType const* lhs, UnitType const* rhs) -> bool { + return lhs->get_weighted_value() < rhs->get_weighted_value(); + } + )->first; +} - return true; +template +void UnitInstanceGroup::set_name(std::string_view new_name) { + name = new_name; } -bool UnitInstanceManager::generate_army( - MapInstance& map_instance, CountryInstance& country, ArmyDeployment const& army_deployment -) { - if (army_deployment.get_regiments().empty()) { - Logger::error( - "Trying to generate army \"", army_deployment.get_name(), "\" with no regiments for country \"", - country.get_identifier(), "\"" - ); - return false; +template +bool UnitInstanceGroup::set_position(ProvinceInstance* new_position) { + bool ret = true; + + if (position != new_position) { + if (position != nullptr) { + ret &= position->remove_unit_instance_group(*this); + } + + position = new_position; + + if (position != nullptr) { + ret &= position->add_unit_instance_group(*this); + } } - if (army_deployment.get_location() == nullptr) { - Logger::error( - "Trying to generate army \"", army_deployment.get_name(), "\" with no location for country \"", - country.get_identifier(), "\"" - ); - return false; + return ret; +} + +template +bool UnitInstanceGroup::set_country(CountryInstance* new_country) { + bool ret = true; + + if (country != new_country) { + if (country != nullptr) { + ret &= country->remove_unit_instance_group(*this); + } + + country = new_country; + + if (country != nullptr) { + ret &= country->add_unit_instance_group(*this); + } } + return ret; +} + +template +bool UnitInstanceGroup::set_leader(_Leader* new_leader) { bool ret = true; - std::vector army_regiments; + if (leader != new_leader) { + if (leader != nullptr) { + if (leader->unit_instance_group == this) { + leader->unit_instance_group = nullptr; + } else { + Logger::error( + "Mismatch between leader and unit instance group: group ", name, " has leader ", + leader->get_name(), " but the leader has group ", leader->get_unit_instance_group() != nullptr + ? leader->get_unit_instance_group()->get_name() : "NULL" + ); + ret = false; + } + } - for (RegimentDeployment const& regiment_deployment : army_deployment.get_regiments()) { - RegimentInstance* regiment = nullptr; + leader = new_leader; - ret &= generate_regiment(regiment_deployment, regiment); + if (leader != nullptr) { + if (leader->unit_instance_group != nullptr) { + if (leader->unit_instance_group != this) { + ret &= leader->unit_instance_group->set_leader(nullptr); + } else { + Logger::error("Leader ", leader->get_name(), " already leads group ", name, "!"); + ret = false; + } + } - if (regiment != nullptr) { - army_regiments.push_back(regiment); + leader->unit_instance_group = static_cast*>(this); } } - if (army_regiments.empty()) { - Logger::error( - "Failed to generate any regiments for army \"", army_deployment.get_name(), "\" for country \"", - country.get_identifier(), "\"" - ); - return false; - } + return ret; +} - ArmyInstance& army_instance = *armies.insert({ army_deployment.get_name(), std::move(army_regiments), nullptr, &country }); +template struct OpenVic::UnitInstanceGroup; +template struct OpenVic::UnitInstanceGroup; - army_instance.set_position(map_instance.get_province_instance_from_const(army_deployment.get_location())); +UnitInstanceGroupBranched::UnitInstanceGroupBranched( + std::string_view new_name, + std::vector&& new_units +) : UnitInstanceGroup { new_name, std::move(new_units) } {} - return ret; +UnitInstanceGroupBranched::UnitInstanceGroupBranched( + std::string_view new_name, + std::vector&& new_units +) : UnitInstanceGroup { new_name, std::move(new_units) } {} + +template +bool UnitInstanceManager::generate_unit_instance( + UnitDeployment const& unit_deployment, UnitInstanceBranched*& unit_instance +) { + unit_instance = &*get_unit_instances().insert( + [&unit_deployment]() -> UnitInstanceBranched { + if constexpr (Branch == UnitType::branch_t::LAND) { + // TODO - get pop from Province unit_deployment.get_home() + return { unit_deployment.get_name(), unit_deployment.get_type(), nullptr }; + } else if constexpr (Branch == UnitType::branch_t::NAVAL) { + return { unit_deployment.get_name(), unit_deployment.get_type() }; + } + }() + ); + + return true; } -bool UnitInstanceManager::generate_navy( - MapInstance& map_instance, CountryInstance& country, NavyDeployment const& navy_deployment +template +bool UnitInstanceManager::generate_unit_instance_group( + MapInstance& map_instance, CountryInstance& country, UnitDeploymentGroup const& unit_deployment_group ) { - if (navy_deployment.get_ships().empty()) { + if (unit_deployment_group.get_units().empty()) { Logger::error( - "Trying to generate navy \"", navy_deployment.get_name(), "\" with no ships for country \"", + "Trying to generate unit group \"", unit_deployment_group.get_name(), "\" with no units for country \"", country.get_identifier(), "\"" ); return false; } - if (navy_deployment.get_location() == nullptr) { + if (unit_deployment_group.get_location() == nullptr) { Logger::error( - "Trying to generate navy \"", navy_deployment.get_name(), "\" with no location for country \"", + "Trying to generate unit group \"", unit_deployment_group.get_name(), "\" with no location for country \"", country.get_identifier(), "\"" ); return false; @@ -116,29 +195,34 @@ bool UnitInstanceManager::generate_navy( bool ret = true; - std::vector navy_ships; + std::vector*> unit_instances; - for (ShipDeployment const& ship_deployment : navy_deployment.get_ships()) { - ShipInstance* ship = nullptr; + for (UnitDeployment const& unit_deployment : unit_deployment_group.get_units()) { + UnitInstanceBranched* unit_instance = nullptr; - ret &= generate_ship(ship_deployment, ship); + ret &= generate_unit_instance(unit_deployment, unit_instance); - if (ship != nullptr) { - navy_ships.push_back(ship); + if (unit_instance != nullptr) { + unit_instances.push_back(unit_instance); } } - if (navy_ships.empty()) { + if (unit_instances.empty()) { Logger::error( - "Failed to generate any ships for navy \"", navy_deployment.get_name(), "\" for country \"", + "Failed to generate any units for unit group \"", unit_deployment_group.get_name(), "\" for country \"", country.get_identifier(), "\"" ); return false; } - NavyInstance& navy_intance = *navies.insert({ navy_deployment.get_name(), std::move(navy_ships), nullptr, &country }); + UnitInstanceGroupBranched& unit_instance_group = *get_unit_instance_groups().insert({ + unit_deployment_group.get_name(), std::move(unit_instances) + }); - navy_intance.set_position(map_instance.get_province_instance_from_const(navy_deployment.get_location())); + ret &= unit_instance_group.set_position( + map_instance.get_province_instance_from_const(unit_deployment_group.get_location()) + ); + ret &= unit_instance_group.set_country(&country); return ret; } @@ -153,16 +237,32 @@ bool UnitInstanceManager::generate_deployment( bool ret = true; - for (ArmyDeployment const& army_deployment : deployment->get_armies()) { - ret &= generate_army(map_instance, country, army_deployment); - } + const auto generate_group = [&]() -> void { + for (UnitDeploymentGroup const& unit_deployment_group : deployment->get_unit_deployment_groups()) { + ret &= generate_unit_instance_group(map_instance, country, unit_deployment_group); + } + }; - for (NavyDeployment const& navy_deployment : deployment->get_navies()) { - ret &= generate_navy(map_instance, country, navy_deployment); - } + using enum UnitType::branch_t; + + generate_group.template operator()(); + generate_group.template operator()(); for (LeaderBase const& leader : deployment->get_leaders()) { - ret &= country.add_leader(leader); + switch (leader.get_branch()) { + case LAND: + country.add_leader({ leader }); + break; + case NAVAL: + country.add_leader({ leader }); + break; + default: + Logger::error( + "Invalid branch ", static_cast(leader.get_branch()), " for leader \"", leader.get_name(), + "\", cannot add to country ", country.get_identifier() + ); + ret = false; + } } return ret; diff --git a/src/openvic-simulation/military/UnitInstanceGroup.hpp b/src/openvic-simulation/military/UnitInstanceGroup.hpp index 54aac3d..4fe0cba 100644 --- a/src/openvic-simulation/military/UnitInstanceGroup.hpp +++ b/src/openvic-simulation/military/UnitInstanceGroup.hpp @@ -6,11 +6,10 @@ #include -#include "openvic-simulation/map/ProvinceInstance.hpp" #include "openvic-simulation/military/UnitInstance.hpp" +#include "openvic-simulation/military/UnitType.hpp" #include "openvic-simulation/types/fixed_point/FixedPoint.hpp" #include "openvic-simulation/utility/Getters.hpp" -#include "openvic-simulation/utility/Utility.hpp" namespace OpenVic { struct ProvinceInstance; @@ -31,9 +30,6 @@ namespace OpenVic { struct CountryInstance; - template - struct UnitInstanceGroupBranched; - template struct UnitInstanceGroup { using _UnitInstance = UnitInstanceBranched; @@ -52,110 +48,27 @@ namespace OpenVic { UnitInstanceGroup( std::string_view new_name, - std::vector<_UnitInstance*>&& new_units, - _Leader* new_leader, - CountryInstance* new_country - ) : name { new_name }, - units { std::move(new_units) }, - leader { nullptr }, - position { nullptr }, - country { new_country } { - set_leader(new_leader); - } + std::vector<_UnitInstance*>&& new_units + ); public: UnitInstanceGroup(UnitInstanceGroup&&) = default; UnitInstanceGroup(UnitInstanceGroup const&) = delete; - void set_name(std::string_view new_name) { - name = new_name; - } - - size_t get_unit_count() const { - return units.size(); - } - - bool empty() const { - return units.empty(); - } - - size_t get_unit_category_count(UnitType::unit_category_t unit_category) const { - return std::count_if(units.begin(), units.end(), [unit_category](_UnitInstance const* unit) { - return unit->unit_type.get_unit_category() == unit_category; - }); - } - - UnitType const* get_display_unit_type() const { - if (units.empty()) { - return nullptr; - } - - fixed_point_map_t weighted_unit_types; - - for (_UnitInstance const* unit : units) { - UnitType const& unit_type = unit->get_unit_type(); - weighted_unit_types[&unit_type] += unit_type.get_weighted_value(); - } - - return get_largest_item_tie_break( - weighted_unit_types, - [](UnitType const* lhs, UnitType const* rhs) -> bool { - return lhs->get_weighted_value() < rhs->get_weighted_value(); - } - )->first; - } - - void set_position(ProvinceInstance* new_position) { - if (position != new_position) { - if (position != nullptr) { - position->remove_unit_instance_group(*this); - } - - position = new_position; - - if (position != nullptr) { - position->add_unit_instance_group(*this); - } - } - } - - bool set_leader(_Leader* new_leader) { - bool ret = true; - - if (leader != new_leader) { - if (leader != nullptr) { - if (leader->unit_instance_group == this) { - leader->unit_instance_group = nullptr; - } else { - Logger::error( - "Mismatch between leader and unit instance group: group ", name, " has leader ", - leader->get_name(), " but the leader has group ", leader->get_unit_instance_group() != nullptr - ? leader->get_unit_instance_group()->get_name() : "NULL" - ); - ret = false; - } - } - - leader = new_leader; - - if (leader != nullptr) { - if (leader->unit_instance_group != nullptr) { - if (leader->unit_instance_group != this) { - ret &= leader->unit_instance_group->set_leader(nullptr); - } else { - Logger::error("Leader ", leader->get_name(), " already leads group ", name, "!"); - ret = false; - } - } - - leader->unit_instance_group = static_cast*>(this); - } - } - - return ret; - } + size_t get_unit_count() const; + bool empty() const; + size_t get_unit_category_count(UnitType::unit_category_t unit_category) const; + UnitType const* get_display_unit_type() const; + + void set_name(std::string_view new_name); + bool set_position(ProvinceInstance* new_position); + bool set_country(CountryInstance* new_country); + bool set_leader(_Leader* new_leader); }; + template + struct UnitInstanceGroupBranched; + template<> struct UnitInstanceGroupBranched : UnitInstanceGroup { friend struct UnitInstanceManager; @@ -163,9 +76,7 @@ namespace OpenVic { private: UnitInstanceGroupBranched( std::string_view new_name, - std::vector&& new_units, - _Leader* new_leader, - CountryInstance* new_country + std::vector&& new_units ); public: @@ -183,9 +94,7 @@ namespace OpenVic { UnitInstanceGroupBranched( std::string_view new_name, - std::vector&& new_ships, - _Leader* new_leader, - CountryInstance* new_country + std::vector&& new_ships ); public: @@ -194,11 +103,13 @@ namespace OpenVic { using NavyInstance = UnitInstanceGroupBranched; - struct RegimentDeployment; - struct ShipDeployment; + template + struct UnitDeployment; + + template + struct UnitDeploymentGroup; + struct MapInstance; - struct ArmyDeployment; - struct NavyDeployment; struct Deployment; struct UnitInstanceManager { @@ -206,13 +117,21 @@ namespace OpenVic { plf::colony PROPERTY(regiments); plf::colony PROPERTY(ships); + UNIT_BRANCHED_GETTER(get_unit_instances, regiments, ships); + plf::colony PROPERTY(armies); plf::colony PROPERTY(navies); - bool generate_regiment(RegimentDeployment const& regiment_deployment, RegimentInstance*& regiment); - bool generate_ship(ShipDeployment const& ship_deployment, ShipInstance*& ship); - bool generate_army(MapInstance& map_instance, CountryInstance& country, ArmyDeployment const& army_deployment); - bool generate_navy(MapInstance& map_instance, CountryInstance& country, NavyDeployment const& navy_deployment); + UNIT_BRANCHED_GETTER(get_unit_instance_groups, armies, navies); + + template + bool generate_unit_instance( + UnitDeployment const& unit_deployment, UnitInstanceBranched*& unit_instance + ); + template + bool generate_unit_instance_group( + MapInstance& map_instance, CountryInstance& country, UnitDeploymentGroup const& unit_deployment_group + ); public: bool generate_deployment(MapInstance& map_instance, CountryInstance& country, Deployment const* deployment); diff --git a/src/openvic-simulation/military/UnitType.hpp b/src/openvic-simulation/military/UnitType.hpp index 1642f22..6bd7392 100644 --- a/src/openvic-simulation/military/UnitType.hpp +++ b/src/openvic-simulation/military/UnitType.hpp @@ -74,6 +74,19 @@ namespace OpenVic { UnitType(UnitType&&) = default; }; +#define _UNIT_BRANCHED_GETTER(name, land, naval, const) \ + template \ + constexpr auto const& name() const { \ + if constexpr (Branch == UnitType::branch_t::LAND) { \ + return land; \ + } else if constexpr (Branch == UnitType::branch_t::NAVAL) { \ + return naval; \ + } \ + } + +#define UNIT_BRANCHED_GETTER(name, land, naval) _UNIT_BRANCHED_GETTER(name, land, naval, ) +#define UNIT_BRANCHED_GETTER_CONST(name, land, naval) _UNIT_BRANCHED_GETTER(name, land, naval, const) + template struct UnitTypeBranched; -- cgit v1.2.3-56-ga3b1