Couche protocole¶
La couche protocol/ est la frontière de (dé)sérialisation entre les
chaînes brutes du réseau et l'état typé du client. Elle ne fait aucune E/S : le
réseau lui passe des lignes, elle rend des objets, et inversement.
| Module | Fichier | Rôle |
|---|---|---|
parser |
ai/src/protocol/parser.py |
Ligne serveur brute → message typé |
commands |
ai/src/protocol/commands.py |
Constructeurs de commandes (chaînes pures) |
messages |
ai/src/protocol/messages.py |
Dataclasses/enums des messages |
update |
ai/src/protocol/update.py |
Callbacks de mise à jour de l'état |
parser — lignes serveur vers messages¶
parse_server_line(line, client) (ai/src/protocol/parser.py:26) aiguille
chaque ligne via un match :
match line:
case "ok": return OkKo.OK
case "ko": return OkKo.KO
case "dead": return DeadMessage()
case _ if line.startswith("message "): return parse_broadcast(line)
case _ if line.startswith("eject: "): return parse_eject(line)
case _ if line.startswith("Elevation underway"): return ElevationResult(success=True, level=None)
case _ if line.startswith("Current level: "): ... # -> ElevationResult(success=True, level=k)
case _ if line.startswith("["): ... # Look ou Inventory
case _: raise ValueError(...)
Points clés :
ok/kodeviennent l'enumOkKo;deadunDeadMessage.Elevation underwayetCurrent level: kdeviennent tous deux unElevationResult(success=True, ...), le second portant le nouveau niveau.- Lignes
[...]: ambiguës entreLooketInventory. La désambiguïsation s'appuie surclient.command_queue.peek_last_command()(ai/src/protocol/parser.py:54-60) — si la dernière commande étaitLookon appelleparse_look, si c'étaitInventoryon appelleparse_inventory.
parse_look & parse_inventory¶
parse_look (ai/src/protocol/parser.py:66) retire les crochets, découpe sur
les virgules, puis découpe chaque tuile sur les espaces → LookResult(tiles=...)
(une tuile vide donne une liste vide).
parse_inventory (ai/src/protocol/parser.py:82) découpe de même mais attend
des paires ressource quantité → InventoryResult(items={...}).
parse_eject (ai/src/protocol/parser.py:124) extrait l'entier K après
eject: → EjectMessage(direction=K).
parse_broadcast est un stub
parse_broadcast (ai/src/protocol/parser.py:102) lève
NotImplementedError : les broadcasts entrants ne sont pas traités. La
coordination d'équipe en pâtit. Voir
Limitations connues.
commands — constructeurs de commandes¶
commands.py (ai/src/protocol/commands.py) fournit des fonctions pures qui
renvoient la chaîne exacte de la commande, sans \n final :
def forward() -> str: return "Forward"
def look() -> str: return "Look"
def inventory() -> str: return "Inventory"
def broadcast(text) -> str: return f"Broadcast {text}"
def take(obj) -> str: return f"Take {obj}"
def set(obj) -> str: return f"Set {obj}"
def incantation() -> str: return "Incantation"
# … right, left, connect_nbr, fork, eject
Le \n est ajouté à l'envoi
Ces constructeurs ne produisent pas le saut de ligne final : c'est
Client.send_command qui pousse command + "\n" dans l'OutputBuffer (cf.
Réseau). Garder cette convention évite les doubles \n.
messages — messages typés¶
messages.py (ai/src/protocol/messages.py) définit les structures de
données — aucune logique, uniquement des conteneurs (@dataclass(frozen=True)
et un enum) :
| Type | Contenu |
|---|---|
OkKo |
Enum OK / KO |
LookResult |
tiles ; pos et direction optionnels (réinjectés par la FSM) |
InventoryResult |
items: dict[str, int] |
BroadcastMessage |
direction: int, text: str |
EjectMessage |
direction: int |
DeadMessage |
(vide) |
ElevationResult |
success: bool, level: int \| None |
ConnectNbrResult |
slots: int |
Message est l'union typant toute ligne serveur parsée.
ConnectNbrResult jamais produit
ConnectNbrResult est défini mais aucun parseur ne le construit, car la
reproduction (Fork / Connect_nbr) n'est pas implémentée. Voir
Stratégie (FSM) et Limitations connues.
update — callbacks de mise à jour¶
update.py (ai/src/protocol/update.py) fournit les callbacks branchés par
DroneState à la construction (cf. État interne) :
update_inventory(drone, client, line)(ai/src/protocol/update.py:15) parse la ligne, vérifie que c'est bien unInventoryResult, puis met à jourdrone.inventoryetdrone.food. Surtout, il poseconfig.INIT = True— c'est ce drapeau qui autorise ensuite la boucle principale à sortir surdrone.is_dead()(on ne déclare pas le drone mort tant que le premier inventaire n'est pas arrivé).update_vision(drone, client, line)(ai/src/protocol/update.py:31) parse la ligne et stocke leLookResultdansdrone.last_vision(sinonNone).
Pour aller plus loin¶
- Réseau & file de commandes — d'où viennent les lignes brutes et
comment
peek_last_commanddésambiguïse les[...]. - État interne — comment l'inventaire et la vision alimentent l'état.
- Limitations connues —
parse_broadcast,ConnectNbrResult.