aissia/docs/calcul-menace.md
StillHammer ba42b6d9c7 Update CDC with hybrid architecture (WarFactory + multi-target)
- 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>
2025-10-27 11:49:09 +08:00

21 KiB
Raw Blame History

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 menace
  • 100 - 1 000 : PMC petit
  • 5 000 - 50 000 : Company moyenne
  • 100 000 : État petit
  • 500 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 :

  1. Sword (attaquant) : Capacités offensives
  2. Shield (défenseur) : Capacités défensives
  3. 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() retourne false
    • 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() retourne true
    • 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 diplomatiques
  • ai-framework.md : Menace influence décisions IA (achats, alliances)
  • systeme-militaire.md : Valeurs combat équipements, générations
  • economie-logistique.md : Production rates, capacités industrielles