feat(ir): compile solution blocks to puzzles

This commit is contained in:
Claude Worker claude2
2026-06-11 03:14:20 +02:00
parent dd6df1fa69
commit b1486b27ff
3 changed files with 207 additions and 14 deletions
+26 -14
View File
@@ -150,18 +150,30 @@ et pilote l'écran. Un IR de référence exerçant ces champs est fourni :
par `validate_runtime3_document`, testé en bout-à-bout via `POST /game/scenario`
puis `POST /game/step`).
**En revanche, l'authoring ne les génère pas encore.** Les scénarios
canoniques (`game/scenarios/zacus_v2.yaml`, `zacus_v3.yaml`) décrivent les
mêmes énigmes via un vocabulaire distinct — blocs `solution:`
(`frequency_hz`, `qr_payload`, `sequence`) et `scene: SCENE_X` (référence
d'ID d'écran, pas l'objet d'affichage) — qui **n'est pas traduit** vers les
objets `puzzle`/`scene` de l'IR. L'IR embarqué `DEFAULT.json` ne contient
donc aucun champ `puzzle`/`scene`.
**Le pont authoring → firmware est désormais construit.** Le compilateur
traduit le vocabulaire d'authoring des `puzzles:` (blocs `solution:`) vers les
objets `puzzle` de l'IR et les **attache au step correspondant** (par
`screen_scene_id` == `puzzle.scene`). Fonctions : `translate_solution_to_puzzle`
et `_attach_puzzles_from_authoring` dans `runtime3_common.py`.
Chaînon à construire (tâche dédiée) : enseigner au compilateur la
correspondance `solution:``puzzle:` (ex. `frequency_hz`+`tolerance_hz`
`type:sound`/`melody`/`tolerance` ; `qr_payload`/`sequence`
`type:qr`/`codes` ; allocation des `fragment` de code par énigme), et
exposer un objet `scene` d'affichage dans l'authoring. En attendant,
pousser directement un IR comme `EXAMPLE_LOCAL_PUZZLES.json` reste le moyen
d'exercer les énigmes locales depuis la webUI/gateway.
Table de correspondance `solution:``puzzle:` :
| Authoring (`type` + `solution`) | IR `puzzle` |
|---|---|
| `qr` + `qr_payload: "X"` | `type:qr`, `codes:["X"]` |
| `qr` + `qr_sequence: [a,b]` | `type:qr`, `codes:[a,b]` (ordre conservé) |
| `audio_frequency` + `frequency_hz` (+ `tolerance_hz`) | `type:sound`, `melody:[hz→MIDI]`, `tolerance` (≈ semitons, ≥1) |
| `sound`/`sequence` + `solution.notes: [MIDI…]` | `type:sound`, `melody:[…]` |
Règles : le slot firmware `id` vient de `puzzle_id` sinon d'un défaut par type
(sound→1, sequence→2, qr→3) ; le `fragment` (14 chiffres) vient de
`code_fragment` sinon vaut le chiffre de l'`id`. Une énigme non traduisible
(ex. `sequence` de lettres sans `notes` MIDI — une suite de lettres n'est pas
une séquence de hauteurs détectable) est **ignorée avec un avertissement**, sans
casser la compilation du scénario. Un step portant déjà un `puzzle` explicite
n'est pas écrasé (le passthrough direct prime).
Reste à faire (suite) : exposer un éditeur d'objet `scene` d'affichage
(title/subtitle/symbol/effect) dans l'atelier Blockly — au niveau IR/step,
l'objet `scene` est déjà accepté via le passthrough. `EXAMPLE_LOCAL_PUZZLES.json`
reste l'IR de référence le plus complet (puzzle + scene par step).