refactor: better sentence generator

This commit is contained in:
2026-11-05 22:28:07 +01:00
parent d2d2095081
commit e6e59665e6
7 changed files with 102 additions and 28 deletions
+2
View File
@@ -5,4 +5,6 @@ build
debug.png
error.glsl
forge_default_save.*
project/inc_sentences.glsl
sentences.txt
tmp*
+7 -4
View File
@@ -43,7 +43,7 @@ print-%:
# ACTIONS
.PHONY: init
init: uv-sync git-submodule-init git-submodule-update ## install project
init: uv-sync git-submodule-init git-submodule-update sentences ## install project
.PHONY: update
update: uv-upgrade ## update project dependencies
@@ -55,10 +55,13 @@ format: ruff-fix ruff-format ## format project
lint: ruff ruff-format-check ty ## lint project
.PHONY: gen-img
gen-img: uv-run-invar-mode-gen-img
gen-img: uv-run-invar-mode-gen-img ## generate resources/*.png
.PHONY: debug-img
debug-img: uv-run-invar-mode-debug-img
debug-img: uv-run-invar-mode-debug-img ## debug i2c screen with mock data
.PHONY: sentences
sentences: uv-run-invar-mode-sentences ## generate project/inc_sentences.glsl
.PHONY: rasp-init
rasp-init: rasp-chmod-opt rasp-rsync rasp-unmount ## init raspberry
@@ -68,7 +71,7 @@ rasp-install: rasp-install-pal ## setup raspberry
.PHONY: rasp-install-%
rasp-install-%: ## setup raspberry (PAL/NTSC/HDMI)
$(MAKE) git-submodule-update rasp-rsync rasp-setup-config-$* rasp-setup-cmdline-$* rasp-setup-start-$* rasp-unmount
$(MAKE) git-submodule-update sentences rasp-rsync rasp-setup-config-$* rasp-setup-cmdline-$* rasp-setup-start-$* rasp-unmount
.PHONY: rasp-reset
rasp-reset: rasp-rsync rasp-setup-config-hdmi rasp-reset-cmdline rasp-reset-start rasp-unmount ## reset raspberry to console mode
-21
View File
@@ -1,21 +0,0 @@
#ifndef INC_SENTENCES
#define INC_SENTENCES
#define SENTENCE_COUNT 8
#define SENTENCE_MAX_LENGTH 20
const int sentences[] = int[SENTENCE_COUNT * SENTENCE_MAX_LENGTH](
0x46, 0x6F, 0x6C, 0x6C, 0x65, 0x20, 0x4E, 0x75, 0x69, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x75, 0x20, 0x51, 0x75, 0x61, 0x72, 0x61, 0x6E, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4C, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x46, 0x6F, 0x6C, 0x6C, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x4E, 0x75, 0x69, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x44, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x51, 0x75, 0x61, 0x72, 0x61, 0x6E, 0x74, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x35, 0x33, 0xF8, 0x20, 0x4D, 0x69, 0x65, 0x74, 0x74, 0x65, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
);
const int lengths[] = int[SENTENCE_COUNT](
10, 11, 2, 5, 4, 2, 8, 11
);
#endif
+17
View File
@@ -0,0 +1,17 @@
forge
FORGE
F.O.R.G.E.
Fusion
Of
Real-time
Generative
Effects
Everything you see
Pixel by pixel
Live
Generated
Controlled
π
Kleπek
Code as art
Art as code
+4 -2
View File
@@ -5,7 +5,7 @@ import time
from .display import get_display
from .forge_data import ForgeData
from .i2c import I2C
from .tools import debug_img, gen_img
from .tools import debug_img, gen_img, sentences
def main_loop() -> None:
@@ -26,7 +26,7 @@ def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument(
"--mode", default="default", choices=["default", "gen-img", "debug-img"]
"--mode", default="default", choices=["default", "gen-img", "debug-img", "sentences"]
)
args = parser.parse_args()
@@ -34,5 +34,7 @@ def main() -> None:
gen_img()
elif args.mode == "debug-img":
debug_img()
elif args.mode == "sentences":
sentences()
else:
main_loop()
+2 -1
View File
@@ -1,4 +1,5 @@
from .debug_img import main as debug_img
from .gen_img import main as gen_img
from .sentences import main as sentences
__all__ = ["debug_img", "gen_img"]
__all__ = ["debug_img", "gen_img", "sentences"]
+70
View File
@@ -0,0 +1,70 @@
import logging
import re
from ..constants import PROJECT_PATH
TARGET_FILE = PROJECT_PATH / "project" / "inc_sentences.glsl"
CP437_FILE = PROJECT_PATH / "project" / "inc_cp437.glsl"
SENTENCES_FILE = PROJECT_PATH / "sentences.txt"
BACKUP_SENTENCES_FILE = PROJECT_PATH / "sentences.example.txt"
log = logging.getLogger(__name__)
def read_mapping() -> dict[str, str]:
mapping = {' ': '0x20'}
with CP437_FILE.open() as cp437:
for line in cp437:
if (match := re.match(r'.*// (0x\w\w), (.)$', line)):
mapping[match.group(2)] = match.group(1)
return mapping
def read_sentences() -> list[str]:
if SENTENCES_FILE.exists():
return SENTENCES_FILE.read_text().splitlines()
log.warning("sentences.txt not found, using backup")
return BACKUP_SENTENCES_FILE.read_text().splitlines()
def convert(sentence: str, mapping: dict[str, str], max_len: int) -> str:
out = []
for i in range(max_len):
if i >= len(sentence):
out += ["0x00"]
elif sentence[i] not in mapping:
log.warning(f"Char '{sentence[i]}' not in CP437")
out += ["0x20"]
else:
out += [mapping[sentence[i]]]
return ", ".join(out)
def main():
mapping = read_mapping()
sentences = read_sentences()
max_len = max(len(sentence) for sentence in sentences)
with TARGET_FILE.open("w") as file:
file.write("#ifndef INC_SENTENCES\n")
file.write("#define INC_SENTENCES\n\n")
file.write(f"#define SENTENCE_COUNT {len(sentences)}\n")
file.write(f"#define SENTENCE_MAX_LENGTH {max_len}\n\n")
file.write(
"const int sentences[] = int[SENTENCE_COUNT * SENTENCE_MAX_LENGTH](\n"
)
file.writelines(
" " + convert(sentence, mapping, max_len) + ("," if i < len(sentences) - 1 else " ") + f" // {sentence}\n"
for i, sentence in enumerate(sentences)
)
file.write(");\n\n")
file.write("const int lengths[] = int[SENTENCE_COUNT](\n")
file.write(
" " + ", ".join(str(len(sentence)) for sentence in sentences) + "\n"
)
file.write(");\n")
file.write("#endif")
if __name__ == "__main__":
main()