behaviour-tree-test/modules/generative_grammar/symbol.cpp

88 lines
2.5 KiB
C++

#include "generative_grammar/symbol.h"
#include "core/error/error_macros.h"
#include "core/object/class_db.h"
#include "core/templates/hash_map.h"
void Symbol::_bind_methods() {
BIND_HPROPERTY(Variant::INT, symbol, PROPERTY_HINT_ENUM, Type_hint());
BIND_HPROPERTY(Variant::ARRAY, children_array, PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Symbol"));
}
bool Symbol::is_terminal() const {
switch (this->symbol) {
default:
return false;
}
}
void Symbol::set_children_array(TypedArray<Ref<Symbol>> array) {
for (Ref<Symbol> symbol : this->children) {
if (symbol.is_valid()) {
symbol->set_parent(nullptr);
}
}
this->children.clear();
for (Variant var : array) {
Ref<Symbol> child{ var };
this->children.insert(var);
if (child.is_valid()) {
child->set_parent(this);
}
}
}
TypedArray<Ref<Symbol>> Symbol::get_children_array() const {
TypedArray<Ref<Symbol>> array{};
for (Ref<Symbol> symbol : this->children) {
array.push_back(symbol);
}
return array;
}
void Rule::_bind_methods() {
BIND_HPROPERTY(Variant::OBJECT, pattern, PROPERTY_HINT_RESOURCE_TYPE, "Symbol");
BIND_HPROPERTY(Variant::OBJECT, result, PROPERTY_HINT_RESOURCE_TYPE, "Symbol");
}
bool Rule::match_symbols(Ref<Symbol> match, Ref<Symbol> pattern, HashMap<Ref<Symbol>, Ref<Symbol>> &matches) {
if (match == pattern) {
return true; // reference match or null match
}
ERR_FAIL_COND_V_EDMSG(match.is_valid() == false, false, "Attempt to match null symbol, is not possible");
if (pattern.is_null()) {
return false; // null matches nothing
}
if (match->get_symbol() != pattern->get_symbol()) {
return false; // symbol type mismatch
}
if (match->get_children().size() < pattern->get_children().size()) {
return false; // too little children to be able to match
}
// check for matching outgoing edges
for (Ref<Symbol> pattern_symbol : pattern->get_children()) {
bool match_found{ false };
for (Ref<Symbol> match_symbol : match->get_children()) {
if (match_symbols(match_symbol, pattern_symbol, matches)) {
match_found = true;
break;
}
}
if (!match_found) {
return false;
}
}
matches.insert(pattern, match);
return true;
}
bool Rule::try_apply(Ref<Symbol> match) {
// identify corresponding symbols
HashMap<Ref<Symbol>, Ref<Symbol>> symbols{};
if (!match_symbols(match, this->pattern, symbols)) {
return false;
}
// clear matching edges
for (KeyValue<Ref<Symbol>, Ref<Symbol>> kvp : symbols) {
}
return true;
}