diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 53d1411..e6794a0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,3 +2,5 @@ cmake_minimum_required(VERSION 3.9 FATAL_ERROR) add_executable(main1 main1.cpp) +target_compile_features(main1 PUBLIC cxx_std_17) + diff --git a/src/main1.cpp b/src/main1.cpp index 9025d16..1c28068 100644 --- a/src/main1.cpp +++ b/src/main1.cpp @@ -1,11 +1,15 @@ // this is a naive-ish implementation // this is not pure naive, since it implements the less-branch Criterion compare variant discussed in the valve talk +#include #include #include #include +#include #include +#include #include +#include #include @@ -50,6 +54,7 @@ struct Query { } bool match_criterion(const Criterion& crit) const { + // TODO: lookup is performed 2x, optimize return dict.count(crit.key) && crit.compare(dict.at(crit.key)); } @@ -68,7 +73,15 @@ struct Query { struct Response { Rules rules; + // normally you would give it the caller(entity f is called on?) std::function f; + + Response(void) = default; + Response(const Rules& r, std::function&& _f) : rules(r), f(_f) {} + + size_t criterion_size(void) const { + return rules.crits.size(); + } }; // special keys (usually bucketalbe): @@ -76,6 +89,53 @@ struct Response { // - "who": which char talked. gonna name this differently struct ResponseDB { + std::vector responses; + + // returns index + template + std::optional match(const Query& q, RNG& rng) const { + size_t crit_count_for_match = 0; + + std::vector match_list; + + //for (const auto& r : responses) { + for (size_t i = 0; i < responses.size(); i++) { + const auto& r = responses[i]; + + // skip rules with less criteria matching + if (r.criterion_size() < crit_count_for_match) { + continue; + } + + if (q.match_rules(r.rules)) { + if (crit_count_for_match < r.criterion_size()) { + match_list.clear(); + crit_count_for_match = r.criterion_size(); + } + + match_list.push_back(i); + } + } + + if (match_list.empty()) { + return std::nullopt; + } + + std::shuffle(match_list.begin(), match_list.end(), rng); + + return match_list.front(); + } + + template + bool match_and_run(const Query& q, RNG& rng) const { + auto idx = match(q, rng); + if (idx.has_value()) { + responses.at(*idx).f(); + return true; + } + + return false; + } }; int main(void) { @@ -148,9 +208,11 @@ int main(void) { .add("in_danger", 1.f) ; - // add junk to q2 - for (int i = 0; i < 10000; i++) { - q2.add(std::to_string(i) + "asdf", (i - 155) * 12399.3249f); + // add junk to q1 + // 100'000 -> >200ms + // 10'000 -> >ms + for (int i = 0; i < 10'000; i++) { + q1.add(std::to_string(i) + "asdf", (i - 155) * 12399.3249f); } assert(q1.match_criterion(hp_not_critical) == true); @@ -162,6 +224,20 @@ int main(void) { assert(q1.match_rules(rules_hero_idle_chatter) == true); assert(q2.match_rules(rules_hero_idle_chatter) == false); + // response DB + + std::mt19937 rng{1337*433}; + + ResponseDB db; + size_t fn_called = 0; + db.responses.emplace_back(rules_hero_idle_chatter, [&fn_called](){ fn_called++; }); + + assert(fn_called == 0); + assert(db.match_and_run(q1, rng) == true); + assert(fn_called == 1); + assert(db.match_and_run(q2, rng) == false); + assert(fn_called == 1); + return 0; }