From 31c1c4cfbe27d74db29443ddb36d51b11d8ca135 Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 30 Mar 2026 00:52:51 +0200 Subject: [PATCH] feat: continuing grammar --- modules/generative_grammar/generator.cpp | 23 ++++++++++++++++++ modules/generative_grammar/generator.h | 1 + modules/generative_grammar/grammar.cpp | 31 ++++++++++++++++++------ modules/generative_grammar/grammar.h | 20 ++++++++++----- project/scenes/levels/dungeon.tscn | 24 +++++++++++++----- 5 files changed, 80 insertions(+), 19 deletions(-) diff --git a/modules/generative_grammar/generator.cpp b/modules/generative_grammar/generator.cpp index f1a81b38ef..3613b31806 100644 --- a/modules/generative_grammar/generator.cpp +++ b/modules/generative_grammar/generator.cpp @@ -7,7 +7,30 @@ void Generator::_bind_methods() { BIND_HPROPERTY(Variant::OBJECT, state, PROPERTY_HINT_RESOURCE_TYPE, "Sentence"); } +void Generator::initialise_state() { + for (int i{ 0 }; i < this->state->symbols.size(); ++i) { + this->state->symbols.set(i, NonTerminals::Undefined); + } + for (int i{ 0 }; i < this->state->size.x; ++i) { + this->state->set_at({ i, 0 }, NonTerminals::Blocked); + this->state->set_at({ i, this->state->size.y - 1 }, NonTerminals::Blocked); + } + for (int i{ 0 }; i < this->state->size.y; ++i) { + this->state->set_at({ 0, i }, NonTerminals::Blocked); + this->state->set_at({ this->state->size.x - 1, i }, NonTerminals::Blocked); + } + int y{ (int)Math::rand() % this->state->size.y - 4 }; + for (int i{ 1 }; i < this->state->size.x - 1; ++i) { + this->state->set_at({ i, y }, NonTerminals::Path); + } + this->state->set_at({ 0, y }, NonTerminals::Start); + this->state->set_at({ this->state->size.x - 1, y }, NonTerminals::Goal); +} + void Generator::ready() { + initialise_state(); + // TODO: repeat until terminal state + this->rule->try_apply(this->state); } void Generator::_notification(int what) { diff --git a/modules/generative_grammar/generator.h b/modules/generative_grammar/generator.h index 513fc469e1..ad330ceaf7 100644 --- a/modules/generative_grammar/generator.h +++ b/modules/generative_grammar/generator.h @@ -6,6 +6,7 @@ class Generator : public Node3D { GDCLASS(Generator, Node3D); static void _bind_methods(); + void initialise_state(); void ready(); protected: diff --git a/modules/generative_grammar/grammar.cpp b/modules/generative_grammar/grammar.cpp index 9b7fbcedb0..eb924cb518 100644 --- a/modules/generative_grammar/grammar.cpp +++ b/modules/generative_grammar/grammar.cpp @@ -4,8 +4,8 @@ #include "macros.h" void Sentence::_bind_methods() { - BIND_HPROPERTY(Variant::STRING, symbols_string, PROPERTY_HINT_MULTILINE_TEXT); BIND_PROPERTY(Variant::VECTOR2I, size); + BIND_HPROPERTY(Variant::STRING, symbols_string, PROPERTY_HINT_MULTILINE_TEXT); } bool Sentence::is_terminal() const { @@ -58,7 +58,7 @@ void Sentence::set_symbols_string(String value) { int size{ this->size.x * this->size.y }; int writer{ 0 }; for (int reader{ 0 }; writer < size; ++reader) { - char32_t c{ value.length() >= reader ? value[reader] : (char32_t)'B' }; + char32_t c{ reader < value.length() ? value[reader] : (char32_t)'B' }; if (c != '\n') { this->symbols.set(writer, c); ++writer; @@ -81,9 +81,6 @@ void Sentence::set_size(Vector2i value) { this->size = value; this->symbols.clear(); this->symbols.resize_initialized(this->size.x * this->size.y); - for (int i{ 0 }; i < this->symbols.size(); ++i) { - this->symbols.set(i, 'B'); - } } Vector2i Sentence::get_size() const { @@ -112,10 +109,11 @@ void CompositeRule::try_apply(Ref sentence) { void ReplaceRule::_bind_methods() { BIND_HPROPERTY(Variant::OBJECT, pattern, PROPERTY_HINT_RESOURCE_TYPE, Sentence::get_class_static()); - BIND_HPROPERTY(Variant::OBJECT, result, PROPERTY_HINT_RESOURCE_TYPE, Sentence::get_class_static()); + BIND_HPROPERTY(Variant::DICTIONARY, results_dict, PROPERTY_HINT_DICTIONARY_TYPE, vformat("%s/%s:%s;float", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, Sentence::get_class_static())); } void ReplaceRule::try_apply(Ref sentence) { + ERR_FAIL_COND_EDMSG(this->results.size() == 0, "ReplaceRule::try_apply failed, no results in list"); Vector2i max{ sentence->get_size() - this->pattern->get_size() }; if (max.x < 0 || max.y < 0) { return; // cannot continue, no area in sentence big enough @@ -123,13 +121,32 @@ void ReplaceRule::try_apply(Ref sentence) { for (Vector2i pos{ 0, 0 }; pos.y < max.y; ++pos.y) { for (; pos.x < max.x; ++pos.x) { if (sentence->check_match_at(pos, this->pattern)) { - sentence->write_subsentence(pos, this->result); + sentence->write_subsentence(pos, this->results[Math::rand() % this->results.size()].first); // TODO pick based on weighed random } } pos.x = 0; } } +void ReplaceRule::set_results_dict(Dictionary dict) { + this->results.clear(); + for (KeyValue var : dict) { + Ref key{ var.key }; + if (key.is_valid() && var.value.is_num()) { + float value{ var.value }; + this->results.push_back({ key, value }); + } + } +} + +Dictionary ReplaceRule::get_results_dict() const { + Dictionary dict; + for (KeyValue, float> kvp : this->results) { + dict[kvp.key] = kvp.value; + } + return dict; +} + void ResizeRule::_bind_methods() { BIND_PROPERTY(Variant::INT, factor); } diff --git a/modules/generative_grammar/grammar.h b/modules/generative_grammar/grammar.h index b9508f44c0..c9aa18f031 100644 --- a/modules/generative_grammar/grammar.h +++ b/modules/generative_grammar/grammar.h @@ -7,15 +7,20 @@ typedef char32_t Symbol; namespace NonTerminals { enum : Symbol { - Start = 'S', - Blocked = 'B', - Invalid = '!', + Start = L'S', + Goal = L'G', + Undefined = L'U', + Path = L'P', + Blocked = L'B', + Invalid = L'!', }; }; namespace Terminals { enum : Symbol { - Invalid = '!', + Invalid = L'!', + Wall = L'w', + Path = L'p' }; }; @@ -76,11 +81,14 @@ public: private: Ref pattern{}; - Ref result{}; + Vector, float>> results{}; public: GET_SET_FNS(Ref, pattern); - GET_SET_FNS(Ref, result); + void set_results(Vector, float>> value) { this->results = value; } + Vector, float>> get_results() { return this->results; } + void set_results_dict(Dictionary value); + Dictionary get_results_dict() const; }; class ResizeRule : public CompositeRule { diff --git a/project/scenes/levels/dungeon.tscn b/project/scenes/levels/dungeon.tscn index ec3dcbd7dc..07b9915a51 100644 --- a/project/scenes/levels/dungeon.tscn +++ b/project/scenes/levels/dungeon.tscn @@ -1,12 +1,23 @@ [gd_scene format=3 uid="uid://cak2tf2adjv8j"] [sub_resource type="Sentence" id="Sentence_bb2w7"] -symbols_string = "BBBBB -BBBBB -BBBBB -BBBBB -BBBBB" -size = Vector2i(5, 5) +size = Vector2i(10, 10) +symbols_string = "BBBBBBBBBB +BBBBBBBBBB +BBBBBBBBBB +BBBBBBBBBB +BBBBBBBBBB +BBBBBBBBBB +BBBBBBBBBB +BBBBBBBBBB +BBBBBBBBBB +BBBBBBBBBB" + +[sub_resource type="Sentence" id="Sentence_wail4"] +size = Vector2i(3, 3) +symbols_string = "BBB +BBB +BBB" [node name="Dungeon" type="Node3D" unique_id=719313039] @@ -14,3 +25,4 @@ size = Vector2i(5, 5) state = SubResource("Sentence_bb2w7") [node name="ReplaceRule" type="ReplaceRule" parent="Generator" unique_id=1787373751] +pattern = SubResource("Sentence_wail4")