From e031758cf68535e97045c07f36e2524676447778 Mon Sep 17 00:00:00 2001 From: hop311 Date: Tue, 14 Nov 2023 21:27:39 +0000 Subject: Striped mapmode and improved distributions --- src/openvic-simulation/GameManager.cpp | 131 +++++++++++++-------- src/openvic-simulation/Modifier.hpp | 2 +- src/openvic-simulation/country/CountryInstance.hpp | 2 +- src/openvic-simulation/economy/Good.hpp | 2 +- src/openvic-simulation/history/CountryHistory.hpp | 2 +- src/openvic-simulation/history/ProvinceHistory.hpp | 2 +- src/openvic-simulation/map/Map.cpp | 29 +++-- src/openvic-simulation/map/Map.hpp | 14 ++- src/openvic-simulation/map/Province.cpp | 2 +- src/openvic-simulation/map/Province.hpp | 12 +- src/openvic-simulation/map/Region.cpp | 13 +- src/openvic-simulation/map/Region.hpp | 3 +- src/openvic-simulation/military/Wargoal.hpp | 2 +- src/openvic-simulation/politics/NationalFocus.hpp | 6 +- src/openvic-simulation/pop/Pop.hpp | 2 +- src/openvic-simulation/types/Colour.hpp | 2 +- .../types/IdentifierRegistry.hpp | 23 +--- .../types/fixed_point/FixedPointMap.hpp | 48 ++++++++ 18 files changed, 187 insertions(+), 110 deletions(-) create mode 100644 src/openvic-simulation/types/fixed_point/FixedPointMap.hpp diff --git a/src/openvic-simulation/GameManager.cpp b/src/openvic-simulation/GameManager.cpp index 427fbb1..755ab37 100644 --- a/src/openvic-simulation/GameManager.cpp +++ b/src/openvic-simulation/GameManager.cpp @@ -61,14 +61,58 @@ bool GameManager::expand_building(Province::index_t province_index, std::string_ return province->expand_building(building_type_identifier); } -static constexpr colour_t LOW_ALPHA_VALUE = float_to_alpha_value(0.4f); -static constexpr colour_t HIGH_ALPHA_VALUE = float_to_alpha_value(0.7f); - -static colour_t default_colour(Province const& province) { - /* Nice looking colours to blend with the terrain textures */ - static constexpr colour_t LAND_COLOUR = 0x0D7017; - static constexpr colour_t WATER_COLOUR = 0x4287F5; - return LOW_ALPHA_VALUE | (province.get_water() ? WATER_COLOUR : LAND_COLOUR); +static constexpr colour_t ALPHA_VALUE = float_to_alpha_value(0.5f); + +static constexpr Mapmode::base_stripe_t combine_base_stripe(colour_t base, colour_t stripe) { + return (static_cast(stripe) << (sizeof(colour_t) * 8)) | base; +} + +static constexpr Mapmode::base_stripe_t make_solid_base_stripe(colour_t colour) { + return combine_base_stripe(colour, colour); +} + +static constexpr auto make_solid_base_stripe_func(auto func) { + return [func](Map const& map, Province const& province) -> Mapmode::base_stripe_t { + return make_solid_base_stripe(func(map, province)); + }; +} + +template T> +static constexpr Mapmode::base_stripe_t get_colour_mapmode(T const* item) { + return item != nullptr ? make_solid_base_stripe(ALPHA_VALUE | item->get_colour()) : NULL_COLOUR; +} + +template T> +static constexpr auto get_colour_mapmode(T const*(Province::*get_item)() const) { + return [get_item](Map const& map, Province const& province) -> Mapmode::base_stripe_t { + T const* item = (province.*get_item)(); + return item != nullptr ? make_solid_base_stripe(ALPHA_VALUE | item->get_colour()) : NULL_COLOUR; + }; +} + +template T> +static constexpr Mapmode::base_stripe_t shaded_mapmode(fixed_point_map_t const& map) { + const std::pair, fixed_point_map_const_iterator_t> largest = + get_largest_two_items(map); + if (largest.first != map.end()) { + const colour_t base_colour = ALPHA_VALUE | largest.first->first->get_colour(); + if (largest.second != map.end()) { + /* If second largest is at least a third... */ + if (largest.second->second * 3 >= get_total(map)) { + const colour_t stripe_colour = ALPHA_VALUE | largest.second->first->get_colour(); + return combine_base_stripe(base_colour, stripe_colour); + } + } + return make_solid_base_stripe(base_colour); + } + return NULL_COLOUR; +} + +template T> +static constexpr auto shaded_mapmode(fixed_point_map_t const&(Province::*get_map)() const) { + return [get_map](Map const& map, Province const& province) -> Mapmode::base_stripe_t { + return shaded_mapmode((province.*get_map)()); + }; } bool GameManager::load_hardcoded_defines() { @@ -78,48 +122,39 @@ bool GameManager::load_hardcoded_defines() { const std::vector mapmodes { { "mapmode_terrain", - [](Map const&, Province const& province) -> colour_t { - return default_colour(province); + [](Map const&, Province const& province) -> Mapmode::base_stripe_t { + return NULL_COLOUR; } }, + { + "mapmode_political", get_colour_mapmode(&Province::get_owner) + }, { "mapmode_province", - [](Map const&, Province const& province) -> colour_t { - return HIGH_ALPHA_VALUE | province.get_colour(); - } + make_solid_base_stripe_func([](Map const&, Province const& province) -> colour_t { + return ALPHA_VALUE | province.get_colour(); + }) }, { - "mapmode_region", - [](Map const&, Province const& province) -> colour_t { - Region const* region = province.get_region(); - return region != nullptr ? HIGH_ALPHA_VALUE | region->get_colour() : default_colour(province); - } + "mapmode_region", get_colour_mapmode(&Province::get_region) }, { "mapmode_index", - [](Map const& map, Province const& province) -> colour_t { + make_solid_base_stripe_func([](Map const& map, Province const& province) -> colour_t { const colour_t f = fraction_to_colour_byte(province.get_index(), map.get_province_count() + 1); - return HIGH_ALPHA_VALUE | (f << 16) | (f << 8) | f; - } + return ALPHA_VALUE | (f << 16) | (f << 8) | f; + }) }, { - "mapmode_terrain_type", - [](Map const& map, Province const& province) -> colour_t { - TerrainType const* terrarin_type = province.get_terrain_type(); - return terrarin_type != nullptr ? HIGH_ALPHA_VALUE | terrarin_type->get_colour() : default_colour(province); - } + "mapmode_terrain_type", get_colour_mapmode(&Province::get_terrain_type) }, { - "mapmode_rgo", - [](Map const& map, Province const& province) -> colour_t { - Good const* rgo = province.get_rgo(); - return rgo != nullptr ? HIGH_ALPHA_VALUE | rgo->get_colour() : default_colour(province); - } + "mapmode_rgo", get_colour_mapmode(&Province::get_rgo) }, { "mapmode_infrastructure", - [](Map const& map, Province const& province) -> colour_t { - BuildingInstance const* railroad = province.get_building_by_identifier("building_railroad"); + make_solid_base_stripe_func([](Map const& map, Province const& province) -> colour_t { + BuildingInstance const* railroad = province.get_building_by_identifier("railroad"); if (railroad != nullptr) { colour_t val = fraction_to_colour_byte(railroad->get_current_level(), railroad->get_building().get_max_level() + 1, 0.5f, 1.0f); @@ -133,32 +168,30 @@ bool GameManager::load_hardcoded_defines() { val <<= 8; break; } - return HIGH_ALPHA_VALUE | val; + return ALPHA_VALUE | val; } - return default_colour(province); - } + return NULL_COLOUR; + }) }, { "mapmode_population", - [](Map const& map, Province const& province) -> colour_t { - return HIGH_ALPHA_VALUE | (fraction_to_colour_byte(province.get_total_population(), map.get_highest_province_population() + 1, 0.1f, 1.0f) << 8); - } + make_solid_base_stripe_func([](Map const& map, Province const& province) -> colour_t { + // TODO - explore non-linear scaling to have more variation among non-massive provinces + // TODO - when selecting a province, only show the population of provinces controlled (or owned?) + // by the same country, relative to the most populous province in that set of provinces + return ALPHA_VALUE | (fraction_to_colour_byte( + province.get_total_population(), map.get_highest_province_population() + 1, 0.1f, 1.0f + ) << 8); + }) }, { - "mapmode_culture", - [](Map const& map, Province const& province) -> colour_t { - HasIdentifierAndColour const* largest = get_largest_item(province.get_culture_distribution()).first; - return largest != nullptr ? HIGH_ALPHA_VALUE | largest->get_colour() : default_colour(province); - } + "mapmode_culture", shaded_mapmode(&Province::get_culture_distribution) }, { - "mapmode_religion", - [](Map const& map, Province const& province) -> colour_t { - HasIdentifierAndColour const* largest = get_largest_item(province.get_religion_distribution()).first; - return largest != nullptr ? HIGH_ALPHA_VALUE | largest->get_colour() : default_colour(province); - } + "mapmode_religion", shaded_mapmode(&Province::get_religion_distribution) } }; + for (mapmode_t const& mapmode : mapmodes) { ret &= map.add_mapmode(mapmode.first, mapmode.second); } diff --git a/src/openvic-simulation/Modifier.hpp b/src/openvic-simulation/Modifier.hpp index fc37655..084a0c2 100644 --- a/src/openvic-simulation/Modifier.hpp +++ b/src/openvic-simulation/Modifier.hpp @@ -36,7 +36,7 @@ namespace OpenVic { struct ModifierValue { friend struct ModifierManager; - using effect_map_t = decimal_map_t; + using effect_map_t = fixed_point_map_t; private: effect_map_t values; diff --git a/src/openvic-simulation/country/CountryInstance.hpp b/src/openvic-simulation/country/CountryInstance.hpp index 6510ecf..99461b5 100644 --- a/src/openvic-simulation/country/CountryInstance.hpp +++ b/src/openvic-simulation/country/CountryInstance.hpp @@ -15,7 +15,7 @@ namespace OpenVic { Religion const* PROPERTY_RW(religion); CountryParty const* PROPERTY_RW(ruling_party); Date PROPERTY_RW(last_election); - decimal_map_t PROPERTY(upper_house); + fixed_point_map_t PROPERTY(upper_house); Province const* PROPERTY_RW(capital); GovernmentType const* PROPERTY_RW(government_type); fixed_point_t PROPERTY_RW(plurality); diff --git a/src/openvic-simulation/economy/Good.hpp b/src/openvic-simulation/economy/Good.hpp index ae2d6a9..bec5cca 100644 --- a/src/openvic-simulation/economy/Good.hpp +++ b/src/openvic-simulation/economy/Good.hpp @@ -33,7 +33,7 @@ namespace OpenVic { using price_t = fixed_point_t; static constexpr price_t NULL_PRICE = fixed_point_t::_0(); - using good_map_t = decimal_map_t; + using good_map_t = fixed_point_map_t; private: GoodCategory const& category; diff --git a/src/openvic-simulation/history/CountryHistory.hpp b/src/openvic-simulation/history/CountryHistory.hpp index ffb44c0..ed200bf 100644 --- a/src/openvic-simulation/history/CountryHistory.hpp +++ b/src/openvic-simulation/history/CountryHistory.hpp @@ -31,7 +31,7 @@ namespace OpenVic { std::optional PROPERTY(religion); std::optional PROPERTY(ruling_party); std::optional PROPERTY(last_election); - decimal_map_t PROPERTY(upper_house); + fixed_point_map_t PROPERTY(upper_house); std::optional PROPERTY(capital); std::optional PROPERTY(government_type); std::optional PROPERTY(plurality); diff --git a/src/openvic-simulation/history/ProvinceHistory.hpp b/src/openvic-simulation/history/ProvinceHistory.hpp index 5a18723..313f3a4 100644 --- a/src/openvic-simulation/history/ProvinceHistory.hpp +++ b/src/openvic-simulation/history/ProvinceHistory.hpp @@ -33,7 +33,7 @@ namespace OpenVic { std::optional PROPERTY(life_rating); std::optional PROPERTY(terrain_type); building_level_map_t PROPERTY(buildings); - decimal_map_t PROPERTY(party_loyalties); + fixed_point_map_t PROPERTY(party_loyalties); ProvinceHistoryEntry(Province const& new_province, Date new_date); }; diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index 7e2213e..261a13e 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -24,7 +24,7 @@ Mapmode::index_t Mapmode::get_index() const { return index; } -colour_t Mapmode::get_colour(Map const& map, Province const& province) const { +Mapmode::base_stripe_t Mapmode::get_base_stripe_colours(Map const& map, Province const& province) const { return colour_func ? colour_func(map, province) : NULL_COLOUR; } @@ -254,15 +254,23 @@ bool Map::generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) cons mapmode = &Mapmode::ERROR_MAPMODE; } // Skip past Province::NULL_INDEX - for (size_t i = 0; i < MAPMODE_COLOUR_SIZE; ++i) { + for (size_t i = 0; i < sizeof(Mapmode::base_stripe_t); ++i) { *target++ = 0; } for (Province const& province : provinces.get_items()) { - const colour_t colour = mapmode->get_colour(*this, province); - *target++ = (colour >> 16) & FULL_COLOUR; - *target++ = (colour >> 8) & FULL_COLOUR; - *target++ = colour & FULL_COLOUR; - *target++ = (colour >> 24) & FULL_COLOUR; + const Mapmode::base_stripe_t base_stripe = mapmode->get_base_stripe_colours(*this, province); + const colour_t base_colour = static_cast(base_stripe); + const colour_t stripe_colour = static_cast(base_stripe >> (sizeof(colour_t) * 8)); + + *target++ = (base_colour >> 16) & COLOUR_COMPONENT; // red + *target++ = (base_colour >> 8) & COLOUR_COMPONENT; // green + *target++ = (base_colour >> 0) & COLOUR_COMPONENT; // blue + *target++ = (base_colour >> 24) & COLOUR_COMPONENT; // alpha + + *target++ = (stripe_colour >> 16) & COLOUR_COMPONENT; // red + *target++ = (stripe_colour >> 8) & COLOUR_COMPONENT; // green + *target++ = (stripe_colour >> 0) & COLOUR_COMPONENT; // blue + *target++ = (stripe_colour >> 24) & COLOUR_COMPONENT; // alpha } return ret; } @@ -489,7 +497,7 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain uint8_t const* terrain_data = terrain_bmp.get_pixel_data().data(); std::vector province_checklist(provinces.size()); - std::vector> terrain_type_pixels_list(provinces.size()); + std::vector> terrain_type_pixels_list(provinces.size()); bool ret = true; std::unordered_set unrecognised_province_colours; @@ -553,9 +561,8 @@ bool Map::load_map_images(fs::path const& province_path, fs::path const& terrain size_t missing = 0; for (size_t idx = 0; idx < province_checklist.size(); ++idx) { Province* province = provinces.get_item_by_index(idx); - province->_set_terrain_type( - reinterpret_cast(get_largest_item(terrain_type_pixels_list[idx]).first) - ); + const fixed_point_map_const_iterator_t largest = get_largest_item(terrain_type_pixels_list[idx]); + province->_set_terrain_type(largest != terrain_type_pixels_list[idx].end() ? largest->first : nullptr); province->on_map = province_checklist[idx]; if (!province->on_map) { if (detailed_errors) { diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp index d11ad8e..db67390 100644 --- a/src/openvic-simulation/map/Map.hpp +++ b/src/openvic-simulation/map/Map.hpp @@ -14,7 +14,10 @@ namespace OpenVic { struct Mapmode : HasIdentifier { friend struct Map; - using colour_func_t = std::function; + /* Bottom 32 bits are the base colour, top 32 are the stripe colour, both in ARGB format with the alpha channels + * controlling interpolation with the terrain colour (0 = all terrain, 255 = all corresponding RGB) */ + using base_stripe_t = uint64_t; + using colour_func_t = std::function; using index_t = size_t; private: @@ -29,7 +32,7 @@ namespace OpenVic { Mapmode(Mapmode&&) = default; index_t get_index() const; - colour_t get_colour(Map const& map, Province const& province) const; + base_stripe_t get_base_stripe_colours(Map const& map, Province const& province) const; }; struct GoodManager; @@ -98,7 +101,12 @@ namespace OpenVic { bool add_mapmode(std::string_view identifier, Mapmode::colour_func_t colour_func); IDENTIFIER_REGISTRY_ACCESSORS(mapmode) Mapmode const* get_mapmode_by_index(size_t index) const; - static constexpr size_t MAPMODE_COLOUR_SIZE = 4; + + /* The mapmode colour image contains of a list of base colours and stripe colours. Each colour is four bytes + * in RGBA format, with the alpha value being used to interpolate with the terrain colour, so A = 0 is fully terrain + * and A = 255 is fully the RGB colour packaged with A. The base and stripe colours for each province are packed + * together adjacently, so each province's entry is 8 bytes long. The list contains Province::MAX_INDEX + 1 entries, + * that is the maximum allowed number of provinces plus one for the index-zero "null province". */ bool generate_mapmode_colours(Mapmode::index_t index, uint8_t* target) const; bool setup(BuildingManager const& building_manager, PopManager const& pop_manager); diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp index 4b76210..1b47dea 100644 --- a/src/openvic-simulation/map/Province.cpp +++ b/src/openvic-simulation/map/Province.cpp @@ -16,7 +16,7 @@ Province::index_t Province::get_index() const { return index; } -Region* Province::get_region() const { +Region const* Province::get_region() const { return region; } diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index eda05fb..21a974f 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -65,7 +65,7 @@ namespace OpenVic { private: const index_t index; - Region* region = nullptr; + Region const* region = nullptr; bool on_map = false, has_region = false, water = false; life_rating_t life_rating = 0; colony_status_t colony_status = colony_status_t::STATE; @@ -75,10 +75,10 @@ namespace OpenVic { std::vector pops; Pop::pop_size_t total_population; - decimal_map_t PROPERTY(pop_type_distribution); - decimal_map_t PROPERTY(ideology_distribution); - decimal_map_t PROPERTY(culture_distribution); - decimal_map_t PROPERTY(religion_distribution); + fixed_point_map_t PROPERTY(pop_type_distribution); + fixed_point_map_t PROPERTY(ideology_distribution); + fixed_point_map_t PROPERTY(culture_distribution); + fixed_point_map_t PROPERTY(religion_distribution); std::vector adjacencies; province_positions_t positions; @@ -98,7 +98,7 @@ namespace OpenVic { Province(Province&&) = default; index_t get_index() const; - Region* get_region() const; + Region const* get_region() const; bool get_on_map() const; bool get_has_region() const; bool get_water() const; diff --git a/src/openvic-simulation/map/Region.cpp b/src/openvic-simulation/map/Region.cpp index ac232df..e33d9c9 100644 --- a/src/openvic-simulation/map/Region.cpp +++ b/src/openvic-simulation/map/Region.cpp @@ -65,18 +65,15 @@ ProvinceSet::provinces_t const& ProvinceSet::get_provinces() const { return provinces; } +static constexpr colour_t ERROR_REGION_COLOUR = COLOUR_COMPONENT << 16; + Region::Region(std::string_view new_identifier, provinces_t&& new_provinces, bool new_meta) - : HasIdentifier { new_identifier }, ProvinceSet { std::move(new_provinces) }, meta { new_meta } { + : HasIdentifierAndColour { + new_identifier, new_provinces.size() > 0 ? new_provinces.front()->get_colour() : ERROR_REGION_COLOUR, false, false + }, ProvinceSet { std::move(new_provinces) }, meta { new_meta } { lock(); } bool Region::get_meta() const { return meta; } - -colour_t Region::get_colour() const { - if (empty()) { - return FULL_COLOUR << 16; - } - return get_provinces().front()->get_colour(); -} diff --git a/src/openvic-simulation/map/Region.hpp b/src/openvic-simulation/map/Region.hpp index 157b643..9119b93 100644 --- a/src/openvic-simulation/map/Region.hpp +++ b/src/openvic-simulation/map/Region.hpp @@ -28,7 +28,7 @@ namespace OpenVic { /* REQUIREMENTS: * MAP-6, MAP-44, MAP-48 */ - struct Region : HasIdentifier, ProvinceSet { + struct Region : HasIdentifierAndColour, ProvinceSet { friend struct Map; private: @@ -44,6 +44,5 @@ namespace OpenVic { Region(Region&&) = default; bool get_meta() const; - colour_t get_colour() const; }; } diff --git a/src/openvic-simulation/military/Wargoal.hpp b/src/openvic-simulation/military/Wargoal.hpp index 3700347..b34d64f 100644 --- a/src/openvic-simulation/military/Wargoal.hpp +++ b/src/openvic-simulation/military/Wargoal.hpp @@ -47,7 +47,7 @@ namespace OpenVic { WAR_SCORE_BATTLE_FACTOR, CONSTRUCTION_SPEED }; - using peace_modifiers_t = decimal_map_t; + using peace_modifiers_t = fixed_point_map_t; private: const std::string PROPERTY(sprite); diff --git a/src/openvic-simulation/politics/NationalFocus.hpp b/src/openvic-simulation/politics/NationalFocus.hpp index 7c5e40a..e7d1f90 100644 --- a/src/openvic-simulation/politics/NationalFocus.hpp +++ b/src/openvic-simulation/politics/NationalFocus.hpp @@ -23,9 +23,9 @@ namespace OpenVic { friend struct NationalFocusManager; public: - using pop_promotion_map_t = std::map; - using party_loyalty_map_t = std::map; - using production_map_t = std::map; + using pop_promotion_map_t = fixed_point_map_t; + using party_loyalty_map_t = fixed_point_map_t; + using production_map_t = fixed_point_map_t; private: uint8_t PROPERTY(icon); diff --git a/src/openvic-simulation/pop/Pop.hpp b/src/openvic-simulation/pop/Pop.hpp index 4abb2a9..f7f20fe 100644 --- a/src/openvic-simulation/pop/Pop.hpp +++ b/src/openvic-simulation/pop/Pop.hpp @@ -49,7 +49,7 @@ namespace OpenVic { friend struct PopManager; using sprite_t = uint8_t; - using rebel_units_t = decimal_map_t; + using rebel_units_t = fixed_point_map_t; private: const enum class strata_t { POOR, MIDDLE, RICH } strata; diff --git a/src/openvic-simulation/types/Colour.hpp b/src/openvic-simulation/types/Colour.hpp index e516d5b..7c97b12 100644 --- a/src/openvic-simulation/types/Colour.hpp +++ b/src/openvic-simulation/types/Colour.hpp @@ -15,7 +15,7 @@ namespace OpenVic { * When colour_t is used in a purely graphical context, NULL_COLOUR * should be allowed. */ - static constexpr colour_t NULL_COLOUR = 0, FULL_COLOUR = 0xFF; + static constexpr colour_t NULL_COLOUR = 0, COLOUR_COMPONENT = 0xFF; static constexpr colour_t MAX_COLOUR_RGB = 0xFFFFFF, MAX_COLOUR_ARGB = 0xFFFFFFFF; constexpr colour_t float_to_colour_byte(float f, float min = 0.0f, float max = 1.0f) { diff --git a/src/openvic-simulation/types/IdentifierRegistry.hpp b/src/openvic-simulation/types/IdentifierRegistry.hpp index 662815e..3794dd6 100644 --- a/src/openvic-simulation/types/IdentifierRegistry.hpp +++ b/src/openvic-simulation/types/IdentifierRegistry.hpp @@ -6,6 +6,7 @@ #include #include "openvic-simulation/dataloader/NodeTools.hpp" +#include "openvic-simulation/types/fixed_point/FixedPointMap.hpp" #include "openvic-simulation/utility/Getters.hpp" #include "openvic-simulation/utility/Logger.hpp" @@ -77,22 +78,6 @@ namespace OpenVic { HasIdentifierAndColour& operator=(HasIdentifierAndColour&&) = delete; }; - template - using decimal_map_t = std::map; - - template - constexpr typename decimal_map_t::value_type get_largest_item(decimal_map_t const& map) { - constexpr auto pred = [](typename decimal_map_t::value_type a, typename decimal_map_t::value_type b) -> bool { - return a.second < b.second; - }; - const typename decimal_map_t::const_iterator result = std::max_element(map.begin(), map.end(), pred); - if (result != map.end()) { - return *result; - } else { - return { nullptr, -1 }; - } - } - /* Callbacks for trying to add duplicate keys via UniqueKeyRegistry::add_item */ static bool duplicate_fail_callback(std::string_view registry_name, std::string_view duplicate_identifier) { Logger::error( @@ -274,10 +259,10 @@ namespace OpenVic { } NodeTools::node_callback_t expect_item_decimal_map( - NodeTools::callback_t&&> callback + NodeTools::callback_t&&> callback ) const { return [this, callback](ast::NodeCPtr node) -> bool { - decimal_map_t map; + fixed_point_map_t map; bool ret = expect_item_dictionary([&map](value_type const& key, ast::NodeCPtr value) -> bool { fixed_point_t val; const bool ret = NodeTools::expect_fixed_point(NodeTools::assign_variable_callback(val))(value); @@ -370,7 +355,7 @@ namespace OpenVic { return plural.expect_item_dictionary(callback); \ } \ NodeTools::node_callback_t expect_##singular##_decimal_map( \ - NodeTools::callback_t&&> callback \ + NodeTools::callback_t&&> callback \ ) const { \ return plural.expect_item_decimal_map(callback); \ } diff --git a/src/openvic-simulation/types/fixed_point/FixedPointMap.hpp b/src/openvic-simulation/types/fixed_point/FixedPointMap.hpp new file mode 100644 index 0000000..a7d298b --- /dev/null +++ b/src/openvic-simulation/types/fixed_point/FixedPointMap.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "openvic-simulation/types/fixed_point/FixedPoint.hpp" + +namespace OpenVic { + + template + using fixed_point_map_t = std::map; + + template + using fixed_point_map_value_t = typename fixed_point_map_t::value_type; + + template + using fixed_point_map_const_iterator_t = typename fixed_point_map_t::const_iterator; + + template + constexpr fixed_point_t get_total(fixed_point_map_t const& map) { + fixed_point_t total = 0; + for (auto const& [key, value] : map) { + total += value; + } + return total; + } + + template + constexpr fixed_point_map_const_iterator_t get_largest_item(fixed_point_map_t const& map) { + constexpr auto pred = [](fixed_point_map_value_t a, fixed_point_map_value_t b) -> bool { + return a.second < b.second; + }; + return std::max_element(map.begin(), map.end(), pred); + } + + template + constexpr std::pair, fixed_point_map_const_iterator_t> get_largest_two_items( + fixed_point_map_t const& map + ) { + fixed_point_map_const_iterator_t largest = map.end(), second_largest = map.end(); + for (fixed_point_map_const_iterator_t it = map.begin(); it != map.end(); ++it) { + if (largest == map.end() || it->second > largest->second) { + second_largest = largest; + largest = it; + } else if (second_largest == map.end() || it->second > second_largest->second) { + second_largest = it; + } + } + return std::make_pair(std::move(largest), std::move(second_largest)); + } +} -- cgit v1.2.3-56-ga3b1