OptaPlanner读取JSON护甲数据 求解重量属性最优护甲套装
基于OptaPlanner的艾尔登法环最优护甲配装求解
问题背景
《艾尔登法环》是现象级热门游戏,衍生出大量配装玩法研究。游戏内包含数百件护甲、武器与法术道具,基于玩家属性与道具属性筛选最优装备组合是极具实用价值的实际需求,也是学习使用约束求解器(Constraint Solvers)的绝佳落地场景。
实现目标
- 输入为JSON格式存储的游戏全量护甲数据集
- 求解覆盖头部、胸部、臂甲、腿部四个部位的完整护甲套装,实现最低重量下的最高强韧度(POISE)与物理防御(PHYSICAL_DEFENSE)
已有工作与初始问题
项目基于开源配装优化项目二次开发,初始阶段已完成的开发工作:
- 已整理全量护甲数据存入
armor.json文件 - 已创建与JSON结构匹配的
ArmorPiece数据类 - 已创建标注
@PlanningEntity的护甲组合实体类ArmorSet - 已编写标注
@PlanningSolution的ArmorSetComboPlanningSolution类(初始版本实现存在错误) - 尝试编写求解器
ArmorSetEasyOptimizer,但无法正常运行
修复方案与实现代码
核心调整点为改用@PlanningEntityProperty注解修正规划实体绑定逻辑,修正后的ArmorSetComboPlanningSolution实现代码如下:
@PlanningSolution public class ArmorSetComboPlanningSolution { public List<ArmorPiece> armorPieces; public Map<Integer, List<ArmorPiece>> armorByType; @ValueRangeProvider(id = "headRange") @ProblemFactCollectionProperty public List<ArmorPiece> headList; @ValueRangeProvider(id = "chestRange") @ProblemFactCollectionProperty public List<ArmorPiece> chestList; @ValueRangeProvider(id = "armsRange") @ProblemFactCollectionProperty public List<ArmorPiece> armsList; @ValueRangeProvider(id = "legsRange") @ProblemFactCollectionProperty public List<ArmorPiece> legsList; @PlanningEntityProperty public ArmorSet armorSet; @PlanningScore(bendableHardLevelsSize = 1, bendableSoftLevelsSize = 5) BendableLongScore score; ArmorSetComboPlanningSolution() { } ArmorSetComboPlanningSolution(List<ArmorPiece> armorPieces) { this.armorPieces = armorPieces; this.armorByType = armorPieces.stream().collect(groupingBy(ArmorPiece::armorCategoryID)); this.headList = armorByType.get(0); this.chestList = armorByType.get(1); this.armsList = armorByType.get(2); this.legsList = armorByType.get(3); // 初始化起始配装值 this.armorSet = new ArmorSet(0L, this.headList.get(0), this.chestList.get(0), this.armsList.get(0), this.legsList.get(0)); } }
随后实现对应评分计算器,设定硬约束为强韧度不低于61、总重量不超过60.64,软约束按优先级依次优化强韧重量比、物理防御值、物防重量比、魔法防御值、魔防重量比,评分器实现代码如下:
public class ArmorSetEasyOptimizer implements EasyScoreCalculator<ArmorSetComboPlanningSolution, BendableLongScore> { private final int TARGE_POISE = 61; private final double MAX_WEIGHT = 60.64; public ArmorSetEasyOptimizer() { } @Override public BendableLongScore calculateScore(ArmorSetComboPlanningSolution solution) { long hardScore = 0L; ArmorSet armorSet = solution.armorSet; if (armorSet.getTotalPoise() < TARGE_POISE) { hardScore--; } if (armorSet.getTotalWeight() > MAX_WEIGHT) { hardScore--; } long poiseRatio = (long) (armorSet.getTotalPoise() / (double) armorSet.getTotalWeight() * 100); long physicalDefenseScaled = (long) (armorSet.getTotalPhysicalDefense() * 100); long physicalDefenseToWeightRatio = (long) (physicalDefenseScaled / armorSet.getTotalWeight()); long magicDefenseScaled = (long) (armorSet.getTotalMagicDefense() * 100); long magicDefenseToWeightRatio = (long) (magicDefenseScaled / armorSet.getTotalWeight()); return BendableLongScore.of( new long[]{ hardScore }, new long[]{ poiseRatio, physicalDefenseScaled, physicalDefenseToWeightRatio, magicDefenseScaled, magicDefenseToWeightRatio } ); } }
运行结果
求解器运行10秒后得到最优解,运行日志与结果如下:
19:02:12.707 [main] INFO org.optaplanner.core.impl.localsearch.DefaultLocalSearchPhase - Local Search phase (1) ended: time spent (10000), best score ([0]hard/[179/3540/97/2750/75]soft), score calculation speed (987500/sec), step total (4046). 19:02:12.709 [main] INFO org.optaplanner.core.impl.solver.DefaultSolver - Solving ended: time spent (10000), best score ([0]hard/[179/3540/97/2750/75]soft), score calculation speed (985624/sec), phase total (2), environment mode (REPRODUCIBLE), move thread count (NONE). [0]hard/[179/3540/97/2750/75]soft ArmorSet (Weight: 36.3, Poise: 65, Physical: 35.4, Phys/Weight: 0.97, Magic: 27.5, Magic/Weight: 0.75 ) [ head: Radahn Soldier Helm (Weight: 4.0, Poise: 5), chest: Veteran's Armor (Weight: 18.9, Poise: 37), arms: Godskin Noble Bracelets (Weight: 1.7, Poise: 1), legs: Veteran's Greaves (Weight: 11.7, Poise: 22) ]
- 最优配装总重量36.3,强韧度65,物理防御35.4,物防重量比0.97,魔法防御27.5,魔防重量比0.75
- 具体部件为拉塔恩士兵头盔、老兵铠甲、神皮贵族臂环、老兵腿甲
内容的提问来源于stack exchange,提问作者Gavin Ray
相关产品推荐
相关产品推荐

