refactor: 删除所有逻辑fallback——缺失配置报错而非静默跳过
- DefaultDefensePlanner: 空catalog抛ArgumentEx, 缺ammo类型抛InvalidOp - AmmunitionSpec? → AmmunitionSpec(非空), 删除 ==null 静默返回 - 删除 0.8f射程安全系数, 1.5f时间窗口乘数 - AlgorithmFactory 移除IDefensePlanner(null)注册 - SimulationEngine 构造必须传planner,6个调用点全部更新
This commit is contained in:
parent
b5b561039b
commit
45387fee73
@ -10,7 +10,6 @@ namespace CounterDrone.Core.Algorithms
|
||||
{
|
||||
[typeof(ICloudDispersionModel)] = () => new GaussianPuffDispersion(),
|
||||
[typeof(IDamageModel)] = () => new DamageModelRouter(),
|
||||
[typeof(IDefensePlanner)] = () => new DefaultDefensePlanner(null),
|
||||
};
|
||||
|
||||
public static void Register<TInterface>(Func<object> factory)
|
||||
|
||||
@ -12,7 +12,9 @@ namespace CounterDrone.Core.Algorithms
|
||||
|
||||
public DefaultDefensePlanner(List<AmmunitionSpec> ammoCatalog)
|
||||
{
|
||||
_ammoCatalog = ammoCatalog ?? new List<AmmunitionSpec>();
|
||||
_ammoCatalog = ammoCatalog ?? throw new ArgumentNullException(nameof(ammoCatalog));
|
||||
if (_ammoCatalog.Count == 0)
|
||||
throw new ArgumentException("弹药规格目录不能为空");
|
||||
}
|
||||
|
||||
private static readonly Dictionary<PowerType, AerosolType> MatchTable = new()
|
||||
@ -60,6 +62,17 @@ namespace CounterDrone.Core.Algorithms
|
||||
var sorted = threats.OrderByDescending(t => t.Priority).ToList();
|
||||
|
||||
// Step 2-4: 贪心分配求解
|
||||
// 预先检查:所有需要的弹药类型都在目录中
|
||||
var neededTypes = sorted
|
||||
.Select(t => MatchAmmo((PowerType)t.Target.PowerType))
|
||||
.Distinct()
|
||||
.ToList();
|
||||
foreach (var t in neededTypes)
|
||||
{
|
||||
if (!_ammoCatalog.Any(a => a.AerosolType == (int)t))
|
||||
throw new InvalidOperationException($"弹药规格目录中缺少类型: {t}");
|
||||
}
|
||||
|
||||
result.Best = Solve(sorted, fireUnits, environment);
|
||||
|
||||
// Step 5: 临界方案
|
||||
@ -230,8 +243,7 @@ namespace CounterDrone.Core.Algorithms
|
||||
{
|
||||
var candidates = new List<InterceptCandidate>();
|
||||
var neededAmmo = MatchAmmo((PowerType)threat.Target.PowerType);
|
||||
var ammo = _ammoCatalog.FirstOrDefault(a => a.AerosolType == (int)neededAmmo);
|
||||
if (ammo == null) return candidates;
|
||||
var ammo = _ammoCatalog.First(a => a.AerosolType == (int)neededAmmo);
|
||||
|
||||
var ammoEff = ComputeEffectiveRadius(threat, ammo, env);
|
||||
|
||||
@ -265,7 +277,7 @@ namespace CounterDrone.Core.Algorithms
|
||||
|
||||
if (unit.MuzzleVelocity <= 0) return null;
|
||||
float maxRange = unit.MuzzleVelocity * unit.MuzzleVelocity / 9.81f;
|
||||
if (dist > maxRange * 0.8f) return null;
|
||||
if (dist > maxRange) return null;
|
||||
|
||||
float shellTime = dist / unit.MuzzleVelocity;
|
||||
float interceptTime = threat.ArrivalTime;
|
||||
@ -302,7 +314,7 @@ namespace CounterDrone.Core.Algorithms
|
||||
float totalTime = flightTime + fallTime;
|
||||
|
||||
float interceptTime = threat.ArrivalTime;
|
||||
if (totalTime > interceptTime * 1.5f) return null;
|
||||
if (totalTime > interceptTime) return null;
|
||||
|
||||
float avgSpeed = (float)threat.Target.TypicalSpeed / 3.6f;
|
||||
float neededExposure = ammoType == AerosolType.ActiveMaterial ? 2f : 6f;
|
||||
@ -365,11 +377,9 @@ namespace CounterDrone.Core.Algorithms
|
||||
return (effectiveR, expansionTime);
|
||||
}
|
||||
|
||||
private int CalcRoundsNeeded(DroneGroup threat, AmmunitionSpec? ammo,
|
||||
private int CalcRoundsNeeded(DroneGroup threat, AmmunitionSpec ammo,
|
||||
CombatScene env, bool isAirBased)
|
||||
{
|
||||
if (ammo == null) return 1;
|
||||
|
||||
float avgSpeed = (float)threat.Target.TypicalSpeed / 3.6f;
|
||||
var (effectiveR, _) = ComputeEffectiveRadius(threat, ammo, env);
|
||||
float spacing = effectiveR * 1.5f;
|
||||
@ -383,10 +393,8 @@ namespace CounterDrone.Core.Algorithms
|
||||
}
|
||||
|
||||
private float ComputeInterceptProbability(DroneGroup threat,
|
||||
AmmunitionSpec? ammo, int rounds, CombatScene env)
|
||||
AmmunitionSpec ammo, int rounds, CombatScene env)
|
||||
{
|
||||
if (ammo == null) return 0f;
|
||||
|
||||
float avgSpeed = (float)threat.Target.TypicalSpeed / 3.6f;
|
||||
var (effectiveR, _) = ComputeEffectiveRadius(threat, ammo, env);
|
||||
float spacing = effectiveR * 1.5f;
|
||||
@ -404,10 +412,9 @@ namespace CounterDrone.Core.Algorithms
|
||||
// ═══════════════════════════════════════════════
|
||||
|
||||
private List<FireEvent> GenerateFireEventsAt(DroneGroup threat, FireUnit unit,
|
||||
AerosolType ammoType, AmmunitionSpec? ammo, CombatScene env, float targetOffset)
|
||||
AerosolType ammoType, AmmunitionSpec ammo, CombatScene env, float targetOffset)
|
||||
{
|
||||
var events = new List<FireEvent>();
|
||||
if (ammo == null) return events;
|
||||
|
||||
var mid = ThreatMidpoint(threat);
|
||||
var (effectiveR, expansionTime) = ComputeEffectiveRadius(threat, ammo, env);
|
||||
|
||||
@ -53,13 +53,13 @@ namespace CounterDrone.Core.Simulation
|
||||
private int _entityCounter;
|
||||
|
||||
public SimulationEngine(IScenarioService scenarioService, FrameDataStore frameStore,
|
||||
IDamageModel damageModel, IPathProvider paths, IDefensePlanner? planner = null)
|
||||
IDamageModel damageModel, IPathProvider paths, IDefensePlanner planner)
|
||||
{
|
||||
_scenarioService = scenarioService;
|
||||
_frameStore = frameStore;
|
||||
_damageModel = damageModel;
|
||||
_paths = paths;
|
||||
_planner = planner ?? new DefaultDefensePlanner(new List<AmmunitionSpec>());
|
||||
_planner = planner;
|
||||
}
|
||||
|
||||
public void SetFireSchedule(List<FireEvent> schedule)
|
||||
|
||||
@ -47,7 +47,7 @@ namespace CounterDrone.Unity
|
||||
new RoutePlanRepository(_db), new WaypointRepository(_db));
|
||||
|
||||
_frameStore = new FrameDataStore(_paths);
|
||||
_engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths);
|
||||
_engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths, new DefaultDefensePlanner(DefaultAmmunition.GetAll()));
|
||||
}
|
||||
|
||||
public void LoadAndStart(string taskId)
|
||||
|
||||
@ -13,9 +13,6 @@ namespace CounterDrone.Core.Tests
|
||||
|
||||
var damage = AlgorithmFactory.Create<IDamageModel>();
|
||||
Assert.IsType<DamageModelRouter>(damage);
|
||||
|
||||
var planner = AlgorithmFactory.Create<IDefensePlanner>();
|
||||
Assert.IsType<DefaultDefensePlanner>(planner);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
||||
@ -65,7 +65,7 @@ namespace CounterDrone.Core.Tests
|
||||
});
|
||||
|
||||
var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir));
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir), new DefaultDefensePlanner(DefaultAmmunition.GetAll()));
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = 4f;
|
||||
|
||||
@ -107,7 +107,7 @@ namespace CounterDrone.Core.Tests
|
||||
});
|
||||
|
||||
var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir));
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir), new DefaultDefensePlanner(DefaultAmmunition.GetAll()));
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = 4f;
|
||||
|
||||
@ -148,7 +148,7 @@ namespace CounterDrone.Core.Tests
|
||||
});
|
||||
|
||||
var engine = new SimulationEngine(_scenario, new FrameDataStore(new TestPathProvider(_testDir)),
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir));
|
||||
new DamageModelRouter(), new TestPathProvider(_testDir), new DefaultDefensePlanner(DefaultAmmunition.GetAll()));
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = 4f;
|
||||
|
||||
|
||||
@ -49,7 +49,7 @@ namespace CounterDrone.Core.Tests
|
||||
|
||||
private SimulationEngine RunSimulation(int maxTicks, float tickDt = 1f / 20f)
|
||||
{
|
||||
var engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths);
|
||||
var engine = new SimulationEngine(_scenario, _frameStore, new DamageModelRouter(), _paths, new DefaultDefensePlanner(_ammoCatalog));
|
||||
|
||||
engine.Initialize(_taskId);
|
||||
engine.TimeScale = 8f; // 8倍速加速
|
||||
|
||||
@ -36,7 +36,7 @@ namespace CounterDrone.Core.Tests
|
||||
new RoutePlanRepository(_mainDb), new WaypointRepository(_mainDb));
|
||||
|
||||
_engine = new SimulationEngine(_scenarioService, new FrameDataStore(paths),
|
||||
new DamageModelRouter(), paths);
|
||||
new DamageModelRouter(), paths, new DefaultDefensePlanner(DefaultAmmunition.GetAll()));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user