Spaces:
Sleeping
🚜 HARVESTER AI FIX - Correction du comportement automatique
Date: 3 Octobre 2025
Problème rapporté: "Havester reste immobile après sortie du HQ, ne cherche pas ressources automatiquement"
Status: ✅ CORRIGÉ
🐛 PROBLÈME IDENTIFIÉ
Symptômes
- Le Harvester sort du HQ après production
- Il reste immobile (peut être sélectionné mais ne bouge pas)
- Il ne cherche PAS automatiquement les ressources
- Pas de mouvement vers les patches ORE/GEM
Cause racine
Ligne 571 de app.py (AVANT correction) :
# Find nearest ore if not gathering and not target
if not unit.gathering and not unit.target:
nearest_ore = self.find_nearest_ore(unit.position)
if nearest_ore:
unit.ore_target = nearest_ore
unit.gathering = True
unit.target = nearest_ore
Problème: La condition not unit.target était trop restrictive !
Quand le Harvester sort du HQ ou dépose des ressources, il avait parfois un target résiduel (position de sortie, dernière commande de mouvement, etc.). Avec ce target résiduel, la condition if not unit.gathering and not unit.target: échouait, donc find_nearest_ore() n'était JAMAIS appelé.
Scénario du bug
1. Harvester spawn depuis HQ à position (200, 200)
2. Harvester a target résiduel = (220, 220) [position de sortie]
3. update_harvester() appelé:
- unit.returning = False ✓
- unit.ore_target = None ✓
- unit.gathering = False ✓
- unit.target = (220, 220) ❌ [RÉSIDUEL!]
4. Condition: if not unit.gathering and not unit.target:
- not False = True ✓
- not (220, 220) = False ❌
- True AND False = FALSE
5. Bloc find_nearest_ore() JAMAIS EXÉCUTÉ
6. Harvester reste immobile indéfiniment 😱
✅ CORRECTION IMPLÉMENTÉE
Changements dans app.py
1. Ligne 530 - Nettoyer target après dépôt
# Deposit cargo
self.game_state.players[unit.player_id].credits += unit.cargo
unit.cargo = 0
unit.returning = False
unit.gathering = False
unit.ore_target = None
unit.target = None # ← AJOUTÉ: Nettoie target résiduel
2. Lignes 571-577 - Logique de recherche améliorée
# FIXED: Always search for ore when idle (not gathering and no ore target)
# This ensures Harvester automatically finds ore after spawning or depositing
if not unit.gathering and not unit.ore_target: # ← CHANGÉ: Vérifie ore_target au lieu de target
nearest_ore = self.find_nearest_ore(unit.position)
if nearest_ore:
unit.ore_target = nearest_ore
unit.gathering = True
unit.target = nearest_ore
# If no ore found, clear any residual target to stay idle
elif unit.target:
unit.target = None # ← AJOUTÉ: Nettoie target si pas de minerai
Logique améliorée
AVANT (bugué) :
if not unit.gathering and not unit.target:
# Cherche minerai
❌ Échoue si target résiduel existe
APRÈS (corrigé) :
if not unit.gathering and not unit.ore_target:
# Cherche minerai
if nearest_ore:
# Assigne target
elif unit.target:
unit.target = None # Nettoie résiduel
✅ Fonctionne toujours, même avec target résiduel
🔄 NOUVEAU CYCLE COMPLET
Avec la correction, voici le cycle automatique du Harvester :
1. SPAWN depuis HQ
├─ cargo = 0
├─ gathering = False
├─ returning = False
├─ ore_target = None
└─ target = None (ou résiduel)
2. update_harvester() tick 1
├─ Condition: not gathering (True) and not ore_target (True)
├─ → find_nearest_ore() appelé ✅
├─ → ore_target = Position(1200, 800) [minerai trouvé]
├─ → gathering = True
└─ → target = Position(1200, 800)
3. MOVING TO ORE (ticks 2-50)
├─ ore_target existe → continue
├─ Distance > 20px → move to target
└─ Unit se déplace automatiquement
4. HARVESTING (tick 51)
├─ Distance < 20px
├─ Récolte tile: cargo += 50 (ORE) ou +100 (GEM)
├─ Terrain → GRASS
├─ ore_target = None
└─ gathering = False
5. CONTINUE ou RETURN
├─ Si cargo < 180 → retour étape 2 (cherche nouveau minerai)
└─ Si cargo ≥ 180 → returning = True
6. DEPOSITING
├─ find_nearest_depot() trouve HQ/Refinery
├─ Move to depot
├─ Distance < 80px → deposit
├─ credits += cargo
├─ cargo = 0, returning = False
└─ target = None ✅ [NETTOYÉ!]
7. REPEAT → Retour étape 2
🧪 TESTS
Test manuel
Lancer le serveur
cd /home/luigi/rts/web python app.pyOuvrir le jeu dans le navigateur
http://localhost:7860Produire un Harvester
- Sélectionner le HQ (Quartier Général)
- Cliquer sur bouton "Harvester" (200 crédits)
- Attendre production (~5 secondes)
Observer le comportement
- ✅ Harvester sort du HQ
- ✅ Après 1-2 secondes, commence à bouger automatiquement
- ✅ Se dirige vers le patch ORE/GEM le plus proche
- ✅ Récolte automatiquement
- ✅ Retourne au HQ/Refinery automatiquement
- ✅ Dépose et recommence automatiquement
Test automatisé
Script Python créé : /home/luigi/rts/web/test_harvester_ai.py
cd /home/luigi/rts/web
python test_harvester_ai.py
Le script :
- Vérifie les ressources sur la carte
- Produit un Harvester
- Surveille son comportement pendant 10 secondes
- Vérifie que :
- Le Harvester bouge (distance > 10px)
- Le flag
gatheringest activé ore_targetest assignétargetest défini pour le mouvement
📊 VÉRIFICATIONS
Checklist de fonctionnement
- Serveur démarre sans erreur
- Terrain contient ORE/GEM (check
/healthendpoint) - HQ existe pour Joueur 0
- Crédits ≥ 200 pour production
- Harvester produit depuis HQ (PAS Refinery!)
- Harvester sort du HQ après production
- Harvester commence à bouger après 1-2 secondes ← NOUVEAU!
- Harvester se dirige vers minerai
- Harvester récolte (ORE → GRASS)
- Harvester retourne au dépôt
- Crédits augmentent après dépôt
- Harvester recommence automatiquement
Debugging
Si le Harvester ne bouge toujours pas :
Vérifier les logs serveur
# Ajouter dans update_harvester() ligne 515 print(f"[Harvester {unit.id[:8]}] gathering={unit.gathering}, " f"returning={unit.returning}, cargo={unit.cargo}, " f"ore_target={unit.ore_target}, target={unit.target}")Vérifier le terrain
curl http://localhost:7860/health | jq '.terrain' | grep -c '"ore"' # Devrait retourner > 0Vérifier update_harvester() appelé
# Dans update_game_state() ligne 428 if unit.type == UnitType.HARVESTER: print(f"[TICK {self.game_state.tick}] Calling update_harvester for {unit.id[:8]}") self.update_harvester(unit)Vérifier find_nearest_ore() trouve quelque chose
# Dans update_harvester() ligne 572 nearest_ore = self.find_nearest_ore(unit.position) print(f"[Harvester {unit.id[:8]}] find_nearest_ore returned: {nearest_ore}")
🎯 RÉSULTATS ATTENDUS
Avant correction
❌ Harvester sort du HQ
❌ Reste immobile indéfiniment
❌ gathering = False (jamais activé)
❌ ore_target = None (jamais assigné)
❌ target = (220, 220) [résiduel du spawn]
Après correction
✅ Harvester sort du HQ
✅ Commence à bouger après 1-2 secondes
✅ gathering = True (activé automatiquement)
✅ ore_target = Position(1200, 800) (assigné automatiquement)
✅ target = Position(1200, 800) (suit ore_target)
✅ Cycle complet fonctionne
📝 NOTES TECHNIQUES
Différence clé
Condition AVANT :
if not unit.gathering and not unit.target:
- Vérifie
target(peut être résiduel) - Échoue si spawn/mouvement laisse un
target
Condition APRÈS :
if not unit.gathering and not unit.ore_target:
- Vérifie
ore_target(spécifique à la récolte) - Réussit toujours après spawn/dépôt (ore_target nettoyé)
- Nettoie
targetrésiduel si pas de minerai
États du Harvester
| État | gathering | returning | ore_target | target | Comportement |
|---|---|---|---|---|---|
| IDLE | False | False | None | None | ✅ Cherche minerai |
| SEARCHING | True | False | Position | Position | Se déplace vers ore |
| HARVESTING | True | False | Position | Position | Récolte sur place |
| FULL | False | True | None | None → Depot | Retourne au dépôt |
| DEPOSITING | False | True | None | Depot | Se déplace vers dépôt |
| AFTER DEPOSIT | False | False | None | None ✅ | Retour IDLE (cherche) |
Le nettoyage de target = None après dépôt garantit que le Harvester revient à l'état IDLE proprement.
🚀 DÉPLOIEMENT
Mettre à jour Docker
cd /home/luigi/rts
docker build -t rts-game .
docker stop rts-container 2>/dev/null || true
docker rm rts-container 2>/dev/null || true
docker run -d -p 7860:7860 --name rts-container rts-game
Tester immédiatement
# Vérifier serveur
curl http://localhost:7860/health
# Ouvrir navigateur
firefox http://localhost:7860
# Ou test automatisé
cd /home/luigi/rts/web
python test_harvester_ai.py
✅ CONCLUSION
Problème: Harvester immobile après spawn
Cause: Condition not unit.target trop restrictive avec targets résiduels
Solution: Vérifier not unit.ore_target + nettoyer target après dépôt
Résultat: Harvester cherche automatiquement ressources comme Red Alert! 🚜💰
Status: ✅ CORRIGÉ ET TESTÉ
Fichiers modifiés:
/home/luigi/rts/web/app.py(lignes 530, 571-577)/home/luigi/rts/web/test_harvester_ai.py(nouveau)/home/luigi/rts/web/HARVESTER_AI_FIX.md(ce document)