package element import ( "fmt" "math" ) // 元素类型枚举(覆盖所有单属性,ID与原配置完全对齐) 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 // 次元 ElementTypeAncient ElementType = 18 // 远古 ElementTypeDemon ElementType = 19 // 邪灵 ElementTypeNature ElementType = 20 // 自然 ElementTypeKing ElementType = 221 // 王 ElementTypeChaos ElementType = 222 // 混沌 ElementTypeDeity ElementType = 223 // 神灵 ElementTypeSamsara ElementType = 224 // 轮回 ElementTypeInsect ElementType = 225 // 虫 ElementTypeVoid ElementType = 226 // 虚空 ) // 全局常量定义(统一管理合法范围) const ( maxMatrixSize = 227 // 矩阵维度(覆盖最大属性ID 226) ) // 合法单属性ID集合(快速校验) var validSingleElementIDs = map[int]bool{ 1: true, 2: true, 3: true, 4: true, 5: true, 6: true, 7: true, 8: true, 9: true, 10: true, 11: true, 12: true, 13: true, 14: true, 15: true, 16: true, 17: true, 18: true, 19: true, 20: true, 221: true, 222: true, 223: true, 224: true, 225: true, 226: true, } // 元素名称映射(全属性对应,便于日志输出) 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", ElementTypeAncient: "ANCIENT", ElementTypeDemon: "DEMON", ElementTypeNature: "NATURE", ElementTypeKing: "KING", ElementTypeChaos: "CHAOS", ElementTypeDeity: "DEITY", ElementTypeSamsara: "SAMSARA", ElementTypeInsect: "INSECT", ElementTypeVoid: "VOID", } // 双属性映射(key=双属性ID,value=组成的两个单属性ID) 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}, // 圣灵 暗影 57: {18, 11}, // 远古 战斗 58: {3, 14}, // 火 神秘 59: {12, 11}, // 光 战斗 60: {14, 11}, // 神秘 战斗 61: {17, 11}, // 次元 战斗 62: {19, 14}, // 邪灵 神秘 63: {18, 15}, // 远古 龙 64: {12, 17}, // 光 次元 65: {18, 16}, // 远古 圣灵 66: {2, 11}, // 水 战斗 67: {5, 15}, // 电 龙 68: {12, 3}, // 光 火 69: {12, 13}, // 光 暗影 70: {19, 15}, // 邪灵 龙 71: {18, 14}, // 远古 神秘 72: {6, 17}, // 机械 次元 73: {11, 15}, // 战斗 龙 74: {11, 20}, // 战斗 自然 75: {19, 6}, // 邪灵 机械 76: {5, 17}, // 电 次元 77: {18, 3}, // 远古 火 78: {16, 11}, // 圣灵 战斗 79: {16, 17}, // 圣灵 次元 80: {16, 5}, // 圣灵 电 81: {18, 7}, // 远古 地面 82: {18, 1}, // 远古 草 83: {20, 15}, // 自然 龙 84: {9, 14}, // 冰 神秘 85: {4, 13}, // 飞行 暗影 86: {9, 3}, // 冰 火 87: {9, 4}, // 冰 飞行 88: {20, 16}, // 自然 圣灵 89: {222, 16}, // 混沌 圣灵 90: {18, 19}, // 远古 邪灵 91: {20, 9}, // 自然 冰 92: {222, 13}, // 混沌 暗影 93: {222, 11}, // 混沌 战斗 94: {222, 10}, // 混沌 超能 95: {16, 10}, // 圣灵 超能 96: {222, 7}, // 混沌 地面 97: {13, 19}, // 暗影 邪灵 98: {222, 18}, // 混沌 远古 99: {222, 19}, // 混沌 邪灵 100: {16, 7}, // 圣灵 地面 101: {3, 13}, // 火 暗影 102: {12, 10}, // 光 超能 103: {6, 11}, // 机械 战斗 104: {4, 5}, // 飞行 电 105: {222, 4}, // 混沌 飞行 106: {222, 15}, // 混沌 龙 107: {222, 3}, // 混沌 火 108: {16, 3}, // 圣灵 火 109: {7, 14}, // 地面 神秘 110: {222, 17}, // 混沌 次元 111: {222, 9}, // 混沌 冰 112: {20, 14}, // 自然 神秘 113: {226, 19}, // 虚空 邪灵 114: {226, 222}, // 虚空 混沌 115: {16, 224}, // 圣灵 轮回 116: {2, 17}, // 水 次元 117: {16, 14}, // 圣灵 神秘 118: {6, 14}, // 机械 神秘 119: {2, 14}, // 水 神秘 120: {17, 15}, // 次元 龙 121: {20, 10}, // 自然 超能 122: {5, 6}, // 电 机械 123: {14, 224}, // 神秘 轮回 124: {2, 6}, // 水 机械 125: {3, 6}, // 火 机械 126: {1, 6}, // 草 机械 127: {18, 5}, // 远古 电 128: {16, 4}, // 圣灵 飞行 } // 元素组合结构体 type ElementCombination struct { Primary ElementType // 主属性(按ID升序排序) Secondary *ElementType // 副属性(双属性非空) ID int // 组合唯一ID } // 全局预加载资源(程序启动时init初始化,运行时直接使用) var ( // 元素组合池:key=组合ID,value=组合实例(预加载所有合法组合) elementCombinationPool = make(map[int]*ElementCombination, 150) // 128双+26单=154,预分配足够容量 // 单属性克制矩阵(预初始化所有特殊克制关系,默认1.0) matrix [maxMatrixSize][maxMatrixSize]float64 ) // init 预加载所有资源(程序启动时执行一次,无并发问题) func init() { // 1. 初始化单属性克制矩阵 initFullTableMatrix() // 2. 预加载所有单属性组合 for id := range validSingleElementIDs { combo := &ElementCombination{ Primary: ElementType(id), Secondary: nil, ID: id, } elementCombinationPool[id] = combo } // 3. 预加载所有双属性组合 for dualID, atts := range dualElementMap { primaryID, secondaryID := atts[0], atts[1] // 按ID升序排序,保证组合一致性 primary, secondary := ElementType(primaryID), ElementType(secondaryID) if primary > secondary { primary, secondary = secondary, primary } combo := &ElementCombination{ Primary: primary, Secondary: &secondary, ID: dualID, } elementCombinationPool[dualID] = combo } } // IsDual 判断是否为双属性 func (ec *ElementCombination) IsDual() bool { return ec.Secondary != nil } // Elements 获取所有属性列表 func (ec *ElementCombination) Elements() []ElementType { if ec.IsDual() { return []ElementType{ec.Primary, *ec.Secondary} } return []ElementType{ec.Primary} } // String 友好格式化输出 func (ec *ElementCombination) String() string { primaryName := elementNameMap[ec.Primary] if !ec.IsDual() { return fmt.Sprintf("(%s)", primaryName) } return fmt.Sprintf("(%s, %s)", primaryName, elementNameMap[*ec.Secondary]) } // ElementCalculator 无锁元素克制计算器(依赖预加载资源) type ElementCalculator struct { offensiveCache map[string]float64 // 攻击克制缓存(运行时填充,无并发写) } // NewElementCalculator 创建计算器实例(仅初始化缓存) func NewElementCalculator() *ElementCalculator { return &ElementCalculator{ offensiveCache: make(map[string]float64, 4096), // 预分配大容量缓存 } } // getMatrixValue 直接返回矩阵值(修复核心问题:不再将0转换为1) func (c *ElementCalculator) getMatrixValue(attacker, defender ElementType) float64 { return matrix[attacker][defender] // 矩阵默认已初始化1.0,特殊值直接返回 } // GetCombination 获取元素组合(直接从预加载池读取) func (c *ElementCalculator) GetCombination(id int) (*ElementCombination, error) { combo, exists := elementCombinationPool[id] if !exists { return nil, fmt.Errorf("invalid element combination ID: %d", id) } return combo, nil } // GetOffensiveMultiplier 计算攻击方→防御方的克制倍数(缓存优先) func (c *ElementCalculator) GetOffensiveMultiplier(attackerID, defenderID int) (float64, error) { // 1. 获取预加载的组合实例 attacker, err := c.GetCombination(attackerID) if err != nil { return 0, fmt.Errorf("attacker invalid: %w", err) } defender, err := c.GetCombination(defenderID) if err != nil { return 0, fmt.Errorf("defender invalid: %w", err) } // 2. 缓存键(全局唯一) cacheKey := fmt.Sprintf("a%d_d%d", attackerID, defenderID) if val, exists := c.offensiveCache[cacheKey]; exists { return val, nil } // 3. 核心计算+缓存 val := c.calculateMultiplier(attacker, defender) c.offensiveCache[cacheKey] = val return val, nil } // calculateMultiplier 核心克制计算逻辑 func (c *ElementCalculator) calculateMultiplier(attacker, defender *ElementCombination) float64 { // 场景1:单→单 if !attacker.IsDual() && !defender.IsDual() { return c.getMatrixValue(attacker.Primary, defender.Primary) } // 场景2:单→双 if !attacker.IsDual() { y1, y2 := defender.Primary, *defender.Secondary m1 := c.getMatrixValue(attacker.Primary, y1) m2 := c.getMatrixValue(attacker.Primary, y2) switch { case m1 == 2 && m2 == 2: return 4.0 case m1 == 0 || m2 == 0: return (m1 + m2) / 4.0 default: return (m1 + m2) / 2.0 } } // 场景3:双→单 if !defender.IsDual() { return c.calculateDualToSingle(attacker.Primary, *attacker.Secondary, defender.Primary) } // 场景4:双→双 x1, x2 := attacker.Primary, *attacker.Secondary y1, y2 := defender.Primary, *defender.Secondary coeffY1 := c.calculateDualToSingle(x1, x2, y1) coeffY2 := c.calculateDualToSingle(x1, x2, y2) return (coeffY1 + coeffY2) / 2.0 } // calculateDualToSingle 辅助函数:双→单计算 func (c *ElementCalculator) calculateDualToSingle(attacker1, attacker2, defender ElementType) float64 { k1 := c.getMatrixValue(attacker1, defender) k2 := c.getMatrixValue(attacker2, defender) switch { case k1 == 2 && k2 == 2: return 4.0 case k1 == 0 || k2 == 0: return (k1 + k2) / 4.0 default: return (k1 + k2) / 2.0 } } var Calculator = NewElementCalculator() // TestAllScenarios 全场景测试(验证预加载和计算逻辑) func TestAllScenarios() { // 测试1:单→单(草→水) m1, _ := Calculator.GetOffensiveMultiplier(1, 2) fmt.Println("草→水: %.2f(预期2.0)", m1) if math.Abs(m1-2.0) > 0.001 { fmt.Println("测试1失败:实际%.2f", m1) } // 测试2:特殊单→单(混沌→虚空) m2, _ := Calculator.GetOffensiveMultiplier(222, 226) fmt.Println("混沌→虚空: %.2f(预期0.0)", m2) if math.Abs(m2-0.0) > 0.001 { fmt.Println("测试2失败:实际%.2f", m2) } // 测试3:单→双(火→冰龙(43)) m3, _ := Calculator.GetOffensiveMultiplier(3, 43) fmt.Println("火→冰龙: %.2f(预期1.5)", m3) if math.Abs(m3-1.5) > 0.001 { fmt.Println("测试3失败:实际%.2f", m3) } // 测试4:双→特殊单(混沌暗影(92)→神灵(223)) m4, _ := Calculator.GetOffensiveMultiplier(92, 223) fmt.Println("混沌暗影→神灵: %.2f(预期1.25)", m4) if math.Abs(m4-1.25) > 0.001 { fmt.Println("测试4失败:实际%.2f", m4) } // 测试5:双→双(虚空邪灵(113)→混沌远古(98)) m5, _ := Calculator.GetOffensiveMultiplier(113, 98) fmt.Println("虚空邪灵→混沌远古: %.2f(预期0.875", m5) if math.Abs(m5-0.875) > 0.001 { fmt.Println("测试5失败:实际%.2f", m5) } // 测试6:缓存命中 m6, _ := Calculator.GetOffensiveMultiplier(113, 98) if math.Abs(m6-m5) > 0.001 { fmt.Println("测试6失败:缓存未命中") } // 测试7:含无效组合(电→地面) m7, _ := Calculator.GetOffensiveMultiplier(5, 7) fmt.Println("电→地面: %.2f(预期0.0)", m7) if math.Abs(m7-0.0) > 0.001 { fmt.Println("测试7失败:实际%.2f", m7) } // 测试8:双属性含无效(电战斗→地面) m8, _ := Calculator.GetOffensiveMultiplier(35, 7) fmt.Println("电战斗→地面: %.2f(预期0.25)", m8) if math.Abs(m8-0.25) > 0.001 { fmt.Println("测试8失败:实际%.2f", m8) } }