Files
notarius/internal/modules/dnd/extract/spells/canonicalize.go

93 lines
2.4 KiB
Go

package spells
import (
"sort"
"gitea.maximumdirect.net/eric/notarius/internal/modules/dnd/shared"
)
func canonicalizeResponse(response *extractionResponse, sourceID string) {
if response == nil {
return
}
for index := range response.SpellCasts {
canonicalizeSpellCast(&response.SpellCasts[index], sourceID)
}
sort.SliceStable(response.SpellCasts, func(i, j int) bool {
left, leftOK := earliestSourceUnit(response.SpellCasts[i])
right, rightOK := earliestSourceUnit(response.SpellCasts[j])
if leftOK != rightOK {
return leftOK
}
if !leftOK {
return false
}
return left < right
})
}
func canonicalizeSpellCast(spell *spellCastResponse, sourceID string) {
for index := range spell.SourceRefs {
spell.SourceRefs[index].SourceID = sourceID
spell.SourceRefs[index].StartUnitID = canonicalUnitRef(spell.SourceRefs[index].StartUnitID)
spell.SourceRefs[index].EndUnitID = canonicalUnitRef(spell.SourceRefs[index].EndUnitID)
}
sort.SliceStable(spell.SourceRefs, func(i, j int) bool {
left := spell.SourceRefs[i]
right := spell.SourceRefs[j]
if left.StartUnitID.Int() != right.StartUnitID.Int() {
return unitSortValue(left.StartUnitID) < unitSortValue(right.StartUnitID)
}
return unitSortValue(left.EndUnitID) < unitSortValue(right.EndUnitID)
})
spell.SourceRefs = dedupeSourceRefs(spell.SourceRefs)
}
func canonicalUnitRef(ref shared.UnitRef) shared.UnitRef {
value := ref.Int()
if value <= 0 {
return ref
}
return shared.UnitRefFromInt(value)
}
func dedupeSourceRefs(refs []shared.SourceRefResponse) []shared.SourceRefResponse {
if len(refs) < 2 {
return refs
}
out := refs[:0]
var previous shared.SourceRefResponse
for index, ref := range refs {
if index > 0 && sameSourceRef(previous, ref) {
continue
}
out = append(out, ref)
previous = ref
}
return out
}
func sameSourceRef(left shared.SourceRefResponse, right shared.SourceRefResponse) bool {
return left.SourceID == right.SourceID &&
left.StartUnitID.Int() == right.StartUnitID.Int() &&
left.EndUnitID.Int() == right.EndUnitID.Int()
}
func earliestSourceUnit(spell spellCastResponse) (int, bool) {
for _, ref := range spell.SourceRefs {
start := ref.StartUnitID.Int()
if start > 0 {
return start, true
}
}
return 0, false
}
func unitSortValue(ref shared.UnitRef) int {
value := ref.Int()
if value <= 0 {
return int(^uint(0) >> 1)
}
return value
}