File size: 4,964 Bytes
12bc208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
"""
decision.py — Tactical Decision Layer
---------------------------------------
Receives ETA and hit probability from models.py and converts them into
a human-readable threat level and tactical recommendation.

This module knows nothing about models, physics, or metadata.
Its only job is: predictions in, decision out.
"""

from src.schemas import DECISION_THRESHOLDS

def get_recommendation(eta_seconds, hit_probability, no_aa_capability, enemy_generation, friendly_generation):
    """
    Converts model predictions and platform data into a tactical recommendation.

    Args:
        eta_seconds (float): Predicted evasion time in seconds, clipped at 0.
        hit_probability (float): Probability of hit after evasion maneuvers (0.0 - 1.0).
        no_aa_capability (int): 1 if enemy has no air-to-air capability, 0 otherwise.
        enemy_generation (float): Enemy aircraft generation (e.g. 4.0, 4.5, 5.0).
        friendly_generation (float): Friendly aircraft generation (e.g. 4.0, 4.5, 5.0).

    Returns:
        str: Tactical recommendation string for the pilot.
    """
    
    # Check first air-to-air capability
    if no_aa_capability == 1:
        return "NON-THREAT PLATFORM - MONITOR"
    
    # Calculate the generational gap
    gen_gap = friendly_generation - enemy_generation
    
    # Define combat posture
    if gen_gap >= DECISION_THRESHOLDS['gen_advantage_threshold']:
        combat_posture = "Friendly advantage"
    elif gen_gap <= -DECISION_THRESHOLDS['gen_disadvantage_threshold']:
        combat_posture = "Enemy advantage"
    else:
        combat_posture = "Parity"
        
    # Get the ETA status
    if eta_seconds <= DECISION_THRESHOLDS['eta_critical']:
        eta_status = "Low ETA"
    else:
        eta_status = "High ETA"
        
        
    # Get the Hit probability status
    if hit_probability >= DECISION_THRESHOLDS['hit_prob_high']:
        hit_status = "High hit probability"
    elif DECISION_THRESHOLDS['hit_prob_medium'] <= hit_probability <= DECISION_THRESHOLDS['hit_prob_high']:
        hit_status = "Medium hit probability"
    else:
        hit_status = "Low hit probability"
        
        
    # Get the recommendation based on decisions
    if eta_status == "Low ETA":
        if hit_status == "High hit probability":
            # Critical threat - missile close, high chance of hit
            if combat_posture == "Friendly advantage":
                return "BREAK HARD + DEPLOY CM + COUNTER-ENGAGE"
            elif combat_posture == "Parity":
                return "BREAK HARD + DEPLOY CM"
            else:
                # Outmatched - survive first, disengage
                return "BREAK HARD + DEPLOY CM + DISENGAGE IMMEDIATELY"

        elif hit_status == "Medium hit probability":
            # Elevated threat - missile close, uncertain outcome
            if combat_posture == "Friendly advantage":
                return "DEPLOY CM + DEFENSIVE MANEUVERS + ENGAGE"
            elif combat_posture == "Parity":
                return "DEPLOY CM + DEFENSIVE MANEUVERS"
            else:
                # Disadvantaged - don't risk engagement
                return "DEPLOY CM + DEFENSIVE MANEUVERS + DISENGAGE"

        else:
            # Missile close but likely evadable - redirect and reassess
            if combat_posture == "Friendly advantage":
                return "DEPLOY CM + CHANGE FLIGHT PATH + ENGAGE"
            elif combat_posture == "Parity":
                return "DEPLOY CM + CHANGE FLIGHT PATH"
            else:
                return "DEPLOY CM + CHANGE FLIGHT PATH + DISENGAGE"

    else:
        if hit_status == "High hit probability":
            # Time available but threat is serious - prepare now
            if combat_posture == "Friendly advantage":
                return "DEFENSIVE MANEUVERS + PREPARE CM + COUNTER-ENGAGE"
            elif combat_posture == "Parity":
                return "DEFENSIVE MANEUVERS + PREPARE CM"
            else:
                # Outmatched - use the time to create distance
                return "DEFENSIVE MANEUVERS + PREPARE CM + MAINTAIN DISTANCE"

        elif hit_status == "Medium hit probability":
            # Uncertain threat with time to monitor - stay ready
            if combat_posture == "Friendly advantage":
                return "PREPARE CM + MONITOR + ENGAGE WHEN READY"
            elif combat_posture == "Parity":
                return "PREPARE CM + MONITOR TRAJECTORY"
            else:
                return "PREPARE CM + MAINTAIN DISTANCE"

        else:
            # Low threat - missile unlikely to hit, time available
            if combat_posture == "Friendly advantage":
                return "STAY SHARP + CLOSE AND ENGAGE"
            elif combat_posture == "Parity":
                return "STAY SHARP + MONITOR TRAJECTORY"
            else:
                # Disadvantaged even in low threat - keep distance
                return "STAY SHARP + MAINTAIN DISTANCE"