feat: basic grammar functionality done

This commit is contained in:
Sara Gerretsen 2026-03-30 16:22:40 +02:00
parent 31c1c4cfbe
commit e74620ab56
5 changed files with 62 additions and 39 deletions

View file

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

View file

@ -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<Sentence> 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> 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<Sentence> 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 });
}
}

View file

@ -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'
};
};

View file

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

View file

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