Chessistics/CLAUDE.md
2026-04-16 22:37:20 +02:00

4.9 KiB

Chessistics

Jeu de logistique sur echiquier en Godot 4 / C#. Le joueur place des pieces d'echecs sur un plateau ; elles se deplacent automatiquement et transportent des ressources entre des productions et des demandes.

Architecture : Black-Box Simulation

Ref: https://samuel-bouchet.fr/posts/2026-04-08-black-box-sim/

Le moteur de jeu (chessistics-engine/) est une boite noire sans aucune dependance vers Godot. Il recoit des Commands, mute son etat interne, et retourne des Events. Le code Godot (Scripts/) ne fait que traduire l'input en commands et les events en visuels/animations.

Input → Command → GameSim (state + rules) → Events → Presentation
  • Commands (PlacePieceCommand, StartSimulationCommand, …) : seul moyen de modifier l'etat.
  • Events (PiecePlacedEvent, CargoDeliveredEvent, …) : seul output du moteur. Le presenteur les consomme pour animer.
  • GameSim : point d'entree unique. ProcessCommand() retourne la liste d'events.
  • Tests : chessistics-tests/ teste le moteur en headless, sans Godot.

Pieges Godot a eviter

MouseFilter sur les Controls enfants de Node2D

Tout Control (ColorRect, Label…) a MouseFilter = Stop par defaut. Quand un Control est enfant d'un Node2D (ex: les ColorRect dans CellView, les Labels dans PieceView), il participe quand meme au systeme GUI et consomme les clics, empechant _UnhandledInput de recevoir l'evenement.

Regle : toujours mettre MouseFilter = Control.MouseFilterEnum.Ignore sur les Controls purement visuels enfants de Node2D.

Conventions Claude

Plans

Les fichiers de plan doivent etre rediges a la racine du workspace (ex: /workspace/PLAN_juice.md), pas dans .claude/plans/ car ce dossier a une taille limitee.

Harnais d'automatisation (Claude peut jouer tout seul)

Le jeu peut etre pilote de maniere autonome via le flag --automation=<dir>. Un AutomationHarness (Scripts/Automation/) s'active alors comme noeud au root de la scene, lit des commandes JSON dans <dir>/inbox/, ecrit les resultats dans <dir>/outbox/, et place les captures d'ecran dans <dir>/screens/. Sans le flag, comportement normal — overhead zero.

Cote agent, un wrapper Python stdlib (tools/automation/harness.py) expose une API simple. Godot attendu a C:\Apps\godot\Godot_v4.6.2-stable_mono_win64_console.exe.

Build + utilisation

dotnet build Chessistics.csproj             # compiler avant tout lancement
python tools/automation/smoke.py            # smoke test end-to-end
python tools/automation/run_game.py         # REPL interactif

API Python

from tools.automation.harness import Harness

with Harness.launch() as h:
    h.load_mission("campaign_01", 0)        # charge la campagne + mission 0
    state = h.state()                       # snapshot complet (dict)
    h.screenshot("before")                  # -> .automation_runs/<ts>/screens/before.png
    h.place("Pawn", (0, 0), (0, 1))         # pose une piece
    h.step()                                # un tour (auto-wait animation)
    h.screenshot("after")
    h.set_speed(0.1); h.play()              # auto-play rapide

Methodes : screenshot, state, select, place, click_cell, key, play, pause, step, wait_idle, set_speed, load_mission, back_to_menu, quit.

Toutes les commandes non-query attendent EventAnimator.IsAnimating == false avant de retourner -> appels en serie toujours vus par le prochain state().

Validation visuelle par Claude

Les PNG 1280x720 ecrites dans .automation_runs/<run>/screens/ peuvent etre lues directement par l'outil Read de Claude. Workflow type pour valider l'UI :

  1. h.load_mission("campaign_01", N) + h.screenshot("mission_N_start")
  2. Lire le PNG -> verifier titre, flavor banner, board, panneau objectifs, stock
  3. Placer des pieces via h.place(...) et re-screenshot
  4. h.step() en boucle + screenshot a chaque etape
  5. Attendre phase == "MissionComplete" dans le snapshot

Cette boucle permet de valider que :

  • Les demandes affichent les bons compteurs
  • Les pieces bougent comme prevu
  • Le stock se met a jour
  • L'ecran MissionComplete apparait quand attendu

Details importants

  • Place passe par le signal PlacementRequested (meme chemin qu'un vrai clic) -- ne pas appeler GameSim.ProcessCommand(PlacePieceCommand) directement dans le dispatcher, ca mute deux fois.
  • Les captures d'ecran sont prises apres RenderingServer.frame_post_draw -> le frame reflete l'etat final, animations incluses.
  • La facade (AutomationFacade) est la seule surface exposee au dispatcher. Elle ne touche que des methodes/signals publics de GameSim, InputMapper, EventAnimator, ControlBar, PieceStockPanel. La separation black-box tient.
  • Les fichiers IPC sont ecrits .tmp puis renommes (atomique sur Windows).
  • La campagne se charge via load_mission("campaign_01", 0). Passer a une mission

    0 n'est pas supporte directement (il faut passer par MissionComplete reel).