本文目录导读:

这是一个非常经典的面向对象设计问题,也是很多游戏(如《火焰之纹章》《皇室战争》)的核心逻辑。
针对你问的“阵型克制关系有规律吗?”——有规律,但规律通常不是数学公式,而是“索引映射”或“循环链表”逻辑。
下面我提供一个综合 Java 案例,包含完整代码和三种常见的建模方式,并解释其规律。
核心规律总结(先看结论)
阵型克制的“规律”通常分三种:
- 三角循环(石头剪刀布):A克B,B克C,C克A。
- 规律:使用
(攻方.ordinal() + 1) % 3 == 守方.ordinal()
- 规律:使用
- 线性链(火影查克拉属性):火 → 风 → 雷 → 土 → 水 → 火。
- 规律:使用
Map存储直接后继关系,查表即可。
- 规律:使用
- 属性双克(宝可梦):数值加减,存在免疫和抵抗。
- 规律:使用二维数组矩阵
int[attacker][defender],值代表倍率(0.5,1,2,0)。
- 规律:使用二维数组矩阵
综合案例代码(包含枚举 + 工厂模式)
我们设计一个“光明与黑暗”主题的阵型系统。
阵型枚举:PHALANX(枪阵),CAVALRY(骑兵),ARCHER(弓兵)。
克制规律:骑兵克弓兵,弓兵克枪兵,枪兵克骑兵(三角循环)。
完整可运行代码
import java.util.HashMap;
import java.util.Map;
/**
* 综合案例:阵型克制系统
* 展示了三种建模方式(Map、二维数组、循环取模),并集成策略模式。
*/
public class FormationSystem {
// ---------- 1. 枚举定义(附带克制逻辑) ----------
enum Formation {
PHALANX("枪阵"), CAVALRY("骑兵"), ARCHER("弓兵");
private final String displayName;
Formation(String displayName) {
this.displayName = displayName;
}
// 方式一:循环取模规律 (防御方是否被当前攻击方克制)
public boolean counters(Formation defender) {
// 规律:攻方ordinal值 + 1 取模3 == 守方ordinal值
return (this.ordinal() + 1) % 3 == defender.ordinal();
}
public String getDisplayName() {
return displayName;
}
}
// ---------- 2. 核心业务类:BattleEngine ----------
static class BattleEngine {
private static final Map<String, Boolean> cache = new HashMap<>();
// 方式二:使用 Map 存储克制关系(显式,也最灵活)
private static final Map<Formation, Formation> counterMap = new HashMap<>();
static {
counterMap.put(Formation.PHALANX, Formation.CAVALRY); // 枪克骑
counterMap.put(Formation.CAVALRY, Formation.ARCHER); // 骑克弓
counterMap.put(Formation.ARCHER, Formation.PHALANX); // 弓克枪
}
// 方式三:经典二维数组矩阵 (倍率)
private static final double[][] MATRIX = {
// 攻击方 \ 防御方 PHALANX, CAVALRY, ARCHER
/* PHALANX */ {1.0, 1.5, 0.5},
/* CAVALRY */ {0.5, 1.0, 1.5},
/* ARCHER */ {1.5, 0.5, 1.0}
};
/**
* 使用Map判断是否克制(最直观,适合业务扩展)
*/
public static boolean isCounterByMap(Formation attacker, Formation defender) {
return counterMap.get(attacker) == defender;
}
/**
* 使用取模公式判断(最简洁,符合数学规律)
*/
public static boolean isCounterByMath(Formation attacker, Formation defender) {
return (attacker.ordinal() + 1) % 3 == defender.ordinal();
}
/**
* 使用矩阵计算伤害倍率(最强大,可以拓展至RPG)
*/
public static double getDamageMultiplier(Formation attacker, Formation defender) {
return MATRIX[attacker.ordinal()][defender.ordinal()];
}
}
// ---------- 3. 策略模式(让阵型自己决定战斗方式) ----------
interface BattleStrategy {
double execute(Formation attacker, Formation defender);
}
static class SimpleStrategy implements BattleStrategy {
@Override
public double execute(Formation attacker, Formation defender) {
if (attacker.counters(defender)) return 1.5; // 克制
if (defender.counters(attacker)) return 0.5; // 被克制
return 1.0;
}
}
static class AdvancedStrategy implements BattleStrategy {
@Override
public double execute(Formation attacker, Formation defender) {
return BattleEngine.getDamageMultiplier(attacker, defender);
}
}
// ---------- 4. 测试运行 ----------
public static void main(String[] args) {
System.out.println("=== 验证三角循环规律: 骑(1)克弓(2) 且 弓(2)克枪(0) 且 枪(0)克骑(1) ===");
BattleStrategy simple = new SimpleStrategy();
BattleStrategy advanced = new AdvancedStrategy();
// 测试全部组合
for (Formation attacker : Formation.values()) {
for (Formation defender : Formation.values()) {
double ratio = simple.execute(attacker, defender);
double matrixRatio = advanced.execute(attacker, defender);
// 打印战斗格
String effect = ratio > 1 ? "【克制】" : (ratio < 1 ? "【被克】" : "【均势】");
System.out.printf("%-8s vs %-8s -> 策略伤害: %.1f | 矩阵伤害: %.1f %s%n",
attacker.getDisplayName(), defender.getDisplayName(),
ratio, matrixRatio, effect);
}
}
// 验证数学规律与Map的结果一致性
System.out.println("\n=== 一致性校验(Math vs Map) ===");
boolean allMatch = true;
for (Formation a : Formation.values()) {
for (Formation d : Formation.values()) {
if (BattleEngine.isCounterByMap(a, d) != BattleEngine.isCounterByMath(a, d)) {
allMatch = false;
System.out.println("不一致: " + a + " vs " + d);
}
}
}
System.out.println("所有计算方式完全一致: " + allMatch);
}
}
代码运行结果分析
当你运行上述代码,控制台输出效果如下(节选):
=== 验证三角循环规律: 骑(1)克弓(2) 且 弓(2)克枪(0) 且 枪(0)克骑(1) === 枪阵 vs 枪阵 -> 策略伤害: 1.0 | 矩阵伤害: 1.0 【均势】 枪阵 vs 骑兵 -> 策略伤害: 1.5 | 矩阵伤害: 1.5 【克制】 枪阵 vs 弓兵 -> 策略伤害: 0.5 | 矩阵伤害: 0.5 【被克】 骑兵 vs 枪阵 -> 策略伤害: 0.5 | 矩阵伤害: 0.5 【被克】 骑兵 vs 骑兵 -> 策略伤害: 1.0 | 矩阵伤害: 1.0 【均势】 骑兵 vs 弓兵 -> 策略伤害: 1.5 | 矩阵伤害: 1.5 【克制】 弓兵 vs 枪阵 -> 策略伤害: 1.5 | 矩阵伤害: 1.5 【克制】 弓兵 vs 骑兵 -> 策略伤害: 0.5 | 矩阵伤害: 0.5 【被克】 弓兵 vs 弓兵 -> 策略伤害: 1.0 | 矩阵伤害: 1.0 【均势】
更复杂的规律:如何扩展到“双属性”或“五行”
如果你觉得三角循环太简单,可以借鉴 《阴阳师》/《宝可梦》 的规律,假设你有5种阵型(风、林、火、山、雷),克制关系是一个五边形循环。
规律仍然是:
(attacker.ordinal() + 1) % 5 == defender.ordinal()
如果你需要双向克制(例如火克风,但风也克火),规律会变成:
// 双向互克(胜负由数值决定)
int diff = Math.abs(attacker.ordinal() - defender.ordinal());
if (diff == 1 || diff == 4) { /* 互相克制 */ }
“阵型克制有规律吗?”
有,且主要规律是:
- 数学公式:
(attackIndex + shift) % totalTypes == defendIndex,适合循环克制。 - 表驱动(Map/Matrix):
- 查表法(
HashMap<Attack, Defense>)适合“唯一克星”; - 二维矩阵(
double[][])适合“数值倍率”和“免疫”;
- 查表法(
- 面向对象:把对抗逻辑封装在枚举的
counter()方法里,职责清晰。
推荐方案:在真实项目中,优先使用二维矩阵,因为你可以额外存储“技能特效”“属性抗性”等扩展字段,后续加新阵型时0改动(只需扩展数组长度),且性能最优(数组下标访问)。
如果你需要我进一步演示“五行互生互克”的全代码(带生克关系的复杂矩阵),可以告诉我,我给你再补一版。