warfactoryracine/docs/ai-framework.md
StillHammer 5e4235889a Add comprehensive AI, diplomacy, and save system documentation
- ai-framework.md: Unified decision framework with scoring system, RL integration, doctrines
- systeme-diplomatique.md: Relations (shared), intentions (bilateral), threat, reliability systems
- calcul-menace.md: Contextual threat calculation with sword & shield mechanics
- systeme-sauvegarde.md: V1 save system with JSON, metachunks, module autonomy
- module-versioning.md: Automatic MAJOR.MINOR.PATCH.BUILD versioning via CMake

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 22:39:36 +08:00

1415 lines
38 KiB
Markdown

# AI Framework - Unified Decision System
## Philosophie
Le système d'IA de Warfactory repose sur un **framework unifié de prise de décision par scoring**. Tous les types d'IA (tactique, opérationnelle, économique, diplomatique) utilisent le même pattern fondamental :
1. **Générer options** disponibles dans le contexte actuel
2. **Scorer chaque option** selon poids configurables et situation
3. **Choisir la meilleure option** (highest score)
4. **Exécuter l'action** correspondante
Ce pattern unifié permet :
- **Cohérence** : Même logique à travers tous les systèmes IA
- **Configurabilité** : Comportements ajustables via JSON
- **Apprentissage** : Reinforcement Learning ajuste les poids
- **Modularité** : Nouveaux types de décisions ajoutables facilement
- **Testabilité** : Chaque décision isolée et vérifiable
## Architecture Globale
### Hiérarchie des Modules IA
```
AI Framework
├── Core Decision System
│ ├── IDecision (interface de base)
│ ├── Decision Factory (création objets)
│ └── Scoring Engine (évaluation uniforme)
├── Helper Modules (services, pas de décisions)
│ ├── PathfinderModule (calcul chemins)
│ ├── AcquisitionModule (sélection cibles)
│ └── MovementModule (exécution mouvement)
├── Decision Modules (utilisent helpers)
│ ├── TacticalModule (combat temps-réel)
│ ├── OperationalModule (stratégie bataille)
│ ├── CompanyAIModule (business)
│ └── StateAIModule (politique)
└── Data Modules (consultés par tous)
├── DiplomacyModule (relations, traités)
└── EconomyModule (marché, prix)
```
### Flux de Décision Type
```
OperationalModule
↓ (donne posture: "rush blindé")
TacticalModule
↓ (demande chemins pour flanking)
PathfinderModule → retourne 3 chemins possibles
↓ (demande cibles prioritaires)
AcquisitionModule → retourne 5 cibles scorées
↓ (choisit meilleure tactique)
TacticalModule → décision: flanking par chemin 2, cible 1
↓ (exécute mouvement)
MovementModule → unités se déplacent
```
## Interface IDecision - Core Pattern
### Définition
Toutes les décisions IA implémentent cette interface :
```cpp
class IDecision {
public:
virtual ~IDecision() = default;
// 1. Générer toutes les options disponibles
virtual std::vector<Option> generateOptions() = 0;
// 2. Évaluer score d'une option dans le contexte
virtual float scoreOption(const Option& opt, const Context& ctx) = 0;
// 3. Choisir la meilleure option
virtual Option chooseBest() = 0;
// 4. Exécuter l'option choisie
virtual Action execute(const Option& opt) = 0;
// 5. Obtenir les poids configurés
virtual Weights getWeights() const = 0;
// 6. Définir nouveaux poids (pour RL)
virtual void setWeights(const Weights& weights) = 0;
};
```
### Pattern d'Usage : Decision Objects Éphémères
**Principe** : New → Use → Delete
```cpp
// Création décision éphémère
IDecision* decision = DecisionFactory::create(
"flanking_maneuver",
context,
weights
);
// Évaluation et choix
Option best = decision->chooseBest();
// Exécution
Action action = decision->execute(best);
// Destruction immédiate
delete decision;
```
**Avantages** :
- **Pas d'état persistant** : Chaque décision isolée
- **Parallélisation** : Évaluer N décisions simultanément sans conflits
- **Hot-reload** : Charger nouveaux types depuis modules .so
- **Memory safety** : Objets détruits après usage
**Alternative avec smart pointers** :
```cpp
auto decision = DecisionFactory::createUnique("flanking_maneuver", ctx, weights);
Option best = decision->chooseBest();
Action action = decision->execute(best);
// Auto-delete à la sortie de scope
```
### Structures de Données
#### Option
Représente une action possible :
```cpp
struct Option {
std::string type; // "flanking", "frontal_assault", etc.
json parameters; // Paramètres spécifiques
float base_score; // Score de base (avant modifiers)
std::vector<Modifier> modifiers; // Bonus/malus contextuels
};
```
#### Context
État du monde pertinent pour la décision :
```cpp
struct Context {
json world_state; // État général (terrain, météo, etc.)
json entities; // Entités pertinentes (unités, ennemis)
json objectives; // Objectifs actuels
json constraints; // Contraintes (budget, temps, etc.)
Doctrine* doctrine; // Doctrine appliquée (USSR, OTAN, etc.)
};
```
#### Weights
Poids configurables pour le scoring :
```cpp
struct Weights {
std::map<std::string, float> values; // "aggression": 0.8, "caution": 0.3
float get(const std::string& key, float default_val = 0.5f) const {
auto it = values.find(key);
return (it != values.end()) ? it->second : default_val;
}
};
// Chargement depuis JSON
Weights Weights::fromJson(const json& data) {
Weights w;
for (auto& [key, val] : data.items()) {
w.values[key] = val.get<float>();
}
return w;
}
```
## Système de Scoring Unifié
### Formule Générale
```cpp
float IDecision::scoreOption(const Option& opt, const Context& ctx) {
float score = opt.base_score;
// Application des poids
for (auto& [factor, importance] : weights.values) {
float factor_value = evaluateFactor(factor, opt, ctx);
score += factor_value * importance;
}
// Application des modifiers contextuels
for (auto& modifier : opt.modifiers) {
score *= modifier.multiplier;
}
// Normalisation (optionnelle)
return std::clamp(score, 0.0f, 1.0f);
}
```
### Exemple Concret : PathfinderModule
**Options** : 5 chemins possibles vers objectif
```cpp
class PathDecision : public IDecision {
std::vector<Option> generateOptions() override {
std::vector<Option> paths;
// Générer chemins alternatifs
for (auto& path : pathfinder->findAllPaths(start, end)) {
Option opt;
opt.type = "path";
opt.parameters["route"] = path.waypoints;
opt.parameters["distance"] = path.length;
opt.parameters["safety"] = path.threat_level;
opt.parameters["cover"] = path.cover_percentage;
opt.base_score = 0.5f;
// Modifiers contextuels
if (path.crosses_open_terrain) {
opt.modifiers.push_back({"open_terrain", 0.7f});
}
if (path.has_chokepoints) {
opt.modifiers.push_back({"chokepoint", 0.85f});
}
paths.push_back(opt);
}
return paths;
}
float scoreOption(const Option& opt, const Context& ctx) override {
float score = opt.base_score;
// Facteurs de scoring
float distance = opt.parameters["distance"];
float safety = opt.parameters["safety"];
float cover = opt.parameters["cover"];
// Application poids configurables
score += (1.0f - distance / max_distance) * weights.get("speed");
score += safety * weights.get("safety");
score += cover * weights.get("stealth");
// Modifiers
for (auto& mod : opt.modifiers) {
score *= mod.multiplier;
}
return score;
}
};
```
**Configuration Poids (JSON)** :
```json
{
"pathfinder_weights": {
"speed": 0.6,
"safety": 0.3,
"stealth": 0.1
}
}
```
**Usage** :
```cpp
auto decision = new PathDecision(start, end, context, weights);
Option bestPath = decision->chooseBest();
Action moveAction = decision->execute(bestPath);
delete decision;
```
### Exemple : AcquisitionModule
**Options** : Cibles ennemies visibles
```cpp
class AcquisitionDecision : public IDecision {
std::vector<Option> generateOptions() override {
std::vector<Option> targets;
for (auto& enemy : visibleEnemies) {
Option opt;
opt.type = "target";
opt.parameters["entity_id"] = enemy.id;
opt.parameters["threat"] = enemy.calculateThreat();
opt.parameters["vulnerability"] = enemy.calculateVulnerability();
opt.parameters["priority"] = enemy.strategic_value;
opt.base_score = 0.5f;
// Modifiers
if (enemy.is_wounded) {
opt.modifiers.push_back({"wounded", 1.2f});
}
if (enemy.has_cover) {
opt.modifiers.push_back({"covered", 0.8f});
}
targets.push_back(opt);
}
return targets;
}
float scoreOption(const Option& opt, const Context& ctx) override {
float score = opt.base_score;
float threat = opt.parameters["threat"];
float vulnerability = opt.parameters["vulnerability"];
float priority = opt.parameters["priority"];
// Poids doctrine
score += threat * weights.get("threat_priority");
score += vulnerability * weights.get("opportunism");
score += priority * weights.get("strategic_focus");
// Modifiers
for (auto& mod : opt.modifiers) {
score *= mod.multiplier;
}
return score;
}
};
```
**Configuration** :
```json
{
"acquisition_weights": {
"threat_priority": 0.7,
"opportunism": 0.2,
"strategic_focus": 0.1
}
}
```
## Modules Spécialisés
### Helper Modules (Services)
Ces modules **ne prennent pas de décisions**, ils fournissent des services aux decision modules.
#### PathfinderModule
**Responsabilité** : Calculer chemins navigables entre deux points
**Interface** :
```cpp
class PathfinderModule : public IModule {
public:
// Trouver meilleur chemin unique
Path findPath(Position start, Position end, PathConstraints constraints);
// Trouver tous les chemins alternatifs
std::vector<Path> findAllPaths(Position start, Position end, int max_paths = 5);
// Vérifier si chemin encore valide
bool validatePath(const Path& path);
};
struct Path {
std::vector<Position> waypoints;
float length;
float threat_level; // Exposition ennemie
float cover_percentage; // % du chemin avec couvert
bool crosses_open_terrain;
bool has_chokepoints;
};
```
**Utilisé par** : TacticalModule, OperationalModule
#### AcquisitionModule
**Responsabilité** : Identifier et scorer cibles potentielles
**Interface** :
```cpp
class AcquisitionModule : public IModule {
public:
// Obtenir toutes les cibles visibles
std::vector<Target> getVisibleTargets(Unit observer);
// Scorer une cible selon contexte
float scoreTarget(Target target, Context ctx, Weights weights);
// Filtrer cibles selon critères
std::vector<Target> filterTargets(std::vector<Target> targets, FilterCriteria criteria);
};
struct Target {
EntityId id;
Position position;
float threat; // Dangerosité
float vulnerability; // Facilité élimination
float strategic_value; // Importance stratégique
bool is_wounded;
bool has_cover;
};
```
**Utilisé par** : TacticalModule
#### MovementModule
**Responsabilité** : Exécuter déplacements d'unités
**Interface** :
```cpp
class MovementModule : public IModule {
public:
// Déplacer unité selon chemin
void moveUnit(Unit unit, Path path);
// Déplacer formation
void moveFormation(std::vector<Unit> units, Path path, FormationType formation);
// Vérifier si mouvement possible
bool canMove(Unit unit, Position target);
};
```
**Utilisé par** : TacticalModule
### Decision Modules
Ces modules **prennent des décisions** en utilisant les helpers.
#### TacticalModule
**Responsabilité** : Décisions combat temps-réel (secondes/minutes)
**Décisions prises** :
- Choix tactique (flanking, frontal assault, suppression, retreat)
- Sélection cibles
- Positionnement unités
- Utilisation couvert
- Timing engagements
**Dépendances** :
- PathfinderModule (chemins)
- AcquisitionModule (cibles)
- MovementModule (exécution)
**Exemple Décision** :
```cpp
class FlankingDecision : public IDecision {
std::vector<Option> generateOptions() override {
std::vector<Option> options;
// Pour chaque flanc possible
for (auto& flankPosition : identifyFlankPositions(enemy)) {
// Demander chemins au PathfinderModule
auto paths = pathfinder->findAllPaths(myPosition, flankPosition);
for (auto& path : paths) {
// Demander cibles à AcquisitionModule
auto targets = acquisition->getVisibleTargets(myUnit);
Option opt;
opt.type = "flanking";
opt.parameters["path"] = path;
opt.parameters["flank_side"] = flankPosition.side; // "left"/"right"
opt.parameters["targets"] = targets;
opt.base_score = 0.6f; // Flanking généralement bon
// Modifiers
if (path.crosses_open_terrain) {
opt.modifiers.push_back({"exposed_approach", 0.7f});
}
if (targets.size() > 3) {
opt.modifiers.push_back({"many_targets", 1.2f});
}
options.push_back(opt);
}
}
return options;
}
float scoreOption(const Option& opt, const Context& ctx) override {
// Récupérer poids doctrine
Doctrine* doctrine = ctx.doctrine;
float flanking_preference = doctrine->tactical_weights["flanking"];
float score = opt.base_score * flanking_preference;
// Facteurs tactiques
Path path = opt.parameters["path"];
score += path.cover_percentage * weights.get("safety");
score -= path.threat_level * weights.get("caution");
// Modifiers
for (auto& mod : opt.modifiers) {
score *= mod.multiplier;
}
return score;
}
};
```
**Configuration Poids** :
```json
{
"tactical_weights": {
"safety": 0.4,
"caution": 0.3,
"aggression": 0.7
}
}
```
#### OperationalModule
**Responsabilité** : Choix stratégie/posture bataille (heures/jours)
**Décisions prises** :
- Posture opérationnelle (rush blindé, raid cavalerie, défense en profondeur)
- Allocation forces entre secteurs
- Timing offensives
- Objectifs prioritaires
**Dépendances** :
- TacticalModule (exécution tactique)
- DiplomacyModule (contexte stratégique)
**Exemple Décision** :
```cpp
class OperationalPostureDecision : public IDecision {
std::vector<Option> generateOptions() override {
std::vector<Option> postures;
// Postures disponibles selon doctrine
for (auto& [posture_name, posture_weight] : doctrine->operational_weights) {
Option opt;
opt.type = "posture";
opt.parameters["name"] = posture_name;
opt.base_score = posture_weight;
// Évaluer faisabilité
if (posture_name == "rush_blinde" && terrain.is_open) {
opt.modifiers.push_back({"favorable_terrain", 1.3f});
}
if (posture_name == "infiltration" && units.has_infantry) {
opt.modifiers.push_back({"suitable_units", 1.2f});
}
postures.push_back(opt);
}
return postures;
}
Action execute(const Option& opt) override {
std::string posture = opt.parameters["name"];
// Donner directive au TacticalModule
tacticalModule->setPosture(posture);
// Ajuster poids tactiques selon posture
if (posture == "rush_blinde") {
tacticalModule->adjustWeights({
{"flanking", 1.5f}, // Boost flanking
{"caution", 0.5f} // Réduire caution
});
}
return Action{posture, opt.parameters};
}
};
```
**Doctrines Opérationnelles** :
```json
// doctrines/ussr.json
{
"name": "USSR Deep Battle",
"operational_weights": {
"deep_battle": 0.8,
"overwhelming_assault": 0.9,
"mobile_defense": 0.4,
"raid_cavalry": 0.3,
"infiltration": 0.2
},
"tactical_weights": {
"frontal_assault": 0.8,
"flanking": 0.5,
"combined_arms": 0.7,
"retreat_threshold": 0.2
}
}
// doctrines/nato.json
{
"name": "NATO AirLand Battle",
"operational_weights": {
"airland_battle": 0.9,
"maneuver_warfare": 0.8,
"deep_strike": 0.7,
"overwhelming_assault": 0.4,
"mobile_defense": 0.6
},
"tactical_weights": {
"frontal_assault": 0.3,
"flanking": 0.9,
"combined_arms": 0.9,
"retreat_threshold": 0.6
}
}
```
#### CompanyAIModule
**Responsabilité** : Décisions business (jours/semaines)
**Décisions prises** :
- Investissements R&D
- Production (quoi produire, combien)
- Prix et stratégie commerciale
- Lobbying états
- Acquisitions/expansions
**Dépendances** :
- EconomyModule (prix marché, demande)
- DiplomacyModule (relations, influence)
**Exemple Décision** :
```cpp
class CompanyInvestmentDecision : public IDecision {
std::vector<Option> generateOptions() override {
std::vector<Option> investments;
// R&D options
for (auto& tech : availableTechnologies) {
Option opt;
opt.type = "research";
opt.parameters["tech_id"] = tech.id;
opt.parameters["cost"] = tech.research_cost;
opt.parameters["expected_profit"] = estimateProfit(tech);
opt.base_score = 0.5f;
if (tech.is_breakthrough) {
opt.modifiers.push_back({"breakthrough", 1.5f});
}
investments.push_back(opt);
}
// Production expansion
Option expand;
expand.type = "expand_production";
expand.parameters["cost"] = calculate_expansion_cost();
expand.parameters["capacity_increase"] = 0.3f;
expand.base_score = 0.4f;
investments.push_back(expand);
// Lobbying
for (auto& state : states) {
float influence = diplomacy->getInfluence(company_id, state.id);
if (influence < 0.8f) {
Option lobby;
lobby.type = "lobbying";
lobby.parameters["state_id"] = state.id;
lobby.parameters["cost"] = calculateLobbyCost(state);
lobby.parameters["influence_gain"] = 0.1f;
lobby.base_score = 0.3f;
investments.push_back(lobby);
}
}
return investments;
}
float scoreOption(const Option& opt, const Context& ctx) override {
float score = opt.base_score;
if (opt.type == "research") {
float expected_profit = opt.parameters["expected_profit"];
float cost = opt.parameters["cost"];
float roi = expected_profit / cost;
score += roi * weights.get("innovation");
score -= (cost / company_budget) * weights.get("risk_aversion");
}
else if (opt.type == "lobbying") {
float influence_gain = opt.parameters["influence_gain"];
score += influence_gain * weights.get("political_focus");
}
for (auto& mod : opt.modifiers) {
score *= mod.multiplier;
}
return score;
}
};
```
**Configuration Company** :
```json
{
"company_ai_weights": {
"innovation": 0.7,
"risk_aversion": 0.4,
"political_focus": 0.6,
"profit_maximization": 0.8,
"quality_focus": 0.6
}
}
```
#### StateAIModule
**Responsabilité** : Décisions étatiques (semaines/mois)
**Décisions prises** :
- Achats militaires
- Alliances diplomatiques
- Budgets sectoriels
- Objectifs stratégiques
**Dépendances** :
- DiplomacyModule (relations)
- EconomyModule (budget disponible)
- OperationalModule (besoins militaires)
**Exemple Décision** :
```cpp
class StateMilitaryPurchaseDecision : public IDecision {
std::vector<Option> generateOptions() override {
std::vector<Option> purchases;
// Pour chaque Company
for (auto& company : companies) {
// Vérifier relation diplomatique
float relation = diplomacy->getRelation(state_id, company.id);
if (relation < 0.3f) continue; // Trop mauvaise relation
// Pour chaque véhicule disponible
for (auto& vehicle : company.catalog) {
Option opt;
opt.type = "purchase";
opt.parameters["company_id"] = company.id;
opt.parameters["vehicle_id"] = vehicle.id;
opt.parameters["price"] = vehicle.price;
opt.parameters["performance"] = vehicle.combat_rating;
opt.base_score = 0.5f;
// Modifiers
if (relation > 0.8f) {
opt.modifiers.push_back({"good_relations", 1.2f});
}
if (company.reputation > 0.9f) {
opt.modifiers.push_back({"trusted_brand", 1.1f});
}
purchases.push_back(opt);
}
}
return purchases;
}
float scoreOption(const Option& opt, const Context& ctx) override {
float score = opt.base_score;
float price = opt.parameters["price"];
float performance = opt.parameters["performance"];
float value = performance / price;
score += value * weights.get("cost_effectiveness");
score += performance * weights.get("quality_priority");
// Influence politique
CompanyId company = opt.parameters["company_id"];
float influence = diplomacy->getInfluence(company, state_id);
score += influence * weights.get("lobbying_susceptibility");
for (auto& mod : opt.modifiers) {
score *= mod.multiplier;
}
return score;
}
};
```
**Configuration State** :
```json
{
"state_ai_weights": {
"cost_effectiveness": 0.6,
"quality_priority": 0.7,
"lobbying_susceptibility": 0.4,
"strategic_autonomy": 0.5
}
}
```
## Decision Factory
### Création Dynamique
```cpp
class DecisionFactory {
public:
// Enregistrer types de décisions
static void registerDecision(const std::string& type, DecisionCreator creator);
// Créer décision par nom
static IDecision* create(
const std::string& type,
const Context& ctx,
const Weights& weights
);
// Créer avec smart pointer
static std::unique_ptr<IDecision> createUnique(
const std::string& type,
const Context& ctx,
const Weights& weights
);
private:
static std::map<std::string, DecisionCreator> registry;
};
// Type pour fonction de création
using DecisionCreator = std::function<IDecision*(const Context&, const Weights&)>;
```
### Enregistrement Décisions
```cpp
// Dans l'initialisation du module
void TacticalModule::initialize() {
DecisionFactory::registerDecision("flanking", [](auto ctx, auto weights) {
return new FlankingDecision(ctx, weights);
});
DecisionFactory::registerDecision("frontal_assault", [](auto ctx, auto weights) {
return new FrontalAssaultDecision(ctx, weights);
});
DecisionFactory::registerDecision("retreat", [](auto ctx, auto weights) {
return new RetreatDecision(ctx, weights);
});
}
```
### Chargement depuis Modules .so
```cpp
// Hot-reload de nouveaux types de décisions
void AIFramework::loadDecisionModule(const std::string& module_path) {
void* handle = dlopen(module_path.c_str(), RTLD_LAZY);
// Récupérer fonction d'enregistrement
auto registerFunc = (RegisterDecisionsFunc)dlsym(handle, "registerDecisions");
// Enregistrer les décisions du module
registerFunc(DecisionFactory::getInstance());
}
```
## Reinforcement Learning Integration
### Ajustement des Poids
Le système RL ajuste les poids selon résultats des décisions :
```cpp
class RLEngine {
public:
// Enregistrer une décision et son outcome
void recordDecision(
const std::string& decision_type,
const Weights& weights_used,
const Option& chosen_option,
float outcome_reward // -1.0 à +1.0
);
// Ajuster poids selon historical performance
Weights adjustWeights(
const std::string& decision_type,
const Weights& current_weights,
float learning_rate = 0.1f
);
// Obtenir poids optimisés pour contexte
Weights getOptimizedWeights(
const std::string& decision_type,
const Context& ctx
);
private:
struct DecisionRecord {
Weights weights;
Option option;
float reward;
Context context;
};
std::map<std::string, std::vector<DecisionRecord>> history;
};
```
### Exemple RL Tactique
```cpp
// Enregistrer décision
auto decision = new FlankingDecision(ctx, current_weights);
Option best = decision->chooseBest();
Action action = decision->execute(best);
delete decision;
// Observer résultat combat
float outcome = evaluateCombatOutcome(); // -1.0 (défaite) à +1.0 (victoire)
// Enregistrer pour RL
rlEngine->recordDecision("flanking", current_weights, best, outcome);
// Ajuster poids pour prochaine fois
Weights new_weights = rlEngine->adjustWeights("flanking", current_weights);
saveWeights("tactical_flanking_weights.json", new_weights);
```
### Poids Initiaux (Manuels)
**Important** : En V1, pas de training automatique. Poids configurés manuellement dans JSON.
```json
// config/ai/tactical_initial_weights.json
{
"flanking": {
"safety": 0.4,
"caution": 0.3,
"aggression": 0.7,
"speed": 0.6
},
"frontal_assault": {
"safety": 0.2,
"caution": 0.1,
"aggression": 0.9,
"overwhelming_force": 0.8
},
"retreat": {
"safety": 0.9,
"caution": 0.8,
"preservation": 0.9
}
}
```
Le RL ajuste ces valeurs au fil du temps selon expérience.
## Performance et Optimisation
### Object Pooling
Pour éviter new/delete fréquents :
```cpp
class DecisionPool {
public:
template<typename T>
T* acquire(const Context& ctx, const Weights& weights) {
if (pool.empty()) {
return new T(ctx, weights);
}
T* obj = pool.back();
pool.pop_back();
obj->reset(ctx, weights);
return obj;
}
template<typename T>
void release(T* obj) {
pool.push_back(obj);
}
private:
std::vector<IDecision*> pool;
};
```
**Usage** :
```cpp
auto decision = decisionPool->acquire<FlankingDecision>(ctx, weights);
Option best = decision->chooseBest();
decisionPool->release(decision);
```
### Parallélisation
Évaluer plusieurs décisions simultanément :
```cpp
std::vector<Option> evaluateDecisionsParallel(
const std::vector<std::string>& decision_types,
const Context& ctx,
const Weights& weights
) {
std::vector<std::future<Option>> futures;
for (auto& type : decision_types) {
futures.push_back(std::async(std::launch::async, [&]() {
auto decision = DecisionFactory::createUnique(type, ctx, weights);
return decision->chooseBest();
}));
}
std::vector<Option> results;
for (auto& future : futures) {
results.push_back(future.get());
}
return results;
}
```
### Performance Targets
- **TacticalModule** : 60 décisions/seconde (temps-réel combat)
- **OperationalModule** : 10 décisions/seconde (moins fréquent)
- **CompanyAI** : 1 décision/seconde (batch processing)
- **StateAI** : 0.1 décision/seconde (décisions rares)
## Intégration Architecture Modulaire
### AI Framework comme Module
```cpp
class AIFrameworkModule : public IModule {
public:
void initialize() override {
// Charger configurations
loadDoctrines("config/doctrines/");
loadWeights("config/ai/");
// Enregistrer décisions
registerAllDecisions();
// Initialiser RL engine
rlEngine = new RLEngine();
}
json process(const json& input) override {
// Traiter requêtes de décision
std::string decision_type = input["decision_type"];
Context ctx = Context::fromJson(input["context"]);
Weights weights = getWeights(decision_type);
auto decision = DecisionFactory::createUnique(decision_type, ctx, weights);
Option best = decision->chooseBest();
json output;
output["chosen_option"] = best.toJson();
return output;
}
void shutdown() override {
delete rlEngine;
}
};
```
### Communication avec Autres Modules
**TacticalModule demande décision** :
```cpp
// TacticalModule process()
json request;
request["decision_type"] = "flanking";
request["context"] = currentContext.toJson();
json response = sendToModule("ai_framework", request);
Option chosen = Option::fromJson(response["chosen_option"]);
// Exécuter
executeOption(chosen);
```
**OperationalModule configure TacticalModule** :
```cpp
// OperationalModule choisit posture
auto decision = new OperationalPostureDecision(ctx, weights);
Option posture = decision->chooseBest();
// Envoyer directive à TacticalModule
json directive;
directive["posture"] = posture.parameters["name"];
directive["weight_adjustments"] = calculateAdjustments(posture);
sendToModule("tactical", directive);
```
## Configuration et Données
### Structure Fichiers Config
```
config/
├── ai/
│ ├── tactical_weights.json
│ ├── operational_weights.json
│ ├── company_weights.json
│ └── state_weights.json
├── doctrines/
│ ├── ussr.json
│ ├── nato.json
│ ├── china.json
│ └── guerrilla.json
└── rl/
├── learning_rates.json
└── reward_functions.json
```
### Exemple Configuration Complète
**config/ai/tactical_weights.json** :
```json
{
"flanking": {
"safety": 0.4,
"caution": 0.3,
"aggression": 0.7,
"speed": 0.6,
"stealth": 0.5
},
"frontal_assault": {
"safety": 0.2,
"caution": 0.1,
"aggression": 0.9,
"overwhelming_force": 0.8,
"speed": 0.4
},
"suppression": {
"safety": 0.6,
"rate_of_fire": 0.9,
"ammunition_conservation": 0.3,
"area_denial": 0.8
},
"retreat": {
"safety": 0.9,
"caution": 0.8,
"preservation": 0.9,
"speed": 0.7,
"covering_fire": 0.6
}
}
```
**config/doctrines/ussr.json** (complet) :
```json
{
"name": "USSR Deep Battle Doctrine",
"description": "Emphasis on overwhelming force, combined arms, and continuous offensive operations",
"operational_weights": {
"deep_battle": 0.8,
"overwhelming_assault": 0.9,
"echeloned_attack": 0.7,
"mobile_defense": 0.4,
"raid_cavalry": 0.3,
"infiltration": 0.2,
"attritional_warfare": 0.6
},
"tactical_weights": {
"frontal_assault": 0.8,
"flanking": 0.5,
"combined_arms": 0.7,
"artillery_preparation": 0.9,
"retreat_threshold": 0.2,
"counterattack": 0.7,
"urban_combat": 0.6
},
"resource_priorities": {
"armor_quantity": 0.9,
"artillery": 0.8,
"infantry_mass": 0.7,
"air_support": 0.5,
"logistics": 0.6
},
"special_characteristics": {
"accepts_high_casualties": true,
"prefers_night_operations": true,
"emphasizes_political_officers": true
}
}
```
**config/doctrines/nato.json** (complet) :
```json
{
"name": "NATO AirLand Battle Doctrine",
"description": "Deep strike, maneuver warfare, and combined arms with heavy air integration",
"operational_weights": {
"airland_battle": 0.9,
"maneuver_warfare": 0.8,
"deep_strike": 0.7,
"defensive_depth": 0.6,
"overwhelming_assault": 0.4,
"mobile_defense": 0.6,
"decapitation_strike": 0.7
},
"tactical_weights": {
"frontal_assault": 0.3,
"flanking": 0.9,
"combined_arms": 0.9,
"artillery_preparation": 0.6,
"retreat_threshold": 0.6,
"air_strikes": 0.9,
"precision_engagement": 0.8
},
"resource_priorities": {
"armor_quality": 0.9,
"air_superiority": 0.9,
"precision_munitions": 0.8,
"C4ISR": 0.9,
"logistics": 0.8
},
"special_characteristics": {
"accepts_high_casualties": false,
"prefers_technology_advantage": true,
"emphasizes_initiative": true
}
}
```
## Évolution Future
### Version 2 : Apprentissage Actif
- **Auto-training** : RL s'entraîne via simulations automatiques
- **Meta-learning** : Adaptation rapide à nouvelles situations
- **Transfer learning** : Connaissances transférées entre doctrines
### Version 3 : Comportements Émergents
- **Genetic algorithms** : Companies/States évoluent génération par génération
- **Multi-agent RL** : Plusieurs IA apprennent en compétition/coopération
- **Adaptive doctrines** : Doctrines mutent selon expérience
### Version 4 : Neural Networks
- **Deep RL** : Réseaux neurones pour décisions complexes
- **Pattern recognition** : Reconnaître situations similaires historiques
- **Predictive modeling** : Anticiper actions adversaires
## Références Croisées
- `systeme-militaire.md` : Combat, véhicules, doctrines militaires
- `economie-logistique.md` : Marché, pricing, supply chains
- `architecture-modulaire.md` : Intégration modules, hot-reload
- `systeme-sauvegarde.md` : Persistence états IA, poids RL
## Exemples Pratiques
### Exemple Complet : Décision Tactique
```cpp
// Contexte bataille
Context ctx;
ctx.world_state = {
{"terrain", "open_plains"},
{"weather", "clear"},
{"time_of_day", "dawn"}
};
ctx.entities = {
{"my_units", {{"tanks", 10}, {"ifv", 5}}},
{"enemy_units", {{"tanks", 8}, {"infantry", 20}}}
};
ctx.objectives = {
{"primary", "secure_hill"},
{"secondary", "minimize_casualties"}
};
ctx.doctrine = doctrineManager->getDoctrine("nato");
// Charger poids
Weights weights = loadWeights("config/ai/tactical_weights.json", "flanking");
// Créer décision
auto decision = DecisionFactory::createUnique("flanking", ctx, weights);
// Générer et évaluer options
std::vector<Option> options = decision->generateOptions();
for (auto& opt : options) {
float score = decision->scoreOption(opt, ctx);
LOG_DEBUG("Option: {} - Score: {}", opt.type, score);
}
// Choisir meilleure
Option best = decision->chooseBest();
LOG_INFO("Chosen: {} (score: {})", best.type, best.base_score);
// Exécuter
Action action = decision->execute(best);
// Observer résultat et apprendre
float outcome = waitForBattleResult();
rlEngine->recordDecision("flanking", weights, best, outcome);
```
### Exemple : Company AI Investment
```cpp
// Contexte company
Context ctx;
ctx.world_state = {
{"market_demand", "high"},
{"tech_level", "gen3"},
{"competition", "moderate"}
};
ctx.entities = {
{"budget", 1000000},
{"reputation", 0.75},
{"research_capacity", 5}
};
Weights weights = companyProfile.weights; // Profil company unique
auto decision = new CompanyInvestmentDecision(ctx, weights);
Option investment = decision->chooseBest();
if (investment.type == "research") {
TechId tech = investment.parameters["tech_id"];
startResearch(tech);
}
else if (investment.type == "lobbying") {
StateId state = investment.parameters["state_id"];
float cost = investment.parameters["cost"];
lobbyState(state, cost);
}
delete decision;
```
## Testing et Validation
### Test Unitaire Decision
```cpp
#ifdef TESTING
void testFlankingDecision() {
// Setup contexte test
Context ctx = createTestContext();
Weights weights = {{"safety", 0.5}, {"aggression", 0.8}};
// Créer décision
auto decision = new FlankingDecision(ctx, weights);
// Vérifier génération options
auto options = decision->generateOptions();
assert(options.size() > 0);
// Vérifier scoring
for (auto& opt : options) {
float score = decision->scoreOption(opt, ctx);
assert(score >= 0.0f && score <= 1.0f);
}
// Vérifier choix cohérent
Option best = decision->chooseBest();
assert(best.type == "flanking");
delete decision;
}
#endif
```
### Benchmark Performance
```cpp
void benchmarkDecisionSpeed() {
Context ctx = createBenchmarkContext();
Weights weights = loadWeights("tactical_weights.json", "flanking");
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 1000; i++) {
auto decision = new FlankingDecision(ctx, weights);
Option best = decision->chooseBest();
delete decision;
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << "1000 decisions in " << duration.count() << "μs\n";
std::cout << "Average: " << (duration.count() / 1000.0f) << "μs per decision\n";
}
```