火力规则:组件匹配修改
This commit is contained in:
@@ -63,7 +63,12 @@
|
||||
- `blueMissileRangeDefault`:蓝方导弹范围缺失时采用的默认值。
|
||||
- `minBlueMissileCountForLinkage`:蓝方导弹数量达到该值才触发联动增强。
|
||||
|
||||
### 2.5 targetId 自动绑定参数(新增)
|
||||
### 2.5 全组件数量匹配参数(新增)
|
||||
- `enableComponentQuantityMatch`:是否启用全组件数量覆盖(非导弹组件)。
|
||||
- `componentDeviceNameMappingCsv`:组件名映射表(逗号分隔),格式 `蓝组件deviceName->红组件deviceName`;为空则默认 `deviceName` 直匹配。
|
||||
- `skipMissileComponentsByNameContains`:跳过覆盖关键词:蓝方组件 `deviceName` 包含该关键词则不覆盖;默认 `导弹`(用于保留导弹联动偏移)。
|
||||
|
||||
### 2.6 targetId 自动绑定参数(新增)
|
||||
- `enableTargetAutoBind`:是否自动给红方武器写入 `targetId`。
|
||||
- `minTargetBindRatio`:最低绑定比例(例如 `0.7` 表示至少 70% 红方武器有目标)。
|
||||
- `allowReserveWithoutTarget`:
|
||||
@@ -79,7 +84,7 @@
|
||||
- 导弹发射车优先绑定蓝方导弹能力目标
|
||||
- 当优先池不足时自动回退到地面池/全目标池,保证大部分武器有目标。
|
||||
|
||||
### 2.6 阵位规则参数(新增)
|
||||
### 2.7 阵位规则参数(新增)
|
||||
- `enablePositionRules`:阵位规则总开关。
|
||||
- 阵位输入来源:`blueTask.warZoneLocation` 与 `blueTask.defZoneLocation`(各 4 个经纬点)。
|
||||
- `fireUnitSpacingMeters`:防区/作战区点位间距(米),例如 `100` 代表约每 100 米一个火力单元。
|
||||
@@ -113,7 +118,7 @@
|
||||
}
|
||||
```
|
||||
|
||||
### 2.7 航迹规则参数(新增)
|
||||
### 2.8 航迹规则参数(新增)
|
||||
- `enableTrajectoryRules`:航迹规则总开关。
|
||||
- `strategyMode`:`auto/shortest/flank/interfere`。
|
||||
- `auto`:智能选择策略。
|
||||
@@ -141,6 +146,7 @@
|
||||
- `装备组件匹配`、`组件参数匹配`:已作为 `legacy` 占位,不承担当前业务决策。
|
||||
- 主决策在 `红方武器自适应装配规则`:调用 `configureRedWeaponsByBlue(...)`,按“映射配置”添加武器。
|
||||
- 导弹增强在 `导弹联动增强规则`:调用 `applyMissileLinkage(...)`,受开关和阈值控制。
|
||||
- 全组件数量匹配在 `全组件数量匹配规则`:按红方 `targetId` 绑定蓝方装备,覆盖非导弹组件 `componentParams[0].number`;找不到组件/targetId 允许跳过。
|
||||
- 任务命名在 `任务自动匹配规则`:调用 `assignTaskNameByRedWeapons(...)`,按红方最终武器自动生成任务名和 `dataType`。
|
||||
- 炮类约束:命中炮类条件时,炮类武器只保留 `炮弹` 组件,单位 `范围米`。
|
||||
- `targetId` 绑定:在装配后自动执行,尽量为红方武器绑定蓝方 `equipmentId`,允许少量空值冗余。
|
||||
|
||||
@@ -149,6 +149,14 @@ function Map buildBusinessConfig() {
|
||||
cfg.put("blueMissileRangeDefault", 220); // 蓝方导弹范围默认值
|
||||
cfg.put("minBlueMissileCountForLinkage", 1); // 联动触发门槛
|
||||
|
||||
// ---------- 全组件数量匹配(可改) ----------
|
||||
// 逻辑:按红方武器 targetId 找到对应蓝方装备(equipmentId),然后覆盖所有“非导弹组件”的数量
|
||||
cfg.put("enableComponentQuantityMatch", Boolean.TRUE);
|
||||
// 格式示例:蓝穿甲弹->红穿甲弹,蓝火控雷达->红火控雷达;为空则默认 deviceName 一致匹配
|
||||
cfg.put("componentDeviceNameMappingCsv", "");
|
||||
// 跳过覆盖:蓝方组件 deviceName 包含该关键词则不覆盖(默认用来保留导弹联动偏移)
|
||||
cfg.put("skipMissileComponentsByNameContains", "导弹");
|
||||
|
||||
// ---------- 任务自动命名模板(可改) ----------
|
||||
// 任务分类优先级:导弹突击 > 防空压制 > 反装甲打击 > 炮火压制 > 通用打击
|
||||
cfg.put("taskName_missile_strike", "导弹突击打击任务");
|
||||
@@ -218,6 +226,18 @@ then
|
||||
applyMissileLinkage($fact, cfg);
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// 全组件数量匹配:按 redWeapon.targetId 对应蓝方装备,覆盖“非导弹组件”的数量
|
||||
rule "全组件数量匹配规则"
|
||||
agenda-group "打击任务"
|
||||
salience 53
|
||||
when
|
||||
$fact : FactTask(blueTask.side == "蓝方", redTask.side == "红方")
|
||||
then
|
||||
Map cfg = buildBusinessConfig();
|
||||
applyAllComponentQuantities($fact, cfg);
|
||||
end
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
rule "任务自动匹配规则"
|
||||
agenda-group "打击任务"
|
||||
@@ -581,6 +601,159 @@ function void bindTargetIdsForRedWeapons(List redWeapons, List blueWeapons, Map
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// component 映射解析 + 全组件数量覆盖
|
||||
function Map parseDeviceNameMapping(String csv) {
|
||||
Map result = new java.util.HashMap();
|
||||
if (csv == null) {
|
||||
return result;
|
||||
}
|
||||
String text = csv.trim();
|
||||
if (text.equals("")) {
|
||||
return result;
|
||||
}
|
||||
String[] parts = text.split(",");
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
String one = parts[i];
|
||||
if (one == null) {
|
||||
continue;
|
||||
}
|
||||
String item = one.trim();
|
||||
if (item.equals("")) {
|
||||
continue;
|
||||
}
|
||||
int idx = item.indexOf("->");
|
||||
if (idx <= 0 || idx >= item.length() - 2) {
|
||||
continue;
|
||||
}
|
||||
String left = item.substring(0, idx).trim();
|
||||
String right = item.substring(idx + 2).trim();
|
||||
if (left.equals("") || right.equals("")) {
|
||||
continue;
|
||||
}
|
||||
result.put(left, right);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function void applyAllComponentQuantities(FactTask fact, Map cfg) {
|
||||
if (fact == null || fact.getBlueTask() == null || fact.getRedTask() == null) {
|
||||
return;
|
||||
}
|
||||
if (!readBooleanCfg(cfg, "enableComponentQuantityMatch", true)) {
|
||||
return;
|
||||
}
|
||||
Task blueTask = fact.getBlueTask();
|
||||
Task redTask = fact.getRedTask();
|
||||
List blueWeapons = blueTask.getTaskWeapons();
|
||||
List redWeapons = redTask.getTaskWeapons();
|
||||
if (blueWeapons == null || blueWeapons.isEmpty() || redWeapons == null || redWeapons.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
String mappingCsv = cfg == null ? null : (String) cfg.get("componentDeviceNameMappingCsv");
|
||||
Map deviceNameMapping = parseDeviceNameMapping(mappingCsv);
|
||||
|
||||
String skipKeyword = cfg == null ? null : (String) cfg.get("skipMissileComponentsByNameContains");
|
||||
if (skipKeyword != null) {
|
||||
skipKeyword = skipKeyword.trim();
|
||||
if (skipKeyword.equals("")) {
|
||||
skipKeyword = null;
|
||||
}
|
||||
}
|
||||
|
||||
// 遍历红方每个武器:用 targetId 找蓝方装备(equipmentId)
|
||||
for (Object objR : redWeapons) {
|
||||
Weapon redWeapon = (Weapon) objR;
|
||||
if (redWeapon == null) {
|
||||
continue;
|
||||
}
|
||||
String targetId = redWeapon.getTargetId();
|
||||
if (isBlank(targetId)) {
|
||||
// 允许不匹配:targetId 为空直接跳过
|
||||
continue;
|
||||
}
|
||||
|
||||
Weapon blueWeapon = null;
|
||||
for (Object objB : blueWeapons) {
|
||||
Weapon w = (Weapon) objB;
|
||||
if (w == null) {
|
||||
continue;
|
||||
}
|
||||
String eqId = w.getEquipmentId();
|
||||
if (eqId != null && eqId.equals(targetId)) {
|
||||
blueWeapon = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (blueWeapon == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List blueComps = blueWeapon.getComponents();
|
||||
List redComps = redWeapon.getComponents();
|
||||
if (blueComps == null || blueComps.isEmpty() || redComps == null || redComps.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 用蓝方组件驱动覆盖红方组件数量
|
||||
for (Object objBC : blueComps) {
|
||||
SubComponents blueComp = (SubComponents) objBC;
|
||||
if (blueComp == null) {
|
||||
continue;
|
||||
}
|
||||
String blueCompName = blueComp.getDeviceName();
|
||||
if (isBlank(blueCompName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 跳过导弹组件覆盖,避免覆盖导弹联动偏移逻辑
|
||||
if (skipKeyword != null && blueCompName.contains(skipKeyword)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String redCompName = (String) deviceNameMapping.get(blueCompName);
|
||||
if (redCompName == null || redCompName.trim().equals("")) {
|
||||
redCompName = blueCompName;
|
||||
}
|
||||
|
||||
SubComponents redComp = null;
|
||||
for (Object objRC : redComps) {
|
||||
SubComponents rc = (SubComponents) objRC;
|
||||
if (rc == null) {
|
||||
continue;
|
||||
}
|
||||
if (redCompName.equals(rc.getDeviceName())) {
|
||||
redComp = rc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (redComp == null) {
|
||||
// 允许不匹配:红方下没有该组件则跳过
|
||||
continue;
|
||||
}
|
||||
|
||||
List blueParams = blueComp.getComponentParams();
|
||||
List redParams = redComp.getComponentParams();
|
||||
if (blueParams == null || blueParams.isEmpty() || redParams == null || redParams.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ComponentParam blueFirst = (ComponentParam) blueParams.get(0);
|
||||
ComponentParam redFirst = (ComponentParam) redParams.get(0);
|
||||
if (blueFirst == null || redFirst == null) {
|
||||
continue;
|
||||
}
|
||||
if (blueFirst.getNumber() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 只覆盖数量(componentParams[0].number)
|
||||
redFirst.setNumber(blueFirst.getNumber());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function void prepareDeploymentPools(FactTask fact, Map cfg, Map runtime) {
|
||||
if (!readBooleanCfg(cfg, "enablePositionRules", true)) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user