diff options
Diffstat (limited to 'src/openvic-simulation/map')
-rw-r--r-- | src/openvic-simulation/map/Building.cpp | 2 | ||||
-rw-r--r-- | src/openvic-simulation/map/Map.cpp | 172 | ||||
-rw-r--r-- | src/openvic-simulation/map/Map.hpp | 18 | ||||
-rw-r--r-- | src/openvic-simulation/map/Province.cpp | 54 | ||||
-rw-r--r-- | src/openvic-simulation/map/Province.hpp | 30 | ||||
-rw-r--r-- | src/openvic-simulation/map/Region.cpp | 17 | ||||
-rw-r--r-- | src/openvic-simulation/map/Region.hpp | 19 |
7 files changed, 216 insertions, 96 deletions
diff --git a/src/openvic-simulation/map/Building.cpp b/src/openvic-simulation/map/Building.cpp index 6e5cf18..eba2049 100644 --- a/src/openvic-simulation/map/Building.cpp +++ b/src/openvic-simulation/map/Building.cpp @@ -117,7 +117,7 @@ bool BuildingManager::generate_province_buildings(Province& province) const { return false; } bool ret = true; - if (!province.is_water()) { + if (!province.get_water()) { for (BuildingType const& type : building_types.get_items()) { ret &= province.add_building({ type }); } diff --git a/src/openvic-simulation/map/Map.cpp b/src/openvic-simulation/map/Map.cpp index 728fc42..3b06c66 100644 --- a/src/openvic-simulation/map/Map.cpp +++ b/src/openvic-simulation/map/Map.cpp @@ -7,6 +7,7 @@ #include "openvic-simulation/utility/Logger.hpp" using namespace OpenVic; +using namespace OpenVic::NodeTools; Mapmode::Mapmode(const std::string_view new_identifier, index_t new_index, colour_func_t new_colour_func) : HasIdentifier { new_identifier }, @@ -53,10 +54,6 @@ bool Map::add_province(const std::string_view identifier, colour_t colour) { return provinces.add_item(std::move(new_province)); } -void Map::lock_provinces() { - provinces.lock(); -} - bool Map::set_water_province(const std::string_view identifier) { if (water_provinces.is_locked()) { Logger::error("The map's water provinces have already been locked!"); @@ -67,7 +64,7 @@ bool Map::set_water_province(const std::string_view identifier) { Logger::error("Unrecognised water province identifier: ", identifier); return false; } - if (province->is_water()) { + if (province->get_water()) { Logger::warning("Province ", identifier, " is already a water province!"); return true; } @@ -98,63 +95,40 @@ bool Map::add_region(const std::string_view identifier, std::vector<std::string_ Logger::error("Invalid region identifier - empty!"); return false; } - Region new_region { identifier }; - bool ret = true; + Region::provinces_t provinces; + provinces.reserve(province_identifiers.size()); + bool meta = false, ret = true; for (const std::string_view province_identifier : province_identifiers) { Province* province = get_province_by_identifier(province_identifier); if (province != nullptr) { - if (new_region.contains_province(province)) { + if (std::find(provinces.begin(), provinces.end(), province) != provinces.end()) { Logger::error("Duplicate province identifier ", province_identifier, " in region ", identifier); ret = false; } else { - size_t other_region_index = reinterpret_cast<size_t>(province->get_region()); - if (other_region_index != 0) { - other_region_index--; - if (other_region_index < regions.size()) - Logger::error("Cannot add province ", province_identifier, " to region ", identifier, " - it is already part of ", regions.get_item_by_index(other_region_index)->get_identifier()); - else - Logger::error("Cannot add province ", province_identifier, " to region ", identifier, " - it is already part of an unknown region with index ", other_region_index); - ret = false; - } else if (!new_region.add_province(province)) { - Logger::error("Failed to add province ", province_identifier, " to region ", identifier); - ret = false; + if (province->get_has_region()) { + meta = true; } + provinces.push_back(province); } } else { Logger::error("Invalid province identifier ", province_identifier, " for region ", identifier); ret = false; } } - new_region.lock(); - if (new_region.empty()) { - Logger::error("No valid provinces in list for ", identifier); - return false; + if (provinces.empty()) { + Logger::warning("No valid provinces in list for ", identifier); + return ret; } - // Used to detect provinces listed in multiple regions, will - // be corrected once regions is stable (i.e. lock_regions). - Region* tmp_region_index = reinterpret_cast<Region*>(regions.size()); - for (Province* province : new_region.get_provinces()) - province->region = tmp_region_index; - ret &= regions.add_item(std::move(new_region)); + if (!meta) { + for (Province* province : provinces) { + province->has_region = true; + } + } + ret &= regions.add_item({ identifier, std::move(provinces), meta }); return ret; } -void Map::lock_regions() { - regions.lock(); - for (Region& region : regions.get_items()) - for (Province* province : region.get_provinces()) - province->region = ®ion; -} - -size_t Map::get_province_count() const { - return provinces.size(); -} - -std::vector<Province> const& Map::get_provinces() const { - return provinces.get_items(); -} - Province* Map::get_province_by_index(Province::index_t index) { return index != Province::NULL_INDEX ? provinces.get_item_by_index(index - 1) : nullptr; } @@ -163,14 +137,6 @@ Province const* Map::get_province_by_index(Province::index_t index) const { return index != Province::NULL_INDEX ? provinces.get_item_by_index(index - 1) : nullptr; } -Province* Map::get_province_by_identifier(const std::string_view identifier) { - return provinces.get_item_by_identifier(identifier); -} - -Province const* Map::get_province_by_identifier(const std::string_view identifier) const { - return provinces.get_item_by_identifier(identifier); -} - Province::index_t Map::get_index_from_colour(colour_t colour) const { const colour_index_map_t::const_iterator it = colour_index_map.find(colour); if (it != colour_index_map.end()) return it->second; @@ -216,22 +182,6 @@ Province const* Map::get_selected_province() const { return get_province_by_index(get_selected_province_index()); } -Region* Map::get_region_by_identifier(const std::string_view identifier) { - return regions.get_item_by_identifier(identifier); -} - -Region const* Map::get_region_by_identifier(const std::string_view identifier) const { - return regions.get_item_by_identifier(identifier); -} - -size_t Map::get_region_count() const { - return regions.size(); -} - -std::vector<Region> const& Map::get_regions() const { - return regions.get_items(); -} - static colour_t colour_at(uint8_t const* colour_data, int32_t idx) { idx *= 3; return (colour_data[idx] << 16) | (colour_data[idx + 1] << 8) | colour_data[idx + 2]; @@ -336,6 +286,9 @@ bool Map::generate_province_shape_image(size_t new_width, size_t new_height, uin Logger::error("Province image is missing ", missing, " province colours"); ret = false; } + + ret &= _generate_province_adjacencies(); + return ret; } @@ -419,9 +372,6 @@ bool Map::setup(GoodManager const& good_manager, BuildingManager const& building bool ret = true; for (Province& province : provinces.get_items()) { province.clear_pops(); - // Set all land provinces to have an RGO based on their index to test them - if (!province.is_water() && good_manager.get_good_count() > 0) - province.rgo = good_manager.get_good_by_index(province.get_index() % good_manager.get_good_count()); ret &= building_manager.generate_province_buildings(province); } return ret; @@ -503,3 +453,83 @@ bool Map::load_province_definitions(std::vector<LineObject> const& lines) { lock_provinces(); return ret; } + +bool Map::load_province_positions(BuildingManager const& building_manager, ast::NodeCPtr root) { + return expect_province_dictionary( + [&building_manager](Province& province, ast::NodeCPtr node) -> bool { + return province.load_positions(building_manager, node); + } + )(root); +} + +bool Map::load_region_file(ast::NodeCPtr root) { + const bool ret = expect_dictionary_reserve_length( + regions, + [this](std::string_view region_identifier, ast::NodeCPtr region_node) -> bool { + std::vector<std::string_view> province_identifiers; + bool ret = expect_list_reserve_length( + province_identifiers, + expect_identifier([&province_identifiers](std::string_view identifier) -> bool { + province_identifiers.push_back(identifier); + return true; + }) + )(region_node); + ret &= add_region(region_identifier, province_identifiers); + return ret; + } + )(root); + lock_regions(); + for (Region& region : regions.get_items()) { + if (!region.meta) { + for (Province* province : region.get_provinces()) { + if (!province->get_has_region()) { + Logger::error("Province in non-meta region without has_region set: ", province->get_identifier()); + province->has_region = true; + } + province->region = ®ion; + } + } + } + for (Province& province : provinces.get_items()) { + const bool region_null = province.get_region() == nullptr; + if (province.get_has_region() == region_null) { + Logger::error("Province has_region / region mismatch: has_region = ", province.get_has_region(), ", region = ", province.get_region()); + province.has_region = !region_null; + } + } + return ret; +} + +bool Map::_generate_province_adjacencies() { + bool changed = false; + + auto generate_adjacency = [&] (shape_pixel_t cur_pixel, size_t x, size_t y) -> bool { + size_t idx = x + y * width; + shape_pixel_t neighbour_pixel = province_shape_image[idx]; + if (cur_pixel.index != neighbour_pixel.index) { + Province* cur = get_province_by_index(cur_pixel.index); + Province* neighbour = get_province_by_index(neighbour_pixel.index); + if(cur != nullptr && neighbour != nullptr) { + cur->add_adjacency(neighbour, 0, 0); + neighbour->add_adjacency(cur, 0, 0); + return true; + } else Logger::error( + "Couldn't find province(s): current = ", cur, " (", cur_pixel.index, + "), neighbour = ", neighbour, " (", neighbour_pixel.index, ")" + ); + } + return false; + }; + + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + shape_pixel_t cur = province_shape_image[x + y * width]; + if(x + 1 < width) + changed |= generate_adjacency(cur, x + 1, y); + if(y + 1 < height) + changed |= generate_adjacency(cur, x, y + 1); + } + } + + return changed; +} diff --git a/src/openvic-simulation/map/Map.hpp b/src/openvic-simulation/map/Map.hpp index 71719e2..163a21f 100644 --- a/src/openvic-simulation/map/Map.hpp +++ b/src/openvic-simulation/map/Map.hpp @@ -61,24 +61,23 @@ namespace OpenVic { Pop::pop_size_t highest_province_population, total_map_population; Province::index_t get_index_from_colour(colour_t colour) const; + bool _generate_province_adjacencies(); public: Map(); bool add_province(const std::string_view identifier, colour_t colour); - void lock_provinces(); + IDENTIFIER_REGISTRY_ACCESSORS(Province, province) + IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(Province, province) bool set_water_province(const std::string_view identifier); bool set_water_province_list(std::vector<std::string_view> const& list); void lock_water_provinces(); bool add_region(const std::string_view identifier, std::vector<std::string_view> const& province_identifiers); - void lock_regions(); + IDENTIFIER_REGISTRY_ACCESSORS(Region, region) + IDENTIFIER_REGISTRY_NON_CONST_ACCESSORS(Region, region) - size_t get_province_count() const; - std::vector<Province> const& get_provinces() const; Province* get_province_by_index(Province::index_t index); Province const* get_province_by_index(Province::index_t index) const; - Province* get_province_by_identifier(const std::string_view identifier); - Province const* get_province_by_identifier(const std::string_view identifier) const; Province::index_t get_province_index_at(size_t x, size_t y) const; bool set_max_provinces(Province::index_t new_max_provinces); Province::index_t get_max_provinces() const; @@ -86,11 +85,6 @@ namespace OpenVic { Province::index_t get_selected_province_index() const; Province const* get_selected_province() const; - Region* get_region_by_identifier(const std::string_view identifier); - Region const* get_region_by_identifier(const std::string_view identifier) const; - size_t get_region_count() const; - std::vector<Region> const& get_regions() const; - bool generate_province_shape_image(size_t new_width, size_t new_height, uint8_t const* colour_data, uint8_t const* terrain_data, terrain_variant_map_t const& terrain_variant_map, bool detailed_errors); size_t get_width() const; @@ -113,5 +107,7 @@ namespace OpenVic { void tick(Date const& today); bool load_province_definitions(std::vector<ovdl::csv::LineObject> const& lines); + bool load_province_positions(BuildingManager const& building_manager, ast::NodeCPtr root); + bool load_region_file(ast::NodeCPtr root); }; } diff --git a/src/openvic-simulation/map/Province.cpp b/src/openvic-simulation/map/Province.cpp index f53de3a..db7e784 100644 --- a/src/openvic-simulation/map/Province.cpp +++ b/src/openvic-simulation/map/Province.cpp @@ -1,14 +1,16 @@ #include "Province.hpp" #include <cassert> +#include <cstddef> #include <iomanip> +#include <iterator> #include <sstream> using namespace OpenVic; using namespace OpenVic::NodeTools; Province::Province(const std::string_view new_identifier, colour_t new_colour, index_t new_index) - : HasIdentifierAndColour { new_identifier, new_colour, false }, + : HasIdentifierAndColour { new_identifier, new_colour, false, false }, index { new_index }, buildings { "buildings", false } { assert(index != NULL_INDEX); @@ -22,7 +24,11 @@ Region* Province::get_region() const { return region; } -bool Province::is_water() const { +bool Province::get_has_region() const { + return has_region; +} + +bool Province::get_water() const { return water; } @@ -30,6 +36,12 @@ Province::life_rating_t Province::get_life_rating() const { return life_rating; } +bool Province::load_positions(BuildingManager const& building_manager, ast::NodeCPtr root) { + // TODO - implement province position loading + // (root is the dictionary after the province identifier) + return true; +} + bool Province::add_building(Building&& building) { return buildings.add_item(std::move(building)); } @@ -64,7 +76,7 @@ bool Province::load_pop_list(PopManager const& pop_manager, ast::NodeCPtr root) } bool Province::add_pop(Pop&& pop) { - if (!is_water()) { + if (!get_water()) { pops.push_back(std::move(pop)); return true; } else { @@ -127,3 +139,39 @@ void Province::tick(Date const& today) { for (Building& building : buildings.get_items()) building.tick(today); } + +Province::adjacency_t::adjacency_t(Province const* province, distance_t distance, flags_t flags) + : province { province }, distance { distance }, flags { flags } { + assert(province != nullptr); +} + +Province::distance_t Province::adjacency_t::get_distance() const { + return distance; +} + +Province::flags_t Province::adjacency_t::get_flags() { + return flags; +} + +bool Province::is_adjacent_to(Province const* province) { + for (adjacency_t adj : adjacencies) + if (adj.province == province) + return true; + return false; +} + +bool Province::add_adjacency(Province const* province, distance_t distance, flags_t flags) { + if (province == nullptr) { + Logger::error("Tried to create null adjacency province for province ", get_identifier(), "!"); + return false; + } + + if (is_adjacent_to(province)) + return false; + adjacencies.push_back({ province, distance, flags }); + return true; +} + +std::vector<Province::adjacency_t> const& Province::get_adjacencies() const { + return adjacencies; +}
\ No newline at end of file diff --git a/src/openvic-simulation/map/Province.hpp b/src/openvic-simulation/map/Province.hpp index 67816ff..370d05c 100644 --- a/src/openvic-simulation/map/Province.hpp +++ b/src/openvic-simulation/map/Province.hpp @@ -17,13 +17,30 @@ namespace OpenVic { using index_t = uint16_t; using life_rating_t = int8_t; + using distance_t = uint16_t; + using flags_t = uint16_t; + + struct adjacency_t { + friend struct Province; + + private: + Province const* const province; + const distance_t distance; + flags_t flags; + + adjacency_t(Province const* province, distance_t distance, flags_t flags); + + public: + distance_t get_distance() const; + flags_t get_flags(); + }; static constexpr index_t NULL_INDEX = 0, MAX_INDEX = (1 << (8 * sizeof(index_t))) - 1; private: const index_t index; Region* region = nullptr; - bool water = false; + bool has_region = false, water = false; life_rating_t life_rating = 0; IdentifierRegistry<Building> buildings; // TODO - change this into a factory-like structure @@ -33,6 +50,8 @@ namespace OpenVic { Pop::pop_size_t total_population; distribution_t pop_types, cultures, religions; + std::vector<adjacency_t> adjacencies; + Province(const std::string_view new_identifier, colour_t new_colour, index_t new_index); public: @@ -40,8 +59,11 @@ namespace OpenVic { index_t get_index() const; Region* get_region() const; - bool is_water() const; + bool get_has_region() const; + bool get_water() const; life_rating_t get_life_rating() const; + bool load_positions(BuildingManager const& building_manager, ast::NodeCPtr root); + bool add_building(Building&& building); IDENTIFIER_REGISTRY_ACCESSORS(Building, building) void reset_buildings(); @@ -62,5 +84,9 @@ namespace OpenVic { void update_state(Date const& today); void tick(Date const& today); + + bool is_adjacent_to(Province const* province); + bool add_adjacency(Province const* province, distance_t distance, flags_t flags); + std::vector<adjacency_t> const& get_adjacencies() const; }; } diff --git a/src/openvic-simulation/map/Region.cpp b/src/openvic-simulation/map/Region.cpp index 33092c5..c0422de 100644 --- a/src/openvic-simulation/map/Region.cpp +++ b/src/openvic-simulation/map/Region.cpp @@ -2,6 +2,8 @@ using namespace OpenVic; +ProvinceSet::ProvinceSet(provinces_t&& new_provinces) : provinces { std::move(new_provinces) } {} + bool ProvinceSet::add_province(Province* province) { if (locked) { Logger::error("Cannot add province to province set - locked!"); @@ -57,13 +59,20 @@ bool ProvinceSet::contains_province(Province const* province) const { return province && std::find(provinces.begin(), provinces.end(), province) != provinces.end(); } -std::vector<Province*> const& ProvinceSet::get_provinces() const { +ProvinceSet::provinces_t const& ProvinceSet::get_provinces() const { return provinces; } -Region::Region(const std::string_view new_identifier) : HasIdentifier { new_identifier } {} +Region::Region(const std::string_view new_identifier, provinces_t&& new_provinces, bool new_meta) + : HasIdentifier { new_identifier }, ProvinceSet { std::move(new_provinces) }, meta { new_meta } { + lock(); +} + +bool Region::get_meta() const { + return meta; +} colour_t Region::get_colour() const { - if (provinces.empty()) return FULL_COLOUR << 16; - return provinces.front()->get_colour(); + 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 2fccf06..d68033b 100644 --- a/src/openvic-simulation/map/Region.hpp +++ b/src/openvic-simulation/map/Region.hpp @@ -5,11 +5,15 @@ namespace OpenVic { struct ProvinceSet { - protected: - std::vector<Province*> provinces; + using provinces_t = std::vector<Province*>; + + private: + provinces_t provinces; bool locked = false; public: + ProvinceSet(provinces_t&& new_provinces = {}); + bool add_province(Province* province); void lock(bool log = false); bool is_locked() const; @@ -18,7 +22,7 @@ namespace OpenVic { size_t size() const; void reserve(size_t size); bool contains_province(Province const* province) const; - std::vector<Province*> const& get_provinces() const; + provinces_t const& get_provinces() const; }; /* REQUIREMENTS: @@ -28,11 +32,18 @@ namespace OpenVic { friend struct Map; private: - Region(const std::string_view new_identifier); + /* A meta region cannot be the template for a state. + * Any region containing a province already listed in a + * previously defined region is considered a meta region. + */ + const bool meta; + + Region(const std::string_view new_identifier, provinces_t&& new_provinces, bool new_meta); public: Region(Region&&) = default; + bool get_meta() const; colour_t get_colour() const; }; } |