- Add hybrid deployment modes: local_dev (MVP) and production_pwa (optional) - Integrate WarFactory engine reuse with hot-reload 0.4ms - Define multi-target compilation strategy (DLL/SO/WASM) - Detail both deployment modes with cost analysis - Add progressive roadmap: Phase 1 (local), Phase 2 (POC WASM), Phase 3 (cloud) - Budget clarified: $10-20/mois (local) vs $13-25/mois (cloud) - Document open questions for technical validation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
21 KiB
Calcul de Menace Contextuelle
Vue d'Ensemble
Le système de calcul de menace évalue la dangerosité qu'une entité représente pour une autre en analysant non seulement les forces brutes, mais aussi les capacités défensives, la qualité des équipements, et la production industrielle.
Principes Fondamentaux
- Contextuel : Menace calculée selon capacités des deux parties
- Asymétrique : A menace B ≠ B menace A
- Sword & Shield : Qualité défenses peut annuler supériorité numérique
- Production : Capacité industrielle = menace future
- Multi-domaines : Terre, air, mer évalués séparément puis agrégés
Échelle de Menace
Valeurs : 0 à 2 000 000+ (pas de maximum strict, type int32_t)
Ordres de grandeur :
0: Aucune menace100 - 1 000: PMC petit5 000 - 50 000: Company moyenne100 000: État petit500 000: État moyen (France, UK, Allemagne)900 000: Superpower (USA, Chine, Russie)1 000 000+: Menace existentielle
Architecture Calcul
Formule Globale
int calculateThreat(Entity attacker, Entity defender) {
auto params = attacker.getThreatParams();
// Composantes
int current_military = evaluateCurrentForces(attacker, defender);
int production_capacity = evaluateProduction(attacker, defender, params.projection_months);
// Pondération configurable par entité
return current_military * params.current_weight +
production_capacity * params.production_weight;
}
struct ThreatCalculationParams {
int projection_months = 12; // Horizon projection (défaut 12 mois)
float current_weight = 0.6f; // Poids forces actuelles (60%)
float production_weight = 0.4f; // Poids production (40%)
};
Personnalisation par entité :
- Company agressive :
current: 0.8, production: 0.2(focus court-terme) - State prudent :
current: 0.4, production: 0.6(focus long-terme) - PMC réactif :
current: 0.9, production: 0.1(menace immédiate prioritaire)
Évaluation Forces Actuelles
Principe : Sword & Shield
Pour chaque domaine (terre, air, mer), on évalue :
- Sword (attaquant) : Capacités offensives
- Shield (défenseur) : Capacités défensives
- Effectiveness : Dans quelle mesure le shield arrête le sword
int evaluateCurrentForces(Entity attacker, Entity defender) {
int land_threat = evaluateLandThreat(attacker, defender);
int air_threat = evaluateAirThreat(attacker, defender);
int naval_threat = evaluateNavalThreat(attacker, defender);
return land_threat + air_threat + naval_threat;
}
Évaluation Domaine Terrestre
Inventaire Forces
Attaquant :
struct LandForces {
std::vector<Tank> tanks;
std::vector<IFV> ifvs;
std::vector<APC> apcs;
std::vector<Artillery> artillery;
std::vector<Infantry> infantry;
};
Défenseur :
struct LandDefenses {
std::vector<ATSystem> anti_tank; // Systèmes anti-char
std::vector<Tank> counter_tanks; // Tanks défensifs
std::vector<Infantry> anti_tank_inf; // Infanterie AT
std::vector<Fortification> fortifications;
};
Couples Équipement ↔ Contre-mesures
Principe : Chaque type d'équipement offensif a des contre-mesures spécifiques.
struct EquipmentCounters {
std::map<EquipmentType, std::vector<CounterType>> counters = {
{TANK, {AT_MISSILE, AT_GUN, COUNTER_TANK, AT_INFANTRY}},
{IFV, {AT_MISSILE, AT_GUN, AUTOCANNON}},
{APC, {AUTOCANNON, MACHINE_GUN, RPG}},
{INFANTRY, {MACHINE_GUN, ARTILLERY, AUTOCANNON}},
{ARTILLERY, {COUNTER_BATTERY, AIR_STRIKE}}
};
};
Évaluation Sword vs Shield
Étape 1 : Match-making
Pour chaque équipement offensif, identifier contre-mesures défensives applicables :
std::vector<Defense> findApplicableDefenses(
Equipment sword,
std::vector<Defense> available_defenses
) {
std::vector<Defense> applicable;
auto counters = EquipmentCounters::counters[sword.type];
for (auto& defense : available_defenses) {
// Vérifier si défense peut contrer cet équipement
if (std::find(counters.begin(), counters.end(), defense.type) != counters.end()) {
// Vérifier compatibilité génération/qualité
if (canCounter(defense, sword)) {
applicable.push_back(defense);
}
}
}
return applicable;
}
bool canCounter(Defense defense, Equipment sword) {
// Exemple : AT missile Gen2 ne peut pas contrer tank Gen4 avec armure avancée
if (defense.generation < sword.generation - 1) {
return false; // Trop ancien
}
// Vérifier spécificités
if (sword.has_reactive_armor && defense.type == AT_MISSILE_OLD) {
return false; // ERA bloque missiles anciens
}
return true;
}
Étape 2 : Calcul Defensive Effectiveness
float calculateDefensiveEffectiveness(
std::vector<Equipment> swords,
std::vector<Defense> shields
) {
float total_sword_value = 0;
float neutralized_value = 0;
for (auto& sword : swords) {
float sword_value = sword.quantity * sword.quality;
total_sword_value += sword_value;
// Trouver défenses applicables
auto applicable_shields = findApplicableDefenses(sword, shields);
// Calculer valeur défensive totale contre ce sword
float shield_value = 0;
for (auto& shield : applicable_shields) {
float shield_effectiveness = calculateShieldEffectiveness(shield, sword);
shield_value += shield.quantity * shield.quality * shield_effectiveness;
}
// Neutralisation proportionnelle
float neutralization = min(1.0f, shield_value / sword_value);
neutralized_value += sword_value * neutralization;
}
return total_sword_value > 0 ? (neutralized_value / total_sword_value) : 0.0f;
}
Étape 3 : Score Final
int evaluateLandThreat(Entity attacker, Entity defender) {
auto swords = attacker.getLandForces();
auto shields = defender.getLandDefenses();
// Menace brute (sans défenses)
int raw_threat = 0;
for (auto& sword : swords) {
raw_threat += sword.quantity * sword.combat_value;
}
// Réduction par défenses
float defensive_effectiveness = calculateDefensiveEffectiveness(swords, shields);
// Menace finale
int final_threat = raw_threat * (1.0f - defensive_effectiveness);
return final_threat;
}
Exemples Concrets Terre
Exemple 1 : Qualité Domine Quantité
Attaquant :
- 20 tanks Gen4 (Leopard 2A7)
- Armure composite avancée
- Génération 4
- Combat value : 1000/tank
- Menace brute : 20 × 1000 = 20 000
Défenseur :
- 100 000 AT missiles Gen2
- Anciens, inefficaces contre armure Gen4
canCounter()retournefalse- Défense applicable : 0
Résultat :
defensive_effectiveness = 0 / 20000 = 0%
final_threat = 20000 × (1 - 0) = 20 000
→ Menace élevée : Défenses obsolètes inefficaces
Exemple 2 : Quantité + Qualité Écrasent
Attaquant :
- 1000 tanks Gen2
- Armure standard
- Combat value : 400/tank
- Menace brute : 1000 × 400 = 400 000
Défenseur :
- 500 AT missiles Gen4 (Javelin)
- Top-attack, très efficaces
- Combat value : 800/missile
canCounter()retournetrue- Shield effectiveness : 0.9 (très efficace)
- Shield value : 500 × 800 × 0.9 = 360 000
Résultat :
defensive_effectiveness = 360000 / 400000 = 90%
final_threat = 400000 × (1 - 0.9) = 40 000
→ Menace faible : Défenses qualitatives réduisent massavement
Exemple 3 : Masse Insuffisante
Attaquant :
- 1000 tanks Gen2
- Combat value : 400/tank
- Menace brute : 400 000
Défenseur :
- 20 AT missiles Gen4
- Très efficaces mais pas assez nombreux
- Shield value : 20 × 800 × 0.9 = 14 400
Résultat :
defensive_effectiveness = 14400 / 400000 = 3.6%
final_threat = 400000 × (1 - 0.036) = 385 440
→ Menace reste élevée : Pas assez de défenses pour couvrir la masse
Évaluation Domaine Aérien
Spécificités Air
Complexité supplémentaire :
- Qualité prime : Quelques jets furtifs Gen4 dominent des centaines AA Gen2
- ECM/ECCM : Guerre électronique critique
- Compatibilité stricte : AA anti-hélicoptère ne touche pas jets
struct AirForces {
std::vector<Fighter> fighters;
std::vector<Bomber> bombers;
std::vector<Helicopter> helicopters;
std::vector<Drone> drones;
// Capacités spéciales
bool has_stealth;
bool has_ecm; // Electronic Counter-Measures
int electronic_warfare_level;
};
struct AirDefenses {
std::vector<AAMissile> aa_missiles;
std::vector<AAGun> aa_guns;
std::vector<Fighter> interceptors;
// Capacités
bool has_eccm; // Electronic Counter-Counter-Measures
int radar_quality;
std::map<AASystem, TargetCapability> capabilities; // Quoi peut toucher quoi
};
enum TargetCapability {
HELICOPTER_ONLY, // Seulement hélicoptères
LOW_ALTITUDE, // Avions basse altitude
HIGH_ALTITUDE, // Avions haute altitude
ALL_AIRCRAFT // Tous types
};
Compatibilité Systèmes
bool canEngageAircraft(AASystem aa, Aircraft aircraft) {
// Vérifier compatibilité type
switch (aa.capability) {
case HELICOPTER_ONLY:
return aircraft.type == HELICOPTER;
case LOW_ALTITUDE:
return aircraft.altitude < 5000; // mètres
case HIGH_ALTITUDE:
return aircraft.altitude > 5000;
case ALL_AIRCRAFT:
return true;
}
// Vérifier guerre électronique
if (aircraft.has_ecm && !aa.has_eccm) {
// ECM peut brouiller AA sans ECCM
float jam_probability = aircraft.ecm_power / (aa.radar_quality + 1);
if (randomFloat() < jam_probability) {
return false; // Brouillé
}
}
// Vérifier furtivité
if (aircraft.has_stealth) {
float detection_range = aa.radar_range * (1.0f - aircraft.stealth_rating);
if (distance(aa, aircraft) > detection_range) {
return false; // Pas détecté
}
}
return true;
}
Exemple Air : Furtivité Domine
Attaquant :
- 20 jets furtifs Gen4 (F-35)
- Stealth rating : 0.9 (réduit détection 90%)
- ECM avancé
- Combat value : 2000/jet
- Menace brute : 40 000
Défenseur :
- 100 000 AA missiles Gen2
- Radar standard
- Pas ECCM
- Seulement 5% peuvent détecter/engager les furtifs
- Shield value effectif : 100000 × 0.05 × 300 = 1 500 000... mais avec ECM :
- Shield value final : 1 500 000 × 0.1 (jam rate) = 150 000
defensive_effectiveness = 150000 / 40000 = ... wait, > 1.0 !
→ Plafonné à min(1.0, value)
defensive_effectiveness = min(1.0, 150000/40000) = 1.0...
ERREUR dans mon calcul !
Correction : Le shield value doit être calculé par aircraft, pas globalement.
// Pour chaque jet
for (auto& jet : jets) {
float jet_value = jet.combat_value;
// Combien de AA peuvent l'engager ?
int applicable_aa = 0;
for (auto& aa : aa_systems) {
if (canEngageAircraft(aa, jet)) {
applicable_aa++;
}
}
// Shield value pour ce jet spécifique
float shield_value = applicable_aa * aa_combat_value;
float neutralization = min(1.0f, shield_value / jet_value);
threat_reduced += jet_value * neutralization;
}
Résultat corrigé :
- 5000 AA peuvent engager (sur 100k)
- Pour 1 jet : shield = 5000 × 300 = 1 500 000 vs jet = 2000
- Neutralization = 100% par jet
- Mais ils peuvent pas tous tirer simultanément !
Contrainte simultanéité :
// Limite engagement simultané
int max_simultaneous = min(applicable_aa, ENGAGEMENT_LIMIT);
// Exemple : Max 100 missiles simultanés par cible
float shield_value = max_simultaneous * aa_combat_value;
Avec limite 100 simultanés :
- Shield = 100 × 300 = 30 000 vs jet = 2000
- Neutralization = 100% par jet
- Mais 20 jets → seulement 2000 engagements simultanés total
- Si AA rate coordination : menace reste
C'est complexe ! Donc en pratique :
float calculateAirDefenseEffectiveness(
std::vector<Aircraft> aircraft,
std::vector<AASystem> aa_systems
) {
float total_threat = 0;
float neutralized = 0;
for (auto& ac : aircraft) {
total_threat += ac.combat_value;
// Compter AA applicables
int applicable_count = 0;
for (auto& aa : aa_systems) {
if (canEngageAircraft(aa, ac)) {
applicable_count++;
}
}
// Engagement limité
int engaged = min(applicable_count, MAX_SIMULTANEOUS_PER_TARGET);
// Probabilité kill
float kill_probability = engaged / float(ENGAGEMENTS_NEEDED_FOR_KILL);
kill_probability = min(1.0f, kill_probability);
neutralized += ac.combat_value * kill_probability;
}
return total_threat > 0 ? (neutralized / total_threat) : 0.0f;
}
Évaluation Domaine Naval
Similaire à terrestre/aérien mais avec spécificités :
- Torpilles vs sonars (submersibles)
- Anti-ship missiles vs CIWS (Close-In Weapon Systems)
- Portée extrême : Naval combat à 100+ km
Structure identique avec couples spécifiques.
Évaluation Production
Principe
La menace ne vient pas seulement des forces actuelles, mais aussi de la capacité à produire plus d'équipements.
int evaluateProduction(Entity attacker, Entity defender, int projection_months) {
int production_threat = 0;
// Pour chaque type d'équipement
for (auto& equipment_type : all_equipment_types) {
// Taux production attaquant
int attacker_rate = attacker.getProductionRate(equipment_type); // unités/mois
// Taux production défenses défenseur
int defender_rate = defender.getProductionRate(getCounterType(equipment_type));
// Projection future
int attacker_produced = attacker_rate * projection_months;
int defender_produced = defender_rate * projection_months;
// Menace nette production
int net_production = attacker_produced - defender_produced;
if (net_production > 0) {
int equipment_value = getEquipmentValue(equipment_type);
production_threat += net_production * equipment_value;
}
}
return production_threat;
}
Exemple Production
État A :
- Production actuelle : 50 tanks/mois
- Projection 12 mois : 600 tanks
- Combat value : 400/tank
- Production threat : 600 × 400 = 240 000
État B (défenseur) :
- Production AT : 100 missiles/mois
- Projection 12 mois : 1200 missiles
- Combat value : 300/missile
- Défense production : 1200 × 300 = 360 000
Net production threat :
Attacker gain : 240 000
Defender gain : 360 000
Net : 240 000 - 360 000 = -120 000 (négatif = défenseur gagne)
production_threat = max(0, net) = 0
→ État B a meilleure production, donc menace production de A est nulle.
Si inverse :
État A :
- Production : 200 tanks/mois → 2400 tanks/an
- Threat : 2400 × 400 = 960 000
État B :
- Production AT : 50 missiles/mois → 600 missiles/an
- Défense : 600 × 300 = 180 000
Net : 960 000 - 180 000 = 780 000
→ État A a production écrasante, menace industrielle massive.
Agrégation Finale
Formule Complète
int calculateThreat(Entity attacker, Entity defender) {
auto params = attacker.getThreatParams();
// Forces actuelles (sword & shield par domaine)
int land_threat = evaluateLandThreat(attacker, defender);
int air_threat = evaluateAirThreat(attacker, defender);
int naval_threat = evaluateNavalThreat(attacker, defender);
int current_military = land_threat + air_threat + naval_threat;
// Production future
int production_threat = evaluateProduction(
attacker,
defender,
params.projection_months
);
// Pondération finale
int total_threat = current_military * params.current_weight +
production_threat * params.production_weight;
return total_threat;
}
Exemples Complets
Superpower vs État Moyen
USA vs France
USA forces :
- Tanks : 8000 (Gen3-4) → 3 200 000
- Aircraft : 2000 (Gen4, furtifs) → 4 000 000
- Naval : 500 ships → 2 500 000
- Total brut : 9 700 000
France défenses :
- AT systems : 3000 (Gen3) → Shield 50% tanks
- AA systems : 1500 (Gen3) → Shield 30% aircraft
- Naval defenses : 200 → Shield 40% naval
Après sword & shield :
- Land : 3 200 000 × 0.5 = 1 600 000
- Air : 4 000 000 × 0.7 = 2 800 000
- Naval : 2 500 000 × 0.6 = 1 500 000
- Current threat : 5 900 000
Production (12 mois) :
- USA : +600 tanks, +100 aircraft → 360 000
- France : +100 tanks, +50 aircraft → 70 000
- Net production : 290 000
Total (60% current, 40% prod) :
5 900 000 × 0.6 + 290 000 × 0.4 = 3 656 000
→ Menace colossale, mais France peut tenir avec alliances
PMC vs Company
PMC_Alpha vs RheinmetallCorp
PMC forces :
- Infantry : 500 (léger armement)
- Vehicles : 20 APCs
- Total : 50 000
Rheinmetall défenses :
- Security : 100 guards
- Fortifications : minimal
- Shield : 5%
Threat : 50 000 × 0.95 = 47 500
→ PMC peut menacer installations Company, mais pas capacités production
Cas Spéciaux
Menace Économique Pure
Pour Companies sans capacités militaires :
int calculateEconomicThreat(Company attacker, Company defender) {
// Part de marché
float market_dominance = attacker.market_share / (defender.market_share + 0.01f);
// Capacité production
float production_ratio = attacker.production_capacity / defender.production_capacity;
// Qualité produits
float quality_advantage = attacker.avg_product_quality / defender.avg_product_quality;
// Menace économique
int economic_threat = (market_dominance * 100000) +
(production_ratio * 80000) +
(quality_advantage * 50000);
return economic_threat;
}
Menace Géographique
Distance géographique module menace :
float getGeographicModifier(Entity attacker, Entity defender) {
float distance_km = calculateDistance(attacker.position, defender.position);
// Projection power diminue avec distance
if (distance_km < 500) {
return 1.0f; // Menace pleine
}
else if (distance_km < 2000) {
return 0.7f; // 30% réduction
}
else if (distance_km < 5000) {
return 0.4f; // 60% réduction
}
else {
return 0.1f; // 90% réduction (trop loin)
}
}
Performance et Optimisation
Cache Threat
class ThreatCache {
private:
struct CachedThreat {
int value;
int timestamp;
int ttl = 3600; // 1 heure
};
std::map<std::pair<EntityId, EntityId>, CachedThreat> cache;
public:
int getThreat(EntityId attacker, EntityId defender) {
auto key = std::make_pair(attacker, defender);
if (cache.contains(key)) {
auto& cached = cache[key];
if (getCurrentTime() - cached.timestamp < cached.ttl) {
return cached.value;
}
}
// Recalculer
int threat = calculateThreat(attacker, defender);
cache[key] = {threat, getCurrentTime()};
return threat;
}
void invalidate(EntityId entity) {
// Invalider tous les caches impliquant cette entité
for (auto it = cache.begin(); it != cache.end();) {
if (it->first.first == entity || it->first.second == entity) {
it = cache.erase(it);
} else {
++it;
}
}
}
};
Invalidation Cache
Événements invalidant cache :
- Production nouvelle unité
- Perte unité au combat
- Nouvelle recherche technologique
- Changement doctrine militaire
Calcul Lazy
// Ne calculer que si demandé par IA
int getThreatOnDemand(EntityId attacker, EntityId defender) {
return threatCache.getThreat(attacker, defender);
}
// Pas de recalcul automatique chaque tick
Références Croisées
systeme-diplomatique.md: Utilisation menace dans relations diplomatiquesai-framework.md: Menace influence décisions IA (achats, alliances)systeme-militaire.md: Valeurs combat équipements, générationseconomie-logistique.md: Production rates, capacités industrielles