implement naive db

This commit is contained in:
Green Sky 2022-08-16 01:15:18 +02:00
parent 63a7fc3114
commit 8a9b05e9a1
2 changed files with 81 additions and 3 deletions

View File

@ -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)

View File

@ -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 <algorithm>
#include <string>
#include <map>
#include <set>
#include <vector>
#include <functional>
#include <optional>
#include <limits>
#include <random>
#include <cassert>
@ -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<void(void)> f;
Response(void) = default;
Response(const Rules& r, std::function<void(void)>&& _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<Response> responses;
// returns index
template<typename RNG>
std::optional<size_t> match(const Query& q, RNG& rng) const {
size_t crit_count_for_match = 0;
std::vector<size_t> 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<typename RNG>
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;
}