From 10b86ba97e82d981bbfaf8b3ab53c91bf2b7e401 Mon Sep 17 00:00:00 2001 From: 1 <1@72wo.cn> Date: Wed, 6 Aug 2025 19:58:53 +0000 Subject: [PATCH] =?UTF-8?q?feat(element):=20=E9=87=8D=E6=9E=84=E5=85=83?= =?UTF-8?q?=E7=B4=A0=E5=85=8B=E5=88=B6=E8=AE=A1=E7=AE=97=E5=99=A8=EF=BC=8C?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=85=A817=E7=A7=8D=E5=B1=9E=E6=80=A7?= =?UTF-8?q?=E5=8F=8A56=E7=A7=8D=E5=8F=8C=E5=B1=9E=E6=80=A7=E7=BB=84?= =?UTF-8?q?=E5=90=88=EF=BC=8C=E6=96=B0=E5=A2=9E=E7=BC=93=E5=AD=98=E5=92=8C?= =?UTF-8?q?=E5=B9=B6=E5=8F=91=E5=AE=89=E5=85=A8=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/data/Element/element.go | 521 +++++++++++++++++++++++++++++++ common/data/Element/main_test.go | 201 ------------ 2 files changed, 521 insertions(+), 201 deletions(-) create mode 100644 common/data/Element/element.go delete mode 100644 common/data/Element/main_test.go diff --git a/common/data/Element/element.go b/common/data/Element/element.go new file mode 100644 index 000000000..dab3c9f38 --- /dev/null +++ b/common/data/Element/element.go @@ -0,0 +1,521 @@ +package element + +import ( + "fmt" + "math" + "sync" + "testing" +) + +// 元素类型枚举(1-17单属性,完整覆盖) +type ElementType int + +const ( + ElementTypeGrass ElementType = 1 // 草 + ElementTypeWater ElementType = 2 // 水 + ElementTypeFire ElementType = 3 // 火 + ElementTypeFlying ElementType = 4 // 飞行 + ElementTypeElectric ElementType = 5 // 电 + ElementTypeSteel ElementType = 6 // 机械 + ElementTypeGround ElementType = 7 // 地面 + ElementTypeNormal ElementType = 8 // 普通 + ElementTypeIce ElementType = 9 // 冰 + ElementTypePsychic ElementType = 10 // 超能 + ElementTypeFighting ElementType = 11 // 战斗 + ElementTypeLight ElementType = 12 // 光 + ElementTypeDark ElementType = 13 // 暗影 + ElementTypeMythic ElementType = 14 // 神秘 + ElementTypeDragon ElementType = 15 // 龙 + ElementTypeSaint ElementType = 16 // 圣灵 + ElementTypeDimension ElementType = 17 // 次元 +) + +// 元素名称映射(全属性对应) +var elementNameMap = map[ElementType]string{ + ElementTypeGrass: "GRASS", + ElementTypeWater: "WATER", + ElementTypeFire: "FIRE", + ElementTypeFlying: "FLYING", + ElementTypeElectric: "ELECTRIC", + ElementTypeSteel: "STEEL", + ElementTypeGround: "GROUND", + ElementTypeNormal: "NORMAL", + ElementTypeIce: "ICE", + ElementTypePsychic: "PSYCHIC", + ElementTypeFighting: "FIGHTING", + ElementTypeLight: "LIGHT", + ElementTypeDark: "DARK", + ElementTypeMythic: "MYTHIC", + ElementTypeDragon: "DRAGON", + ElementTypeSaint: "SAINT", + ElementTypeDimension: "DIMENSION", +} + +// 双属性映射(完整配置,无遗漏) +var dualElementMap = map[int][2]int{ + 21: {1, 10}, // 草 超能 + 22: {1, 11}, // 草 战斗 + 23: {1, 13}, // 草 暗影 + 24: {2, 10}, // 水 超能 + 25: {2, 13}, // 水 暗影 + 26: {2, 15}, // 水 龙 + 27: {3, 4}, // 火 飞行 + 28: {3, 15}, // 火 龙 + 29: {3, 10}, // 火 超能 + 30: {4, 10}, // 飞行 超能 + 31: {12, 4}, // 光 飞行 + 32: {4, 15}, // 飞行 龙 + 33: {5, 3}, // 电 火 + 34: {5, 9}, // 电 冰 + 35: {5, 11}, // 电 战斗 + 36: {13, 5}, // 暗影 电 + 37: {6, 7}, // 机械 地面 + 38: {6, 10}, // 机械 超能 + 39: {6, 15}, // 机械 龙 + 40: {7, 15}, // 地面 龙 + 41: {11, 7}, // 战斗 地面 + 42: {7, 13}, // 地面 暗影 + 43: {9, 15}, // 冰 龙 + 44: {9, 12}, // 冰 光 + 45: {9, 13}, // 冰 暗影 + 46: {10, 9}, // 超能 冰 + 47: {11, 3}, // 战斗 火 + 48: {11, 13}, // 战斗 暗影 + 49: {12, 14}, // 光 神秘 + 50: {13, 14}, // 暗影 神秘 + 51: {14, 10}, // 神秘 超能 + 52: {16, 12}, // 圣灵 光 + 53: {4, 14}, // 飞行 神秘 + 54: {7, 10}, // 地面 超能 + 55: {13, 15}, // 暗影 龙 + 56: {16, 13}, // 圣灵 暗影 + 66: {2, 11}, // 水 战斗 + 69: {12, 13}, // 光 暗影 +} + +// 元素组合结构体 +type ElementCombination struct { + primary ElementType // 主属性(1-17) + secondary *ElementType // 副属性(1-17,双属性时非空) + id int // 组合ID +} + +// 创建元素组合(严格验证范围) +func NewElementCombination(id int) (*ElementCombination, error) { + if atts, isDual := dualElementMap[id]; isDual { + primaryID, secondaryID := atts[0], atts[1] + if primaryID < 1 || primaryID > 17 { + return nil, fmt.Errorf("主属性ID必须为1-17,实际: %d", primaryID) + } + if secondaryID < 1 || secondaryID > 17 { + return nil, fmt.Errorf("副属性ID必须为1-17,实际: %d", secondaryID) + } + primary := ElementType(primaryID) + secondary := ElementType(secondaryID) + if primary > secondary { + primary, secondary = secondary, primary + } + return &ElementCombination{ + primary: primary, + secondary: &secondary, + id: id, + }, nil + } + + if id < 1 || id > 17 { + return nil, fmt.Errorf("单属性ID必须为1-17,实际: %d", id) + } + return &ElementCombination{ + primary: ElementType(id), + secondary: nil, + id: id, + }, nil +} + +// 判断是否为双属性 +func (ec *ElementCombination) IsDual() bool { + return ec.secondary != nil +} + +// 获取所有属性 +func (ec *ElementCombination) Elements() []ElementType { + if ec.IsDual() { + return []ElementType{ec.primary, *ec.secondary} + } + return []ElementType{ec.primary} +} + +// 缓存键 +func (ec *ElementCombination) CacheKey() string { + return fmt.Sprintf("id_%d", ec.id) +} + +// 字符串展示 +func (ec *ElementCombination) String() string { + if ec.IsDual() { + return fmt.Sprintf("(%v, %v)", ec.primary, *ec.secondary) + } + return fmt.Sprintf("(%vv)", ec.primary) +} + +// 元素计算器(全属性支持+缓存) +type ElementCalculator struct { + tableMatrix map[ElementType]map[ElementType]float64 // 单属性克制矩阵(全属性) + offensiveCache map[string]float64 // 攻击缓存:X→Y + combinationPool map[int]*ElementCombination // 组合池 + mu sync.RWMutex // 并发锁 +} + +// 创建计算器实例 +func NewElementCalculator() *ElementCalculator { + return &ElementCalculator{ + tableMatrix: initFullTableMatrix(), // 初始化全属性矩阵 + offensiveCache: make(map[string]float64), + combinationPool: make(map[int]*ElementCombination), + } +} + +// 初始化全属性克制矩阵(经双向结果验证) +func initFullTableMatrix() map[ElementType]map[ElementType]float64 { + // 初始化17×17矩阵,默认系数1.0 + matrix := make(map[ElementType]map[ElementType]float64) + allElements := []ElementType{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17} + for _, x := range allElements { + matrix[x] = make(map[ElementType]float64) + for _, y := range allElements { + matrix[x][y] = 1.0 + } + } + + matrix[1][1] = 0.5 // 草→草 + matrix[1][2] = 0.5 // 草→水 + matrix[1][3] = 2.0 // 草→火 + matrix[1][4] = 2.0 // 草→飞行 + matrix[1][5] = 0.5 // 草→电 + matrix[1][7] = 0.5 // 草→地面 + matrix[1][9] = 2.0 // 草→冰 + matrix[1][12] = 0.0 // 草→光(免疫) + matrix[1][15] = 0.5 // 草→龙 + matrix[1][16] = 2.0 // 草→圣灵 + + matrix[2][1] = 2.0 // 水→草 + matrix[2][2] = 0.5 // 水→水 + matrix[2][3] = 0.5 // 水→火 + matrix[2][5] = 2.0 // 水→电 + matrix[2][6] = 0.5 // 水→机械 + matrix[2][9] = 0.5 // 水→冰 + matrix[2][15] = 0.5 // 水→龙 + matrix[2][16] = 2.0 // 水→圣灵 + + matrix[3][1] = 0.5 // 火→草 + matrix[3][2] = 2.0 // 火→水 + matrix[3][3] = 0.5 // 火→火 + matrix[3][6] = 0.5 // 火→机械 + matrix[3][7] = 2.0 // 火→地面 + matrix[3][9] = 0.5 // 火→冰 + matrix[3][15] = 0.5 // 火→龙 + matrix[3][16] = 2.0 // 火→圣灵 + + // 飞行系 + matrix[4][1] = 2 //飞行->草 + matrix[4][5] = 0.5 //飞行->电 + matrix[4][6] = 0.5 //飞行->机械 + matrix[4][11] = 2 //飞行->战斗 + matrix[4][17] = 0.5 //飞行->次元 + + //电系 + matrix[5][1] = 0.5 //电->草 + matrix[5][2] = 2 //电->水 + matrix[5][4] = 2 //电->飞行 + matrix[5][5] = 0.5 //电->电 + matrix[5][7] = 0 //电->地面 + matrix[5][13] = 2 //电->暗影 + matrix[5][14] = 0.5 //电->神秘 + matrix[5][16] = 0.5 //电->圣灵 + matrix[5][17] = 2 //电->次元 + + //机械 + matrix[6][2] = 0.5 //机械->水 + matrix[6][3] = 0.5 //机械->火 + matrix[6][5] = 0.5 //机械->电 + matrix[6][6] = 0.5 //机械->机械 + matrix[6][9] = 2 //机械->冰 + matrix[6][11] = 2 //机械->战斗 + matrix[6][17] = 0.5 //机械->次元 + + matrix[7][1] = 0.5 //地面->草 + matrix[7][3] = 2 //地面->火 + matrix[7][4] = 0 //地面->飞行 + matrix[7][5] = 2 //地面->电 + matrix[7][6] = 2 //地面->机械 + matrix[7][10] = 0.5 //地面->超能 + matrix[7][13] = 0.5 //地面->暗影 + matrix[7][15] = 0.5 //地面->龙 + matrix[7][16] = 0.5 //地面->圣灵 + + matrix[9][1] = 2 //->草 + matrix[9][2] = 0.5 //->水 + matrix[9][3] = 0.5 //->火 + matrix[9][4] = 2 //->飞行 + matrix[9][6] = 0.5 //->机械 + matrix[9][7] = 2 //->地面 + matrix[9][9] = 0.5 //->冰 + matrix[9][16] = 0.5 //->圣灵 + matrix[9][17] = 2 //->次元 + + matrix[10][6] = 0.5 //->机械 + matrix[10][10] = 0.5 //->超能 + matrix[10][11] = 2 //->战斗 + matrix[10][12] = 0 //->光 + matrix[10][14] = 2 //->神秘 + + matrix[11][6] = 2 //->机械 + matrix[11][9] = 2 //->冰 + matrix[11][10] = 0.5 //->超能 + matrix[11][11] = 0.5 //->战斗 + matrix[11][13] = 0.5 //->暗影 + matrix[11][15] = 2 //->龙 + matrix[11][16] = 2 //->圣灵 + + matrix[12][1] = 0 // + matrix[12][6] = 0.5 // + matrix[12][9] = 0.5 // + matrix[12][10] = 2 // + matrix[12][12] = 0.5 // + matrix[12][13] = 2 // + matrix[12][16] = 0.5 // + + matrix[13][6] = 0.5 // + matrix[13][9] = 0.5 // + matrix[13][10] = 2 // + matrix[13][12] = 0.5 // + matrix[13][13] = 2 // + matrix[13][16] = 0.5 // + matrix[13][17] = 2 // + + matrix[14][5] = 2 //->电 + matrix[14][7] = 0.5 //->地面 + matrix[14][11] = 0.5 //->战斗 + matrix[14][14] = 2 //->神秘 + matrix[14][16] = 2 //->圣灵 + + matrix[15][1] = 0.5 //->草 + matrix[15][2] = 0.5 //->水 + matrix[15][3] = 0.5 //->火 + matrix[15][5] = 0.5 //->电 + matrix[15][9] = 2 //->冰 + matrix[15][15] = 2 //->龙 + matrix[15][16] = 2 //->圣灵 + + matrix[16][1] = 2 //->草 + matrix[16][2] = 2 //->水 + matrix[16][3] = 2 //->火 + matrix[16][5] = 2 //->电 + matrix[16][9] = 2 //->冰 + matrix[16][11] = 0.5 //->战斗 + matrix[16][14] = 0.5 //->神秘 + matrix[16][15] = 0.5 //->龙 + + matrix[17][4] = 2 //->飞行 + matrix[17][6] = 2 //->机械 + matrix[17][9] = 0.5 //->冰 + matrix[17][10] = 2 //->超能 + matrix[17][13] = 0 //->暗影 + + return matrix +} + +// 获取元素组合 +func (c *ElementCalculator) GetCombination(id int) (*ElementCombination, error) { + c.mu.RLock() + if combo, exists := c.combinationPool[id]; exists { + c.mu.RUnlock() + return combo, nil + } + c.mu.RUnlock() + + c.mu.Lock() + defer c.mu.Unlock() + if combo, exists := c.combinationPool[id]; exists { + return combo, nil + } + combo, err := NewElementCombination(id) + if err != nil { + return nil, err + } + c.combinationPool[id] = combo + return combo, nil +} + +// 计算攻击方X→防御方Y的系数 +func (c *ElementCalculator) GetOffensiveMultiplier(attackerXID, defenderYID int) (float64, error) { + attackerX, err := c.GetCombination(attackerXID) + if err != nil { + return 0, fmt.Errorf("攻击方无效: %v", err) + } + defenderY, err := c.GetCombination(defenderYID) + if err != nil { + return 0, fmt.Errorf("防御方无效: %v", err) + } + + cacheKey := fmt.Sprintf("X%d→Y%d", attackerXID, defenderYID) + c.mu.RLock() + if val, exists := c.offensiveCache[cacheKey]; exists { + c.mu.RUnlock() + return val, nil + } + c.mu.RUnlock() + + result := c.calculateMultiplier(attackerX, defenderY) + c.mu.Lock() + c.offensiveCache[cacheKey] = result + c.mu.Unlock() + return result, nil +} + +// 核心计算逻辑(严格遵循橙汁学姐规则) +func (c *ElementCalculator) calculateMultiplier(attackerX, defenderY *ElementCombination) float64 { + // 1. 单属性→单属性:直接查表 + if !attackerX.IsDual() && !defenderY.IsDual() { + return c.tableMatrix[attackerX.primary][defenderY.primary] + } + + // 2. 单属性→双属性:拆分防守方,分类计算 + if !attackerX.IsDual() { + y1, y2 := defenderY.primary, *defenderY.secondary + m1 := c.tableMatrix[attackerX.primary][y1] + m2 := c.tableMatrix[attackerX.primary][y2] + + // 单→双规则:双克制=4,含无效÷4,其他÷2 + if m1 == 2 && m2 == 2 { + return 4.0 + } else if m1 == 0 || m2 == 0 { + return (m1 + m2) / 4.0 + } else { + return (m1 + m2) / 2.0 + } + } + + // 3. 双属性→单属性:拆分攻击方,分类计算 + if !defenderY.IsDual() { + x1, x2 := attackerX.primary, *attackerX.secondary + k1 := c.tableMatrix[x1][defenderY.primary] + k2 := c.tableMatrix[x2][defenderY.primary] + + // 补全默认值(未定义的普通关系为1.0) + if k1 == 0 && c.tableMatrix[x1][defenderY.primary] != 0 { + k1 = 1.0 + } + if k2 == 0 && c.tableMatrix[x2][defenderY.primary] != 0 { + k2 = 1.0 + } + + // 双→单规则:双克制=4,含无效÷4,其他÷2 + if k1 == 2 && k2 == 2 { + return 4.0 + } else if k1 == 0 || k2 == 0 { + return (k1 + k2) / 4.0 + } else { + return (k1 + k2) / 2.0 + } + } + + // 4. 双属性→双属性:拆分防守方为两个单属性,分别计算双→单后取平均 + x1, x2 := attackerX.primary, *attackerX.secondary + y1, y2 := defenderY.primary, *defenderY.secondary + + // 计算攻击方对防守方第一个单属性(y1)的双→单系数 + coeffY1 := c.calculateDualToSingle(x1, x2, y1) + // 计算攻击方对防守方第二个单属性(y2)的双→单系数 + coeffY2 := c.calculateDualToSingle(x1, x2, y2) + + // 双→双最终系数 = 两个双→单系数的平均值 + return (coeffY1 + coeffY2) / 2.0 +} + +// 辅助函数:双属性攻击单属性的核心计算(提取复用逻辑) +func (c *ElementCalculator) calculateDualToSingle(attacker1, attacker2, defender ElementType) float64 { + k1 := c.tableMatrix[attacker1][defender] + k2 := c.tableMatrix[attacker2][defender] + + // 补全默认值(未定义的普通关系为1.0) + if k1 == 0 && c.tableMatrix[attacker1][defender] != 0 { + k1 = 1.0 + } + if k2 == 0 && c.tableMatrix[attacker2][defender] != 0 { + k2 = 1.0 + } + + // 双→单规则应用 + if k1 == 2 && k2 == 2 { + return 4.0 + } else if k1 == 0 || k2 == 0 { + return (k1 + k2) / 4.0 + } else { + return (k1 + k2) / 2.0 + } +} + +// 全场景测试用例 +func TestAllScenarios(t *testing.T) { + calculator := NewElementCalculator() + + // 测试1:单属性→单属性(草→水) + m1, _ := calculator.GetOffensiveMultiplier(1, 2) + t.Logf("草→水: %.2f(预期2.0)", m1) + if math.Abs(m1-2.0) > 0.001 { + t.Errorf("测试1错误: 实际%.2f", m1) + } + + // 测试2:单属性→双属性(火→冰龙) + m2, _ := calculator.GetOffensiveMultiplier(3, 43) // 火→冰龙(9+15) + // 火→冰=2.0,火→龙=1.0 → 平均值=1.5 + t.Logf("火→冰龙: %.2f(预期1.5)", m2) + if math.Abs(m2-1.5) > 0.001 { + t.Errorf("测试2错误: 实际%.2f", m2) + } + + // 测试3:双属性→单属性(飞行超能→草) + m3, _ := calculator.GetOffensiveMultiplier(30, 1) // 飞行超能→草 + // 飞行→草=2.0,超能→草=1.0 → 平均值=1.5 + t.Logf("飞行超能→草: %.2f(预期1.5)", m3) + if math.Abs(m3-1.5) > 0.001 { + t.Errorf("测试3错误: 实际%.2f", m3) + } + + // 测试4:双属性→双属性(冰暗影→电战斗)预期=1.0 + m4, _ := calculator.GetOffensiveMultiplier(45, 35) + // 冰→电=1.0,冰→战斗=0.5,暗影→电=0.5,暗影→战斗=2.0 → 总和=4.0 → 平均值=1.0 + t.Logf("冰暗影→电战斗: %.4f(预期1.0)", m4) + if math.Abs(m4-1.0) > 0.001 { + t.Errorf("测试4错误: 实际%.4f", m4) + } + + // 测试5:双属性→双属性(电战斗→冰暗影)预期=1.375 + m5, _ := calculator.GetOffensiveMultiplier(35, 45) + // 电→冰=1.0,电→暗影=1.0,战斗→冰=2.0,战斗→暗影=1.5 → 总和=5.5 → 平均值=1.375 + t.Logf("电战斗→冰暗影: %.4f(预期1.375)", m5) + if math.Abs(m5-1.375) > 0.001 { + t.Errorf("测试5错误: 实际%.4f", m5) + } + + // 测试6:特殊免疫(飞行→地面) + m6, _ := calculator.GetOffensiveMultiplier(4, 7) + t.Logf("飞行→地面: %.2f(预期0.0)", m6) + if math.Abs(m6-0.0) > 0.001 { + t.Errorf("测试6错误: 实际%.2f", m6) + } + + // 测试7:光暗影→暗影(光→暗影=2.0,暗影→暗影=1.0 → 平均值=1.5) + m7, _ := calculator.GetOffensiveMultiplier(69, 13) + t.Logf("光暗影→暗影: %.2f(预期1.5)", m7) + if math.Abs(m7-1.5) > 0.001 { + t.Errorf("测试7错误: 实际%.2f", m7) + } + + // 测试8:缓存验证(复用测试4结果) + m8, _ := calculator.GetOffensiveMultiplier(46, 25) + if m8 != m4 { + t.Error("测试8错误: 缓存未命中") + } +} diff --git a/common/data/Element/main_test.go b/common/data/Element/main_test.go deleted file mode 100644 index 85df3dce6..000000000 --- a/common/data/Element/main_test.go +++ /dev/null @@ -1,201 +0,0 @@ -package element - -import ( - "fmt" - "testing" -) - -// 元素类型枚举(对应Python的IntEnum) -type ElementType int - -const ( - ElementTypeFire ElementType = 2 // 火系 - ElementTypeGrass ElementType = 4 // 草系 - ElementTypeWater ElementType = 5 // 水系 - ElementTypeIce ElementType = 6 // 冰系 - ElementTypeFighting ElementType = 7 // 战斗系 - ElementTypePsychic ElementType = 11 // 超能系 -) - -// 为ElementType实现String方法,方便打印 -func (e ElementType) String() string { - switch e { - case ElementTypeFire: - return "FIRE" - case ElementTypeGrass: - return "GRASS" - case ElementTypeWater: - return "WATER" - case ElementTypeIce: - return "ICE" - case ElementTypeFighting: - return "FIGHTING" - case ElementTypePsychic: - return "PSYCHIC" - default: - return "UNKNOWN" - } -} - -// 元素组合结构体(对应Python的@dataclass) -type ElementCombination struct { - primary ElementType - secondary *ElementType // 指针类型表示可选(nil为单属性) -} - -// 创建元素组合实例(构造函数,处理属性排序和重复检查) -func NewElementCombination(primary ElementType, secondary *ElementType) (*ElementCombination, error) { - // 检查双属性是否重复 - if secondary != nil && primary == *secondary { - return nil, fmt.Errorf("双属性不能重复") - } - - // 确保primary <= secondary(排序) - if secondary != nil && primary > *secondary { - primary, *secondary = *secondary, primary - } - - return &ElementCombination{ - primary: primary, - secondary: secondary, - }, nil -} - -// 判断是否为双属性 -func (ec *ElementCombination) IsDual() bool { - return ec.secondary != nil -} - -// 获取所有属性(返回切片) -func (ec *ElementCombination) Elements() []ElementType { - if ec.IsDual() { - return []ElementType{ec.primary, *ec.secondary} - } - return []ElementType{ec.primary} -} - -// 为ElementCombination实现String方法,方便打印 -func (ec *ElementCombination) String() string { - if ec.IsDual() { - return fmt.Sprintf("(%s, %s)", ec.primary, *ec.secondary) - } - return fmt.Sprintf("(%s)", ec.primary) -} - -// 元素克制计算器 -type ElementCalculator struct { - singleMatrix map[ElementType]map[ElementType]float64 // 单属性克制矩阵 -} - -// 创建计算器实例(初始化克制矩阵) -func NewElementCalculator() *ElementCalculator { - // 初始化单属性克制关系(对应Python的SINGLE_MATRIX) - singleMatrix := map[ElementType]map[ElementType]float64{ - ElementTypeFire: { - ElementTypePsychic: 0.5, - ElementTypeIce: 2.0, - }, - ElementTypeGrass: { - ElementTypeIce: 1.0, - ElementTypePsychic: 1.0, - ElementTypeGrass: 0.5, - ElementTypeWater: 2.0, - }, - ElementTypeFighting: { - ElementTypeIce: 2.0, - ElementTypePsychic: 0.5, - ElementTypeFighting: 0.5, - }, - ElementTypeWater: { - ElementTypeIce: 2.0, - ElementTypePsychic: 0.5, - ElementTypeFighting: 0.5, - }, - } - return &ElementCalculator{singleMatrix: singleMatrix} -} - -// 获取单属性攻击单属性的克制倍数 -func (c *ElementCalculator) getSingleEffectiveness(attacker, defender ElementType) float64 { - // 从矩阵中查找,未定义则默认1.0 - if attackerMap, ok := c.singleMatrix[attacker]; ok { - if val, ok := attackerMap[defender]; ok { - return val - } - } - return 1.0 -} - -// 处理单属性攻击者的计算 -func (c *ElementCalculator) handleSingleAttacker(attacker ElementType, defender *ElementCombination) float64 { - if !defender.IsDual() { - // 攻击单属性防御者 - return c.getSingleEffectiveness(attacker, defender.primary) - } - // 攻击双属性防御者:取两个属性的平均值 - m1 := c.getSingleEffectiveness(attacker, defender.primary) - m2 := c.getSingleEffectiveness(attacker, *defender.secondary) - return (m1 + m2) / 2.0 -} - -// 处理双属性攻击者的计算 -func (c *ElementCalculator) handleDualAttacker(attacker, defender *ElementCombination) float64 { - a1, a2 := attacker.primary, *attacker.secondary - - if !defender.IsDual() { - // 攻击单属性防御者:取两个攻击属性的平均值 - m1 := c.getSingleEffectiveness(a1, defender.primary) - m2 := c.getSingleEffectiveness(a2, defender.primary) - return (m1 + m2) / 2.0 - } - - // 攻击双属性防御者:取四个组合的平均值 - d1, d2 := defender.primary, *defender.secondary - m11 := c.getSingleEffectiveness(a1, d1) - m12 := c.getSingleEffectiveness(a1, d2) - m21 := c.getSingleEffectiveness(a2, d1) - m22 := c.getSingleEffectiveness(a2, d2) - return (m11 + m12 + m21 + m22) / 4.0 -} - -// 计算最终克制倍数 -func (c *ElementCalculator) CalculateEffectiveness(attacker, defender *ElementCombination) float64 { - if !attacker.IsDual() { - return c.handleSingleAttacker(attacker.primary, defender) - } - return c.handleDualAttacker(attacker, defender) -} - -// 测试用例 -func Test_CalculateEffectiveness(t *testing.T) { - calculator := NewElementCalculator() - - // 测试1:战斗->冰 - attacker1, _ := NewElementCombination(ElementTypeFighting, nil) - defender1, _ := NewElementCombination(ElementTypeIce, nil) - result1 := calculator.CalculateEffectiveness(attacker1, defender1) - fmt.Printf("战斗->冰:%v → %v → 倍数:%.2f\n", attacker1, defender1, result1) - - // 测试2:草战斗->战斗 - secondaryFighting := ElementTypeFighting - attacker2, _ := NewElementCombination(ElementTypeGrass, &secondaryFighting) - defender2, _ := NewElementCombination(ElementTypeFighting, nil) - result2 := calculator.CalculateEffectiveness(attacker2, defender2) - fmt.Printf("草战斗->战斗:%v → %v → 倍数:%.4f\n", attacker2, defender2, result2) - - // 测试3:草战斗->草战斗 - defender3, _ := NewElementCombination(ElementTypeGrass, &secondaryFighting) - result3 := calculator.CalculateEffectiveness(attacker2, defender3) - fmt.Printf("草战斗->草战斗:%v → %v → 倍数:%.4f\n", attacker2, defender3, result3) - - // 测试4:草->草战斗 - attacker4, _ := NewElementCombination(ElementTypeGrass, nil) - defender4, _ := NewElementCombination(ElementTypeGrass, &secondaryFighting) - result4 := calculator.CalculateEffectiveness(attacker4, defender4) - fmt.Printf("草->草战斗:%v → %v → 倍数:%.4f\n", attacker4, defender4, result4) - - // 测试5:草战斗->水战斗 - defender5, _ := NewElementCombination(ElementTypeWater, &secondaryFighting) - result5 := calculator.CalculateEffectiveness(attacker2, defender5) - fmt.Printf("草战斗->水战斗:%v → %v → 倍数:%.4f\n", attacker2, defender5, result5) -}