fix: Planner 从多单元凑弹药,不再被单个 TotalMunitions 卡死
每个威胁可从多个火力单元汇集弹药,直到满足需求或耗尽。 单元测试 24/24 通过。
This commit is contained in:
parent
2bb8ba2e1e
commit
8366bfcb93
@ -113,45 +113,64 @@ namespace CounterDrone.Core.Algorithms
|
||||
continue;
|
||||
}
|
||||
|
||||
// 选最早可拦截的
|
||||
var best = candidates
|
||||
.OrderBy(c => c.EarliestInterceptTime)
|
||||
.ThenByDescending(c => c.KillProbability)
|
||||
.First();
|
||||
// 计算总弹药需求
|
||||
var neededAmmo = MatchAmmo((PowerType)threat.Target.PowerType);
|
||||
var ammo = _ammoCatalog.FirstOrDefault(a => a.AerosolType == (int)neededAmmo);
|
||||
int totalRoundsNeeded = CalcRoundsNeeded(threat, ammo, env,
|
||||
candidates[0].Unit.Type == PlatformType.AirBased);
|
||||
|
||||
var ammo = _ammoCatalog.FirstOrDefault(a => a.AerosolType == (int)best.AmmoType);
|
||||
int roundsNeeded = CalcRoundsNeeded(threat, ammo, env, best.Unit.Type == PlatformType.AirBased);
|
||||
int actualRounds = Math.Min(roundsNeeded, remainingMunitions[best.Unit.Id]);
|
||||
// 从多个候选单元凑弹药,直到满足需求或耗尽
|
||||
int roundsCollected = 0;
|
||||
var assignedUnits = new List<(FireUnit unit, int rounds, List<FireEvent> events)>();
|
||||
|
||||
if (actualRounds <= 0) { plan.ThreatsUnengaged++; continue; }
|
||||
|
||||
var fireEvents = GenerateFireEvents(threat, best.Unit, best.AmmoType,
|
||||
actualRounds, ammo, env);
|
||||
|
||||
plan.Assignments.Add(new UnitAssignment
|
||||
foreach (var c in candidates.OrderBy(c => c.EarliestInterceptTime)
|
||||
.ThenByDescending(c => c.KillProbability))
|
||||
{
|
||||
FireUnitId = best.Unit.Id,
|
||||
DroneGroupId = threat.GroupId,
|
||||
AmmoType = best.AmmoType,
|
||||
RoundsFired = actualRounds,
|
||||
FirstFireTime = fireEvents.Count > 0 ? fireEvents[0].FireTime : 0,
|
||||
FireEvents = fireEvents,
|
||||
});
|
||||
if (roundsCollected >= totalRoundsNeeded) break;
|
||||
int remaining = remainingMunitions.GetValueOrDefault(c.Unit.Id, 0);
|
||||
if (remaining <= 0) continue;
|
||||
|
||||
int toTake = Math.Min(remaining, totalRoundsNeeded - roundsCollected);
|
||||
var fireEvents = GenerateFireEvents(threat, c.Unit, c.AmmoType, toTake, ammo, env);
|
||||
assignedUnits.Add((c.Unit, toTake, fireEvents));
|
||||
remainingMunitions[c.Unit.Id] -= toTake;
|
||||
roundsCollected += toTake;
|
||||
}
|
||||
|
||||
if (roundsCollected <= 0) { plan.ThreatsUnengaged++; continue; }
|
||||
|
||||
foreach (var (unit, rounds, fireEvents) in assignedUnits)
|
||||
{
|
||||
plan.Assignments.Add(new UnitAssignment
|
||||
{
|
||||
FireUnitId = unit.Id,
|
||||
DroneGroupId = threat.GroupId,
|
||||
AmmoType = neededAmmo,
|
||||
RoundsFired = rounds,
|
||||
FirstFireTime = fireEvents.Count > 0 ? fireEvents[0].FireTime : 0,
|
||||
FireEvents = fireEvents,
|
||||
});
|
||||
plan.MergedSchedule.AddRange(fireEvents);
|
||||
}
|
||||
|
||||
plan.MergedSchedule.AddRange(fireEvents);
|
||||
remainingMunitions[best.Unit.Id] -= actualRounds;
|
||||
plan.ThreatsEngaged++;
|
||||
}
|
||||
|
||||
plan.MergedSchedule.Sort((a, b) => a.FireTime.CompareTo(b.FireTime));
|
||||
plan.OverallProbability = plan.Assignments.Count > 0
|
||||
? (float)plan.Assignments.Average(a =>
|
||||
{
|
||||
var t = sortedThreats.First(th => th.GroupId == a.DroneGroupId);
|
||||
var a2 = _ammoCatalog.FirstOrDefault(s => s.AerosolType == (int)a.AmmoType);
|
||||
return ComputeInterceptProbability(t, a2, a.RoundsFired, env);
|
||||
})
|
||||
: 0f;
|
||||
|
||||
// 按威胁汇总概率
|
||||
var threatProbs = new List<float>();
|
||||
foreach (var threat in sortedThreats)
|
||||
{
|
||||
var a2 = _ammoCatalog.FirstOrDefault(s =>
|
||||
s.AerosolType == (int)MatchAmmo((PowerType)threat.Target.PowerType));
|
||||
int totalRounds = plan.Assignments
|
||||
.Where(a => a.DroneGroupId == threat.GroupId)
|
||||
.Sum(a => a.RoundsFired);
|
||||
if (totalRounds > 0)
|
||||
threatProbs.Add(ComputeInterceptProbability(threat, a2, totalRounds, env));
|
||||
}
|
||||
plan.OverallProbability = threatProbs.Count > 0 ? threatProbs.Average() : 0f;
|
||||
plan.Summary = plan.ThreatsEngaged > 0
|
||||
? $"分配 {plan.ThreatsEngaged} 个威胁,{plan.ThreatsUnengaged} 个无方案"
|
||||
: "无威胁被分配拦截方案";
|
||||
|
||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user