aboutsummaryrefslogtreecommitdiff
path: root/src/openvic-simulation/politics/Rule.cpp
diff options
context:
space:
mode:
author Hop311 <Hop3114@gmail.com>2024-01-03 10:39:50 +0100
committer GitHub <noreply@github.com>2024-01-03 10:39:50 +0100
commita649ccb74bd6ab0b62d26e870dfd509cc8f92b1d (patch)
tree5e73f0930d45d789e899601cfcecce094bbba42b /src/openvic-simulation/politics/Rule.cpp
parent143a422bc1c27e6d1ebf7e3ead32fff32877797e (diff)
parente067471f55cd11c6cd86920f9486991d6b552726 (diff)
Merge pull request #116 from OpenVicProject/rule-rework
Mutually exclusive rule groups + modded building rules
Diffstat (limited to 'src/openvic-simulation/politics/Rule.cpp')
-rw-r--r--src/openvic-simulation/politics/Rule.cpp201
1 files changed, 143 insertions, 58 deletions
diff --git a/src/openvic-simulation/politics/Rule.cpp b/src/openvic-simulation/politics/Rule.cpp
index 12db4f4..9ac992a 100644
--- a/src/openvic-simulation/politics/Rule.cpp
+++ b/src/openvic-simulation/politics/Rule.cpp
@@ -1,19 +1,90 @@
#include "Rule.hpp"
+#include "openvic-simulation/economy/BuildingType.hpp"
+#include "openvic-simulation/utility/TslHelper.hpp"
+
using namespace OpenVic;
using namespace OpenVic::NodeTools;
-Rule::Rule(std::string_view new_identifier) : HasIdentifier { new_identifier } {}
+Rule::Rule(std::string_view new_identifier, rule_group_t new_group, size_t new_index)
+ : HasIdentifier { new_identifier }, group { new_group }, index { new_index } {}
-RuleSet::RuleSet(rule_map_t&& new_rules) : rules { std::move(new_rules) } {}
+RuleSet::RuleSet(rule_group_map_t&& new_rule_groups) : rule_groups { std::move(new_rule_groups) } {}
+
+bool RuleSet::trim_and_resolve_conflicts(bool log) {
+ bool ret = true;
+ for (auto [group, rule_map] : mutable_iterator(rule_groups)) {
+ if (Rule::is_mutually_exclusive_group(group)) {
+ Rule const* primary_rule = nullptr;
+ for (auto const& [rule, value] : rule_map) {
+ if (value) {
+ if (primary_rule == nullptr) {
+ primary_rule = rule;
+ } else {
+ if (primary_rule->get_index() < rule->get_index()) {
+ primary_rule = rule;
+ }
+ ret = false;
+ }
+ }
+ }
+ if (log) {
+ for (auto const& [rule, value] : rule_map) {
+ if (value) {
+ if (rule != primary_rule) {
+ Logger::error(
+ "Conflicting mutually exclusive rule: ", rule, " superceeded by ", primary_rule, " - removing!"
+ );
+ }
+ } else {
+ Logger::warning("Disabled mutually exclusive rule: ", rule, " - removing!");
+ }
+ }
+ }
+ rule_map.clear();
+ if (primary_rule != nullptr) {
+ rule_map.emplace(primary_rule, true);
+ }
+ }
+ }
+ return ret;
+}
+
+size_t RuleSet::get_rule_group_count() const {
+ return rule_groups.size();
+}
size_t RuleSet::get_rule_count() const {
- return rules.size();
+ size_t ret = 0;
+ for (auto const& [group, rule_map] : rule_groups) {
+ ret += rule_map.size();
+ }
+ return ret;
+}
+
+RuleSet::rule_map_t const& RuleSet::get_rule_group(Rule::rule_group_t group, bool* successful) const {
+ const rule_group_map_t::const_iterator it = rule_groups.find(group);
+ if (it != rule_groups.end()) {
+ if (successful != nullptr) {
+ *successful = true;
+ }
+ return it->second;
+ }
+ if (successful != nullptr) {
+ *successful = false;
+ }
+ static const rule_map_t empty_map {};
+ return empty_map;
}
-bool RuleSet::get_rule(Rule const* rule, bool* successful) {
- const rule_map_t::const_iterator it = rules.find(rule);
- if (it != rules.end()) {
+bool RuleSet::get_rule(Rule const* rule, bool* successful) const {
+ if (rule == nullptr) {
+ Logger::error("Invalid rule - null!");
+ return false;
+ }
+ rule_map_t const& rule_map = get_rule_group(rule->get_group());
+ const rule_map_t::const_iterator it = rule_map.find(rule);
+ if (it != rule_map.end()) {
if (successful != nullptr) {
*successful = true;
}
@@ -22,16 +93,31 @@ bool RuleSet::get_rule(Rule const* rule, bool* successful) {
if (successful != nullptr) {
*successful = false;
}
- return false;
+ return Rule::is_default_enabled(rule->get_group());
}
bool RuleSet::has_rule(Rule const* rule) const {
- return rules.contains(rule);
+ if (rule == nullptr) {
+ Logger::error("Invalid rule - null!");
+ return false;
+ }
+ return get_rule_group(rule->get_group()).contains(rule);
+}
+
+bool RuleSet::set_rule(Rule const* rule, bool value) {
+ if (rule == nullptr) {
+ Logger::error("Invalid rule - null!");
+ return false;
+ }
+ rule_map_t& rule_map = rule_groups[rule->get_group()];
+ return rule_groups[rule->get_group()].emplace(rule, value).second;
}
RuleSet& RuleSet::operator|=(RuleSet const& right) {
- for (rule_map_t::value_type const& value : right.rules) {
- rules[value.first] |= value.second;
+ for (auto const& [group, rule_map] : right.rule_groups) {
+ for (auto const& [rule, value] : rule_map) {
+ rule_groups[group][rule] |= value;
+ }
}
return *this;
}
@@ -41,61 +127,57 @@ RuleSet RuleSet::operator|(RuleSet const& right) const {
return ret |= right;
}
-bool RuleManager::add_rule(std::string_view identifier) {
+bool RuleManager::add_rule(std::string_view identifier, Rule::rule_group_t group) {
if (identifier.empty()) {
Logger::error("Invalid rule identifier - empty!");
return false;
}
- return rules.add_item({ identifier });
+ return rules.add_item({ identifier, group, rule_group_sizes[group]++ });
}
-bool RuleManager::setup_rules() {
+bool RuleManager::setup_rules(BuildingTypeManager const& building_type_manager) {
bool ret = true;
- /* Economic Rules */
- ret &= add_rule("build_factory");
- ret &= add_rule("expand_factory");
- ret &= add_rule("open_factory");
- ret &= add_rule("destroy_factory");
-
- ret &= add_rule("pop_build_factory");
- ret &= add_rule("pop_expand_factory");
- ret &= add_rule("pop_open_factory");
-
- ret &= add_rule("build_railway");
- ret &= add_rule("can_subsidise");
- ret &= add_rule("factory_priority");
- ret &= add_rule("delete_factory_if_no_input");
-
- ret &= add_rule("build_factory_invest");
- ret &= add_rule("expand_factory_invest");
- ret &= add_rule("open_factory_invest");
- ret &= add_rule("build_railway_invest");
-
- ret &= add_rule("pop_build_factory_invest");
- ret &= add_rule("pop_expand_factory_invest");
-
- ret &= add_rule("can_invest_in_pop_projects");
- ret &= add_rule("allow_foreign_investment");
-
- /* Citizenship Rules */
- ret &= add_rule("primary_culture_voting");
- ret &= add_rule("culture_voting");
- ret &= add_rule("all_voting");
+ using enum Rule::rule_group_t;
+
+ static const ordered_map<Rule::rule_group_t, std::vector<std::string_view>> hardcoded_rules {
+ { ECONOMY, {
+ "expand_factory", "open_factory", "destroy_factory", "pop_build_factory", "pop_expand_factory", "pop_open_factory",
+ "can_subsidise", "factory_priority", "delete_factory_if_no_input", "build_factory_invest", "expand_factory_invest",
+ "open_factory_invest", "build_railway_invest", "pop_build_factory_invest", "pop_expand_factory_invest",
+ "can_invest_in_pop_projects", "allow_foreign_investment"
+ } },
+ { CITIZENSHIP, { "primary_culture_voting", "culture_voting", "all_voting" } },
+ { SLAVERY, { "slavery_allowed" } },
+ { UPPER_HOUSE, { "same_as_ruling_party", "rich_only", "state_vote", "population_vote" } },
+ { VOTING, {
+ "largest_share" /* First Past the Post */,
+ "dhont" /* Jefferson Method */,
+ "sainte_laque" /* Proportional Representation */
+ } }
+ };
- /* Slavery Rule */
- ret &= add_rule("slavery_allowed");
+ size_t rule_count = building_type_manager.get_building_type_types().size();
+ for (auto const& [group, rule_list] : hardcoded_rules) {
+ rule_count += rule_list.size();
+ }
+ rules.reserve(rule_count);
- /* Upper House Composition Rules */
- ret &= add_rule("same_as_ruling_party");
- ret &= add_rule("rich_only");
- ret &= add_rule("state_vote");
- ret &= add_rule("population_vote");
+ for (auto const& [group, rule_list] : hardcoded_rules) {
+ for (std::string_view const& rule : rule_list) {
+ ret &= add_rule(rule, group);
+ }
+ }
- /* Voting System Rules */
- ret &= add_rule("largest_share"); // First Past the Post
- ret &= add_rule("dhont"); // Jefferson Method
- ret &= add_rule("sainte_laque"); // Proportional Representation
+ for (std::string const& type : building_type_manager.get_building_type_types()) {
+ std::string build_rule_string = "build_";
+ if (type != "infrastructure") {
+ build_rule_string += type;
+ } else {
+ build_rule_string += "railway";
+ }
+ ret &= add_rule(build_rule_string, ECONOMY);
+ }
lock_rules();
@@ -111,8 +193,8 @@ node_callback_t RuleManager::expect_rule_set(callback_t<RuleSet&&> ruleset_callb
if (rule != nullptr) {
return expect_bool(
[&ruleset, rule](bool value) -> bool {
- if (!ruleset.rules.emplace(rule, value).second) {
- Logger::warning("Duplicate rule entry: ", rule, " - overwriting existing value!");
+ if (!ruleset.rule_groups[rule->get_group()].emplace(rule, value).second) {
+ Logger::warning("Duplicate rule entry: ", rule, " - ignoring!");
}
return true;
}
@@ -123,6 +205,7 @@ node_callback_t RuleManager::expect_rule_set(callback_t<RuleSet&&> ruleset_callb
}
}
)(root);
+ ret &= ruleset.trim_and_resolve_conflicts(true);
ret &= ruleset_callback(std::move(ruleset));
return ret;
};
@@ -130,8 +213,10 @@ node_callback_t RuleManager::expect_rule_set(callback_t<RuleSet&&> ruleset_callb
namespace OpenVic { // so the compiler shuts up (copied from Modifier.cpp)
std::ostream& operator<<(std::ostream& stream, RuleSet const& value) {
- for (RuleSet::rule_map_t::value_type const& rule : value.rules) {
- stream << rule.first << ": " << (rule.second ? "yes" : "no") << "\n";
+ for (auto const& [group, rule_map] : value.rule_groups) {
+ for (auto const& [rule, value] : rule_map) {
+ stream << rule << ": " << (value ? "yes" : "no") << "\n";
+ }
}
return stream;
}