rts-commander / tests /test_harvester_ai.py
Luigi's picture
deploy(web): full clean snapshot with app code and assets
12d64f8
#!/usr/bin/env python3
"""
Test du comportement IA du Harvester
Vérifie que le Harvester cherche automatiquement les ressources après spawn
"""
import sys
import json
import time
import requests
API_URL = "http://localhost:7860"
def test_harvester_auto_collect():
"""Test que le Harvester commence automatiquement à collecter"""
print("\n" + "="*80)
print("🧪 TEST: Harvester Auto-Collection AI")
print("="*80)
# 1. Get initial state
print("\n📊 1. État initial...")
resp = requests.get(f"{API_URL}/health")
if resp.status_code != 200:
print("❌ Serveur non accessible")
return False
data = resp.json()
initial_units = len(data.get('units', []))
initial_credits_p0 = data.get('players', [{}])[0].get('credits', 0)
print(f" Units initiaux: {initial_units}")
print(f" Crédits Joueur 0: {initial_credits_p0}")
# 2. Build a Harvester from HQ
print("\n🏗️ 2. Construction d'un Harvester depuis HQ...")
# Assuming player 0 has HQ at position (5*40, 5*40) = (200, 200)
build_resp = requests.post(f"{API_URL}/ws", json={
"action": "build_unit",
"player_id": 0,
"unit_type": "harvester"
})
# Wait for production (assume instant for test)
time.sleep(2)
# 3. Check Harvester created
print("\n🔍 3. Vérification du Harvester créé...")
resp = requests.get(f"{API_URL}/health")
data = resp.json()
current_units = len(data.get('units', []))
harvesters = [u for u in data.get('units', []) if u.get('type') == 'harvester']
print(f" Units actuels: {current_units}")
print(f" Harvesters trouvés: {len(harvesters)}")
if len(harvesters) == 0:
print("❌ Aucun Harvester trouvé")
print(" Vérifiez que le HQ peut produire des Harvesters")
print(" Vérifiez que vous avez ≥200 crédits")
return False
# 4. Monitor Harvester behavior for 10 seconds
print("\n👀 4. Surveillance du comportement (10 secondes)...")
harvester = harvesters[0]
harvester_id = harvester.get('id')
initial_pos = harvester.get('position', {})
print(f" Harvester ID: {harvester_id}")
print(f" Position initiale: ({initial_pos.get('x', 0):.1f}, {initial_pos.get('y', 0):.1f})")
print(f" État: gathering={harvester.get('gathering')}, returning={harvester.get('returning')}, cargo={harvester.get('cargo')}")
movements = []
for i in range(10):
time.sleep(1)
resp = requests.get(f"{API_URL}/health")
data = resp.json()
harvesters = [u for u in data.get('units', []) if u.get('id') == harvester_id]
if not harvesters:
print(f"\n ❌ Tick {i+1}: Harvester disparu!")
return False
h = harvesters[0]
pos = h.get('position', {})
target = h.get('target')
ore_target = h.get('ore_target')
gathering = h.get('gathering')
returning = h.get('returning')
cargo = h.get('cargo')
# Calculate distance moved
dist = ((pos.get('x', 0) - initial_pos.get('x', 0))**2 +
(pos.get('y', 0) - initial_pos.get('y', 0))**2)**0.5
movements.append({
'tick': i+1,
'position': pos,
'distance': dist,
'target': target,
'ore_target': ore_target,
'gathering': gathering,
'returning': returning,
'cargo': cargo
})
status = f" 📍 Tick {i+1}: pos=({pos.get('x', 0):.1f},{pos.get('y', 0):.1f}) dist={dist:.1f}px"
if gathering:
status += " 🔍GATHERING"
if ore_target:
status += f" 🎯ORE_TARGET=({ore_target.get('x', 0):.0f},{ore_target.get('y', 0):.0f})"
if returning:
status += " 🔙RETURNING"
if cargo > 0:
status += f" 💰cargo={cargo}"
if target:
status += f" ➡️target=({target.get('x', 0):.0f},{target.get('y', 0):.0f})"
print(status)
# 5. Analysis
print("\n📊 5. Analyse du comportement...")
# Check if moved
final_dist = movements[-1]['distance']
if final_dist < 10:
print(f" ❌ ÉCHEC: Harvester n'a pas bougé (distance={final_dist:.1f}px)")
print(" 🐛 Problème: L'IA ne démarre pas automatiquement")
return False
else:
print(f" ✅ Harvester a bougé: {final_dist:.1f}px")
# Check if gathering flag set
gathering_ticks = sum(1 for m in movements if m['gathering'])
if gathering_ticks > 0:
print(f" ✅ Mode GATHERING activé ({gathering_ticks}/10 ticks)")
else:
print(f" ⚠️ Mode GATHERING jamais activé")
# Check if ore target found
ore_target_ticks = sum(1 for m in movements if m['ore_target'])
if ore_target_ticks > 0:
print(f" ✅ ORE_TARGET trouvé ({ore_target_ticks}/10 ticks)")
else:
print(f" ❌ ORE_TARGET jamais trouvé")
print(" 🐛 Problème: find_nearest_ore() ne trouve rien ou n'est pas appelé")
return False
# Check if moving toward target
target_ticks = sum(1 for m in movements if m['target'])
if target_ticks > 0:
print(f" ✅ TARGET assigné ({target_ticks}/10 ticks)")
else:
print(f" ⚠️ TARGET jamais assigné")
# Success criteria: moved AND found ore target
if final_dist > 10 and ore_target_ticks > 0:
print("\n✅ TEST RÉUSSI: Harvester cherche automatiquement les ressources!")
return True
else:
print("\n❌ TEST ÉCHOUÉ: Harvester ne fonctionne pas correctement")
return False
def show_terrain_info():
"""Affiche les informations du terrain"""
print("\n" + "="*80)
print("🌍 TERRAIN: Vérification des ressources disponibles")
print("="*80)
resp = requests.get(f"{API_URL}/health")
if resp.status_code != 200:
print("❌ Serveur non accessible")
return
data = resp.json()
terrain = data.get('terrain', [])
if not terrain:
print("❌ Pas de données terrain")
return
# Count terrain types
ore_count = 0
gem_count = 0
water_count = 0
grass_count = 0
ore_positions = []
gem_positions = []
for y, row in enumerate(terrain):
for x, cell in enumerate(row):
if cell == 'ore':
ore_count += 1
ore_positions.append((x, y))
elif cell == 'gem':
gem_count += 1
gem_positions.append((x, y))
elif cell == 'water':
water_count += 1
elif cell == 'grass':
grass_count += 1
print(f"\n📊 Statistiques terrain:")
print(f" 🟩 GRASS: {grass_count} tiles")
print(f" 🟨 ORE: {ore_count} tiles")
print(f" 💎 GEM: {gem_count} tiles")
print(f" 🟦 WATER: {water_count} tiles")
print(f" 📏 Total: {len(terrain) * len(terrain[0])} tiles")
if ore_count + gem_count == 0:
print("\n❌ PROBLÈME CRITIQUE: Aucune ressource sur la carte!")
print(" Le Harvester ne peut rien collecter.")
return
print(f"\n✅ {ore_count + gem_count} ressources disponibles")
# Show first 5 ore positions
if ore_positions:
print(f"\n🟨 Premiers patches ORE (max 5):")
for i, (x, y) in enumerate(ore_positions[:5]):
px = x * 40 + 20
py = y * 40 + 20
print(f" {i+1}. Tile ({x},{y}) → Position ({px},{py})px")
if gem_positions:
print(f"\n💎 Premiers patches GEM (max 5):")
for i, (x, y) in enumerate(gem_positions[:5]):
px = x * 40 + 20
py = y * 40 + 20
print(f" {i+1}. Tile ({x},{y}) → Position ({px},{py})px")
if __name__ == "__main__":
print("\n" + "="*80)
print("🚜 HARVESTER AI TEST SUITE")
print("="*80)
print("\n⚠️ Assurez-vous que le serveur tourne sur http://localhost:7860")
print(" (docker run ou python web/app.py)")
input("\nAppuyez sur Entrée pour continuer...")
# First check terrain
show_terrain_info()
# Then test Harvester AI
print("\n")
input("Appuyez sur Entrée pour lancer le test Harvester...")
success = test_harvester_auto_collect()
print("\n" + "="*80)
if success:
print("✅ TOUS LES TESTS RÉUSSIS")
print("="*80)
sys.exit(0)
else:
print("❌ TESTS ÉCHOUÉS")
print("="*80)
sys.exit(1)