feat(suitbuilder): CD-tier filter helpers + tests; gate inventory-go build on go test
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
593e99894f
commit
7155055072
3 changed files with 157 additions and 0 deletions
74
go-services/inventory-go/suit_cd.go
Normal file
74
go-services/inventory-go/suit_cd.go
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue