From e74620ab56f29375174cf0335ff95da3ce1d70aa Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 30 Mar 2026 16:22:40 +0200 Subject: [PATCH] feat: basic grammar functionality done --- modules/generative_grammar/generator.cpp | 21 ++++++++++++---- modules/generative_grammar/grammar.cpp | 30 +++++++++++++---------- modules/generative_grammar/grammar.h | 17 ++++++------- project/project.godot | 2 +- project/scenes/levels/dungeon.tscn | 31 +++++++++++++++--------- 5 files changed, 62 insertions(+), 39 deletions(-) diff --git a/modules/generative_grammar/generator.cpp b/modules/generative_grammar/generator.cpp index 3613b31806..ef84031576 100644 --- a/modules/generative_grammar/generator.cpp +++ b/modules/generative_grammar/generator.cpp @@ -1,5 +1,6 @@ #include "generator.h" #include "core/config/engine.h" +#include "core/math/math_funcs.h" #include "core/object/class_db.h" #include "macros.h" @@ -8,29 +9,39 @@ void Generator::_bind_methods() { } void Generator::initialise_state() { + print_line("Filling state with unknown"); for (int i{ 0 }; i < this->state->symbols.size(); ++i) { - this->state->symbols.set(i, NonTerminals::Undefined); + this->state->symbols.set(i, Terminals::Undefined); } + print_line("Writing borders X"); 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); } + print_line("Writing borders Y"); 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 }; + print_line("Writing path"); + int y{ (Math::abs((int)Math::rand()) % (this->state->size.y - 4)) + 2 }; + print_line("Path at y =", y); for (int i{ 1 }; i < this->state->size.x - 1; ++i) { - this->state->set_at({ i, y }, NonTerminals::Path); + this->state->set_at({ i, y }, Terminals::Path); } - this->state->set_at({ 0, y }, NonTerminals::Start); - this->state->set_at({ this->state->size.x - 1, y }, NonTerminals::Goal); + print_line("Writing start & goal"); + this->state->set_at({ 0, y }, Terminals::Start); + this->state->set_at({ this->state->size.x - 1, y }, Terminals::Goal); } void Generator::ready() { initialise_state(); + print_line("STATE:"); + print_line(this->state->get_symbols_string()); // TODO: repeat until terminal state this->rule->try_apply(this->state); + print_line("STATE:"); + print_line(this->state->get_symbols_string()); } void Generator::_notification(int what) { diff --git a/modules/generative_grammar/grammar.cpp b/modules/generative_grammar/grammar.cpp index eb924cb518..ca967bd96e 100644 --- a/modules/generative_grammar/grammar.cpp +++ b/modules/generative_grammar/grammar.cpp @@ -18,29 +18,33 @@ bool Sentence::is_terminal() const { } Symbol Sentence::get_at(Vector2i coord) const { + ERR_FAIL_COND_V_EDMSG(coord.x >= this->size.x, NonTerminals::Invalid, vformat("Sentence::get_at: invalid coordinate x:%d, size.x:%d", coord.x, this->size.x)); + ERR_FAIL_COND_V_EDMSG(coord.y >= this->size.y, NonTerminals::Invalid, vformat("Sentence::get_at: invalid coordinate y:%d size.y:%d", coord.y, this->size.y)); int idx{ coord.x + (coord.y * this->size.x) }; - ERR_FAIL_COND_V_EDMSG(idx < this->symbols.size(), NonTerminals::Invalid, "Sentence::get_at: invalid coordinate"); + ERR_FAIL_COND_V_EDMSG(idx >= this->symbols.size(), NonTerminals::Invalid, vformat("Sentence::get_at: invalid coordinate x:%d y:%d idx:%d size:%d,%d len:%d", coord.x, coord.y, idx, this->size.x, this->size.y, this->symbols.size())); return this->symbols.get(idx); } void Sentence::set_at(Vector2i coord, Symbol symbol) { + ERR_FAIL_COND_EDMSG(coord.x >= this->size.x, vformat("Sentence::get_at: invalid coordinate x:%d, size.x:%d", coord.x, this->size.x)); + ERR_FAIL_COND_EDMSG(coord.y >= this->size.y, vformat("Sentence::get_at: invalid coordinate y:%d size.y:%d", coord.y, this->size.y)); int idx{ coord.x + (coord.y * this->size.x) }; - ERR_FAIL_COND_EDMSG(idx < this->symbols.size(), "Sentence::set_at: invalid coordinate"); + ERR_FAIL_COND_EDMSG(idx >= this->symbols.size(), vformat("Sentence::set_at: invalid coordinate x:%d y:%d idx:%d size:%d,%d len:%d", coord.x, coord.y, idx, this->size.x, this->size.y, this->symbols.size())); this->symbols.set(idx, symbol); } bool Sentence::check_match_at(Vector2i at, Ref pattern) { Vector2i const pattern_size{ pattern->get_size() }; - if (at.x + pattern_size.x > this->size.x || at.y + pattern_size.y > this->size.y) { + if (at.x + pattern_size.x >= this->size.x || at.y + pattern_size.y >= this->size.y) { return false; // can't match, out of bounds } - for (Vector2i itr{ 0, 0 }; itr.y < pattern_size.x; ++itr.y) { - for (; itr.x + at.x < pattern_size.x; ++itr.x) { + for (Vector2i itr{ 0, 0 }; itr.y < pattern_size.y; ++itr.y) { + for (; itr.x < pattern_size.x; ++itr.x) { if (get_at(at + itr) != pattern->get_at(itr)) { return false; // difference found } } - itr.x = at.x; + itr.x = 0; } return true; } @@ -58,8 +62,8 @@ 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{ reader < value.length() ? value[reader] : (char32_t)'B' }; - if (c != '\n') { + char32_t c{ reader < value.length() ? value[reader] : U'B' }; + if (c != U'\n') { this->symbols.set(writer, c); ++writer; } @@ -70,9 +74,9 @@ String Sentence::get_symbols_string() const { String value{}; for (int i{ 0 }; i < this->symbols.size(); ++i) { if (i != 0 && i % this->size.x == 0) { - value += L'\n'; + value += U'\n'; } - value += this->symbols.get(i); + value += String::chr(this->symbols.get(i)); } return value; } @@ -115,9 +119,6 @@ void ReplaceRule::_bind_methods() { 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 - } 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)) { @@ -134,6 +135,9 @@ void ReplaceRule::set_results_dict(Dictionary dict) { Ref key{ var.key }; if (key.is_valid() && var.value.is_num()) { float value{ var.value }; + if (key->size != this->pattern->size) { + key->set_size(this->pattern->size); + } this->results.push_back({ key, value }); } } diff --git a/modules/generative_grammar/grammar.h b/modules/generative_grammar/grammar.h index c9aa18f031..0f63abafda 100644 --- a/modules/generative_grammar/grammar.h +++ b/modules/generative_grammar/grammar.h @@ -7,20 +7,19 @@ typedef char32_t Symbol; namespace NonTerminals { enum : Symbol { - Start = L'S', - Goal = L'G', - Undefined = L'U', - Path = L'P', - Blocked = L'B', - Invalid = L'!', + Blocked = U'B', + Invalid = U'!', }; }; namespace Terminals { enum : Symbol { - Invalid = L'!', - Wall = L'w', - Path = L'p' + Invalid = U'!', + Start = U's', + Goal = U'g', + Undefined = U'u', + Wall = U'w', + Path = U'p' }; }; diff --git a/project/project.godot b/project/project.godot index 6c88cbb994..18e5f8a8d6 100644 --- a/project/project.godot +++ b/project/project.godot @@ -16,7 +16,7 @@ compatibility/default_parent_skeleton_in_mesh_instance_3d=true [application] config/name="dungeon" -run/main_scene="uid://dnm5d16scmirb" +run/main_scene="uid://cak2tf2adjv8j" config/features=PackedStringArray("4.7", "Forward Plus") config/icon="res://icon.svg" diff --git a/project/scenes/levels/dungeon.tscn b/project/scenes/levels/dungeon.tscn index 07b9915a51..f12438f9ca 100644 --- a/project/scenes/levels/dungeon.tscn +++ b/project/scenes/levels/dungeon.tscn @@ -3,21 +3,27 @@ [sub_resource type="Sentence" id="Sentence_bb2w7"] size = Vector2i(10, 10) symbols_string = "BBBBBBBBBB -BBBBBBBBBB -BBBBBBBBBB -BBBBBBBBBB -BBBBBBBBBB -BBBBBBBBBB -BBBBBBBBBB -BBBBBBBBBB -BBBBBBBBBB +BuuuuuuuuB +BuuuuuuuuB +BuuuuuuuuB +BuuuuuuuuB +BuuuuuuuuB +BuuuuuuuuB +BuuuuuuuuB +BuuuuuuuuB BBBBBBBBBB" [sub_resource type="Sentence" id="Sentence_wail4"] size = Vector2i(3, 3) -symbols_string = "BBB -BBB -BBB" +symbols_string = "uuu +ppp +uuu" + +[sub_resource type="Sentence" id="Sentence_srduu"] +size = Vector2i(3, 3) +symbols_string = "uuu +pxp +uuu" [node name="Dungeon" type="Node3D" unique_id=719313039] @@ -26,3 +32,6 @@ state = SubResource("Sentence_bb2w7") [node name="ReplaceRule" type="ReplaceRule" parent="Generator" unique_id=1787373751] pattern = SubResource("Sentence_wail4") +results_dict = { +SubResource("Sentence_srduu"): 1.0 +}