MosswartOverlord/go-services/inventory-go/suit_cd.go
Erik 7155055072 feat(suitbuilder): CD-tier filter helpers + tests; gate inventory-go build on go test
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25 20:35:20 +02:00

74 lines
2.2 KiB
Go

package main
import "strings"
// CD-tier filtering for the suitbuilder. The allowed_crit_damage constraint
// restricts which crit-damage tiers are permitted on ARMOR pieces; jewelry and
// clothing are never affected. "Prefer the highest allowed tier" is NOT done
// here — it falls out of the existing scoring (CritDamage2 > CritDamage1) and
// the CD-descending armor sort once disallowed tiers are removed.
// critTier normalizes a raw crit_damage_rating into a tier in {0,1,2}. Rare
// high-crit gear (rating >= 2, including 3+) collapses to tier 2 so it counts
// as "CD2" rather than being silently excluded.
func critTier(rating int) int {
switch {
case rating <= 0:
return 0
case rating == 1:
return 1
default:
return 2
}
}
// isArmorSlot reports whether a slot name denotes an armor coverage slot,
// including comma-joined multi-coverage slots like "Chest, Abdomen".
func isArmorSlot(slot string) bool {
if armorSlotSet[slot] {
return true
}
if strings.Contains(slot, ", ") {
for _, p := range strings.Split(slot, ", ") {
if armorSlotSet[strings.TrimSpace(p)] {
return true
}
}
}
return false
}
// allowedCritSet normalizes the constraint's allowed crit-damage tiers into a
// set, or returns nil when the filter is INACTIVE: no values, or all three
// tiers {0,1,2} present (== default). A nil result means "no filter" and keeps
// the default search path byte-identical to the unfiltered solver.
func allowedCritSet(vals []int) map[int]bool {
if len(vals) == 0 {
return nil
}
set := map[int]bool{}
for _, v := range vals {
set[critTier(v)] = true
}
if set[0] && set[1] && set[2] {
return nil
}
return set
}
// filterArmorByCD drops armor items whose crit-damage tier is not in allowed.
// Non-armor items (jewelry, clothing, unknown) always pass through. When
// allowed is nil the input is returned unchanged.
func filterArmorByCD(items []*SuitItem, allowed map[int]bool) []*SuitItem {
if allowed == nil {
return items
}
out := make([]*SuitItem, 0, len(items))
for _, it := range items {
if isArmorSlot(it.Slot) && !allowed[critTier(it.Ratings["crit_damage_rating"])] {
continue
}
out = append(out, it)
}
return out
}