417 lines
13 KiB
Go
417 lines
13 KiB
Go
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集合(按ID直接索引,避免运行时 map 查找)
|
||
var validSingleElementIDs = [maxMatrixSize]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,
|
||
}
|
||
|
||
// 元素名称映射(按ID直接索引,便于日志输出)
|
||
var elementNameMap = [maxMatrixSize]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
|
||
}
|
||
|
||
// 全局预加载资源(程序启动时初始化,运行时只读)
|
||
var (
|
||
validCombinationIDs [maxMatrixSize]bool
|
||
elementCombinationPool [maxMatrixSize]ElementCombination
|
||
dualElementSecondaryPool [maxMatrixSize]ElementType
|
||
matrix [maxMatrixSize][maxMatrixSize]float64
|
||
Calculator *ElementCalculator
|
||
)
|
||
|
||
// init 预加载所有资源(程序启动时执行一次,无并发问题)
|
||
func init() {
|
||
initFullTableMatrix()
|
||
initElementCombinationPool()
|
||
Calculator = NewElementCalculator()
|
||
}
|
||
|
||
func initElementCombinationPool() {
|
||
for id, valid := range validSingleElementIDs {
|
||
if !valid {
|
||
continue
|
||
}
|
||
validCombinationIDs[id] = true
|
||
elementCombinationPool[id] = ElementCombination{
|
||
Primary: ElementType(id),
|
||
ID: id,
|
||
}
|
||
}
|
||
|
||
for dualID, atts := range dualElementMap {
|
||
primaryID, secondaryID := atts[0], atts[1]
|
||
primary, secondary := ElementType(primaryID), ElementType(secondaryID)
|
||
if primary > secondary {
|
||
primary, secondary = secondary, primary
|
||
}
|
||
|
||
dualElementSecondaryPool[dualID] = secondary
|
||
validCombinationIDs[dualID] = true
|
||
elementCombinationPool[dualID] = ElementCombination{
|
||
Primary: primary,
|
||
Secondary: &dualElementSecondaryPool[dualID],
|
||
ID: dualID,
|
||
}
|
||
}
|
||
}
|
||
|
||
func isValidCombinationID(id int) bool {
|
||
return id > 0 && id < maxMatrixSize && validCombinationIDs[id]
|
||
}
|
||
|
||
// IsDual 判断是否为双属性
|
||
func (ec *ElementCombination) IsDual() bool {
|
||
return ec.Secondary != nil
|
||
}
|
||
|
||
// Elements 获取所有属性列表
|
||
func (ec *ElementCombination) Elements() []ElementType {
|
||
if secondary := ec.Secondary; secondary != nil {
|
||
return []ElementType{ec.Primary, *secondary}
|
||
}
|
||
return []ElementType{ec.Primary}
|
||
}
|
||
|
||
// String 友好格式化输出
|
||
func (ec *ElementCombination) String() string {
|
||
if secondary := ec.Secondary; secondary != nil {
|
||
return fmt.Sprintf("(%s, %s)", elementNameMap[ec.Primary], elementNameMap[*secondary])
|
||
}
|
||
return fmt.Sprintf("(%s)", elementNameMap[ec.Primary])
|
||
}
|
||
|
||
// ElementCalculator 无锁元素克制计算器(所有倍数在初始化阶段预计算)
|
||
type ElementCalculator struct {
|
||
offensiveTable [maxMatrixSize][maxMatrixSize]float64
|
||
}
|
||
|
||
// NewElementCalculator 创建计算器实例(构建只读查表缓存)
|
||
func NewElementCalculator() *ElementCalculator {
|
||
c := &ElementCalculator{}
|
||
c.initOffensiveTable()
|
||
return c
|
||
}
|
||
|
||
func (c *ElementCalculator) initOffensiveTable() {
|
||
for attackerID, valid := range validCombinationIDs {
|
||
if !valid {
|
||
continue
|
||
}
|
||
attacker := &elementCombinationPool[attackerID]
|
||
for defenderID, valid := range validCombinationIDs {
|
||
if !valid {
|
||
continue
|
||
}
|
||
defender := &elementCombinationPool[defenderID]
|
||
c.offensiveTable[attackerID][defenderID] = c.calculateMultiplier(attacker, defender)
|
||
}
|
||
}
|
||
}
|
||
|
||
// getMatrixValue 直接返回矩阵值(修复核心问题:不再将0转换为1)
|
||
func (c *ElementCalculator) getMatrixValue(attacker, defender ElementType) float64 {
|
||
return matrix[attacker][defender]
|
||
}
|
||
|
||
// GetCombination 获取元素组合(直接按ID索引)
|
||
func (c *ElementCalculator) GetCombination(id int) (*ElementCombination, error) {
|
||
if !isValidCombinationID(id) {
|
||
return nil, fmt.Errorf("invalid element combination ID: %d", id)
|
||
}
|
||
return &elementCombinationPool[id], nil
|
||
}
|
||
|
||
// GetOffensiveMultiplier 计算攻击方→防御方的克制倍数(只读查表)
|
||
func (c *ElementCalculator) GetOffensiveMultiplier(attackerID, defenderID int) (float64, error) {
|
||
if !isValidCombinationID(attackerID) {
|
||
return 0, fmt.Errorf("attacker invalid: invalid element combination ID: %d", attackerID)
|
||
}
|
||
if !isValidCombinationID(defenderID) {
|
||
return 0, fmt.Errorf("defender invalid: invalid element combination ID: %d", defenderID)
|
||
}
|
||
return c.offensiveTable[attackerID][defenderID], nil
|
||
}
|
||
|
||
// calculateMultiplier 核心克制计算逻辑
|
||
func (c *ElementCalculator) calculateMultiplier(attacker, defender *ElementCombination) float64 {
|
||
if !attacker.IsDual() && !defender.IsDual() {
|
||
return c.getMatrixValue(attacker.Primary, defender.Primary)
|
||
}
|
||
|
||
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
|
||
}
|
||
}
|
||
|
||
if !defender.IsDual() {
|
||
return c.calculateDualToSingle(attacker.Primary, *attacker.Secondary, defender.Primary)
|
||
}
|
||
|
||
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
|
||
}
|
||
}
|
||
|
||
// TestAllScenarios 全场景测试(验证预加载和计算逻辑)
|
||
func TestAllScenarios() {
|
||
m1, _ := Calculator.GetOffensiveMultiplier(1, 2)
|
||
fmt.Println("草→水: %.2f(预期2.0)", m1)
|
||
if math.Abs(m1-2.0) > 0.001 {
|
||
fmt.Println("测试1失败:实际%.2f", m1)
|
||
}
|
||
|
||
m2, _ := Calculator.GetOffensiveMultiplier(222, 226)
|
||
fmt.Println("混沌→虚空: %.2f(预期0.0)", m2)
|
||
if math.Abs(m2-0.0) > 0.001 {
|
||
fmt.Println("测试2失败:实际%.2f", m2)
|
||
}
|
||
|
||
m3, _ := Calculator.GetOffensiveMultiplier(3, 43)
|
||
fmt.Println("火→冰龙: %.2f(预期1.5)", m3)
|
||
if math.Abs(m3-1.5) > 0.001 {
|
||
fmt.Println("测试3失败:实际%.2f", m3)
|
||
}
|
||
|
||
m4, _ := Calculator.GetOffensiveMultiplier(92, 223)
|
||
fmt.Println("混沌暗影→神灵: %.2f(预期1.25)", m4)
|
||
if math.Abs(m4-1.25) > 0.001 {
|
||
fmt.Println("测试4失败:实际%.2f", m4)
|
||
}
|
||
|
||
m5, _ := Calculator.GetOffensiveMultiplier(113, 98)
|
||
fmt.Println("虚空邪灵→混沌远古: %.2f(预期0.875", m5)
|
||
if math.Abs(m5-0.875) > 0.001 {
|
||
fmt.Println("测试5失败:实际%.2f", m5)
|
||
}
|
||
|
||
m6, _ := Calculator.GetOffensiveMultiplier(113, 98)
|
||
if math.Abs(m6-m5) > 0.001 {
|
||
fmt.Println("测试6失败:缓存未命中")
|
||
}
|
||
|
||
m7, _ := Calculator.GetOffensiveMultiplier(5, 7)
|
||
fmt.Println("电→地面: %.2f(预期0.0)", m7)
|
||
if math.Abs(m7-0.0) > 0.001 {
|
||
fmt.Println("测试7失败:实际%.2f", m7)
|
||
}
|
||
|
||
m8, _ := Calculator.GetOffensiveMultiplier(35, 7)
|
||
fmt.Println("电战斗→地面: %.2f(预期0.25)", m8)
|
||
if math.Abs(m8-0.25) > 0.001 {
|
||
fmt.Println("测试8失败:实际%.2f", m8)
|
||
}
|
||
}
|