- 新增 IDefensePlanner 接口 + DefaultDefensePlanner 实现 - FireUnit 重构为统一平台模型(Type/Position/CruiseSpeed/ReleaseAltitude/MuzzleVelocity) - DroneGroup 加入威胁指数(类型系数×速度系数)和优先级排序 - 五步流水线:威胁排序→弹药匹配→候选生成→贪心分配→时序生成 - 弹药精确匹配,不降级;临界方案基于50%概率阈值 - 删除 IDefenseAdvisor/DefaultDefenseAdvisor/RecommendMultiGroup - AlgorithmFactory 注册 IDefensePlanner - 测试更新:DefensePlannerTests 替代旧测试,FullPipelineTests 适配新 API - Unity Managers 更新调用 - 125 测试全通过
144 lines
4.9 KiB
C#
144 lines
4.9 KiB
C#
using System.Collections.Generic;
|
|
using CounterDrone.Core.Algorithms;
|
|
using CounterDrone.Core.Models;
|
|
using Xunit;
|
|
|
|
namespace CounterDrone.Core.Tests
|
|
{
|
|
public class DefensePlannerTests
|
|
{
|
|
private static readonly List<AmmunitionSpec> TestAmmo = DefaultAmmunition.GetAll();
|
|
|
|
private static List<FireUnit> MakeGroundUnits(int count = 5)
|
|
{
|
|
var units = new List<FireUnit>();
|
|
for (int i = 0; i < count; i++)
|
|
units.Add(new FireUnit
|
|
{
|
|
Id = $"u{i}",
|
|
Type = PlatformType.GroundBased,
|
|
Position = new Vector3(5000 + i * 50, 0, 50),
|
|
MuzzleVelocity = 800f,
|
|
TotalMunitions = 3,
|
|
AmmoTypes = new List<AerosolType> { AerosolType.InertGas, AerosolType.ActiveMaterial, AerosolType.ActiveFuel },
|
|
});
|
|
return units;
|
|
}
|
|
|
|
private DroneGroup MakeThreat(PowerType powerType = PowerType.Piston, float speed = 120f)
|
|
{
|
|
return new DroneGroup
|
|
{
|
|
GroupId = "default",
|
|
Target = new TargetConfig
|
|
{
|
|
TargetType = (int)TargetType.Piston,
|
|
PowerType = (int)powerType,
|
|
Quantity = 1,
|
|
TypicalSpeed = speed,
|
|
TypicalAltitude = 500,
|
|
},
|
|
Waypoints = new List<Waypoint>
|
|
{
|
|
new Waypoint { PosX = 0, PosY = 500, PosZ = 100, Altitude = 500, Speed = speed },
|
|
new Waypoint { PosX = 10000, PosY = 500, PosZ = 100, Altitude = 500, Speed = speed },
|
|
},
|
|
};
|
|
}
|
|
|
|
[Fact]
|
|
public void Piston_Engaged()
|
|
{
|
|
var result = new DefaultDefensePlanner(TestAmmo).Plan(
|
|
MakeGroundUnits(),
|
|
new List<DroneGroup> { MakeThreat(PowerType.Piston) },
|
|
new CombatScene { WindSpeed = 5 });
|
|
Assert.True(result.Best.ThreatsEngaged > 0);
|
|
Assert.Contains("分配", result.Best.Summary);
|
|
}
|
|
|
|
[Fact]
|
|
public void Jet_Engaged()
|
|
{
|
|
var result = new DefaultDefensePlanner(TestAmmo).Plan(
|
|
MakeGroundUnits(),
|
|
new List<DroneGroup> { MakeThreat(PowerType.Jet, 500) },
|
|
new CombatScene());
|
|
Assert.True(result.Best.ThreatsEngaged > 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void Electric_Engaged()
|
|
{
|
|
var result = new DefaultDefensePlanner(TestAmmo).Plan(
|
|
MakeGroundUnits(),
|
|
new List<DroneGroup> { MakeThreat(PowerType.Electric) },
|
|
new CombatScene());
|
|
Assert.True(result.Best.ThreatsEngaged > 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void Best_HigherThanCritical()
|
|
{
|
|
var result = new DefaultDefensePlanner(TestAmmo).Plan(
|
|
MakeGroundUnits(10),
|
|
new List<DroneGroup> { MakeThreat() },
|
|
new CombatScene());
|
|
Assert.True(result.Best.ThreatsEngaged > 0);
|
|
Assert.True(result.Critical.ThreatsEngaged > 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void Has_FireSchedule()
|
|
{
|
|
var result = new DefaultDefensePlanner(TestAmmo).Plan(
|
|
MakeGroundUnits(),
|
|
new List<DroneGroup> { MakeThreat() },
|
|
new CombatScene());
|
|
Assert.NotEmpty(result.Best.MergedSchedule);
|
|
}
|
|
|
|
[Fact]
|
|
public void Has_Assignments()
|
|
{
|
|
var result = new DefaultDefensePlanner(TestAmmo).Plan(
|
|
MakeGroundUnits(),
|
|
new List<DroneGroup> { MakeThreat() },
|
|
new CombatScene());
|
|
Assert.NotEmpty(result.Best.Assignments);
|
|
}
|
|
|
|
[Fact]
|
|
public void Critical_Within50Percent()
|
|
{
|
|
var result = new DefaultDefensePlanner(TestAmmo).Plan(
|
|
MakeGroundUnits(10),
|
|
new List<DroneGroup> { MakeThreat() },
|
|
new CombatScene());
|
|
// Critical 方案概率标记为 0.5(阈值下限)
|
|
Assert.True(result.Critical.OverallProbability >= 0.45f);
|
|
Assert.True(result.Critical.Assignments.Count > 0);
|
|
}
|
|
|
|
[Fact]
|
|
public void NoUnits_ThreatsUnengaged()
|
|
{
|
|
var result = new DefaultDefensePlanner(TestAmmo).Plan(
|
|
new List<FireUnit>(),
|
|
new List<DroneGroup> { MakeThreat() },
|
|
new CombatScene());
|
|
Assert.Equal(1, result.Best.ThreatsUnengaged);
|
|
}
|
|
|
|
[Fact]
|
|
public void NoThreats_EmptyPlan()
|
|
{
|
|
var result = new DefaultDefensePlanner(TestAmmo).Plan(
|
|
MakeGroundUnits(),
|
|
new List<DroneGroup>(),
|
|
new CombatScene());
|
|
Assert.Equal(0, result.Best.ThreatsEngaged);
|
|
}
|
|
}
|
|
}
|