Aller au contenu

État interne

La couche state/ est la mémoire du drone : ce qu'il sait de lui-même (niveau, inventaire, food, position, orientation) et de son environnement (la carte mentale torique). Elle est alimentée par les callbacks de mise à jour et consultée par la stratégie.

Module Fichier Rôle
drone ai/src/state/drone.py DroneState : photographie de l'état du drone
inventory ai/src/state/inventory.py Helpers d'inventaire
vision ai/src/state/vision.py Géométrie du champ de vision
world_map ai/src/state/world_map.py Carte mentale torique

DroneState — l'état du drone

DroneState (ai/src/state/drone.py:28) est un @dataclass doté d'un __init__ personnalisé (ai/src/state/drone.py:59). À la construction, il :

  • pose level = 1, inventory = {}, food = 0 ;
  • place la position au centre de la carte : pos = (W // 2, H // 2) ;
  • oriente le drone au N ;
  • construit sa propre WorldMap(W, H) ;
  • envoie immédiatement Inventory puis Look (ai/src/state/drone.py:76-86), chacun avec son callback (update_inventory / update_vision).
self.pos = (world_map[0] // 2, world_map[1] // 2)   # centre de la carte
self.direction = "N"
self.world_map = WorldMap(world_map[0], world_map[1])
...
client.send_command(inventory(), lambda line: update_inventory(self, client, line))
client.send_command(look(),      lambda line: update_vision(self, client, line))

Méthodes de vie

Méthode Définition Sens
time_units_left() food * LIFE_PER_FOOD TU de vie restants (LIFE_PER_FOOD = 126, ai/src/config.py:18)
is_starving(threshold) time_units_left() < threshold famine imminente sous un seuil en TU
is_dead() food <= 0 mort par famine

La position est estimée

Le serveur ne renvoie jamais la position absolue du drone. pos part du centre supposé et est mise à jour localement par la FSM à chaque déplacement (état local optimiste, cf. Stratégie (FSM)).

inventory — helpers d'inventaire

inventory.py (ai/src/state/inventory.py) fournit des accès de haut niveau sur un InventoryResult :

  • normalize_inventory(inv) : dictionnaire complet food + les 6 pierres (absentes ramenées à 0) ;
  • food_count(inv) : quantité de food ;
  • stones_count(inv) : {pierre: quantité for pierre in STONES} — renvoie toujours les 6 pierres, une pierre absente valant 0.

vision — géométrie du champ de vision

Au niveau n, le drone voit un cône de (n+1)² tuiles. vision.py (ai/src/state/vision.py) en donne les formules :

  • tiles_count_for_level(level) = (level + 1) ** 2 (nombre de tuiles vues) ;
  • row_width_for_distance(distance) = 2 * distance + 1 (largeur d'une rangée).

tile_index_to_relative_coord est un stub mort

tile_index_to_relative_coord (ai/src/state/vision.py:20) lève NotImplementedError. La géométrie de conversion index → coordonnée est en fait réimplémentée en ligne dans WorldMap.update_from_look ; ce stub n'est jamais appelé. Voir Limitations connues.

WorldMap — carte mentale torique

WorldMap (ai/src/state/world_map.py) mémorise les ressources aperçues, en travaillant systématiquement en coordonnées wrappées (le monde est un tore).

  • wrap(x, y) = (x % width, y % height) : repli torique.
  • remember_tile, add_resource, remove_resource, get_resources_at : mémoire par tuile.
  • nearest_food(from_pos) / nearest_resource(resource, from_pos) : tuile connue la plus proche selon la distance torique (toric_distance, ai/src/strategy/pathfinding.py).

update_from_look — projeter la vision sur la carte

update_from_look(drone_pos, drone_direction, look_tiles) (ai/src/state/world_map.py:97) est le cœur de la mémoire : pour chaque tuile du look, il déduit son décalage relatif puis le fait pivoter selon l'orientation du drone pour obtenir des coordonnées monde, qu'il wrap et mémorise :

for i, tile_objects in enumerate(look_tiles):
    level = int(math.sqrt(i))
    dx_rel = (i - level**2) - level
    dy_rel = level
    if drone_direction == "N":   real_dx, real_dy =  dx_rel, -dy_rel
    elif drone_direction == "E": real_dx, real_dy =  dy_rel,  dx_rel
    elif drone_direction == "S": real_dx, real_dy = -dx_rel,  dy_rel
    elif drone_direction == "W": real_dx, real_dy = -dy_rel, -dx_rel
    tile_pos = (drone_pos[0] + real_dx, drone_pos[1] + real_dy)
    self.remember_tile(tile_pos[0], tile_pos[1], tile_objects)

L'index i du look encode la rangée (level = ⌊√i⌋) et la colonne ; la rotation N/E/S/W transpose le repère « devant/gauche-droite » du drone en repère monde. display_map(pos) produit une grille ASCII de débogage.

Le lien avec la stratégie

L'update_from_look ci-dessus est appelé par les états de la FSM, qui réinjectent dans le LookResult la position et l'orientation du moment où le Look a été émis (et non du moment où la réponse arrive). Cette idée d'état local optimiste — mettre à jour pos/direction avant la confirmation serveur — est détaillée dans Stratégie (FSM).

Pour aller plus loin