202 lines
6.3 KiB
Go
202 lines
6.3 KiB
Go
|
|
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)
|
|||
|
|
}
|