vRp.CD2g_test/utils/geometry/dp/distribution_pattern.go

128 lines
3.6 KiB
Go

package dp
import (
"github.com/kercylan98/minotaur/utils/geometry"
)
// NewDistributionPattern 构建一个分布图实例
func NewDistributionPattern[Item any](sameKindVerifyHandle func(itemA, itemB Item) bool) *DistributionPattern[Item] {
return &DistributionPattern[Item]{
links: map[int]map[int]Item{},
sameKindVerifyHandle: sameKindVerifyHandle,
}
}
// DistributionPattern 分布图
type DistributionPattern[Item any] struct {
matrix []Item
links map[int]map[int]Item
sameKindVerifyHandle func(itemA, itemB Item) bool
width int
usePos bool
}
// GetLinks 获取关联的成员
// - 其中包含传入的 pos 成员
func (slf *DistributionPattern[Item]) GetLinks(pos int) (result []Link[Item]) {
for pos, item := range slf.links[pos] {
result = append(result, Link[Item]{Pos: pos, Item: item})
}
return
}
// HasLink 检查一个位置是否包含除它本身外的其他关联成员
func (slf *DistributionPattern[Item]) HasLink(pos int) bool {
links, exist := slf.links[pos]
if !exist {
return false
}
return len(links) > 1
}
// LoadMatrix 通过二维矩阵加载分布图
// - 通过该函数加载的分布图使用的矩阵是复制后的矩阵,因此无法直接通过刷新(Refresh)来更新分布关系
// - 需要通过直接刷新的方式请使用 LoadMatrixWithPos
func (slf *DistributionPattern[Item]) LoadMatrix(matrix [][]Item) {
slf.LoadMatrixWithPos(geometry.CoordinateMatrixToPosMatrix(matrix))
slf.usePos = false
}
// LoadMatrixWithPos 通过二维矩阵加载分布图
func (slf *DistributionPattern[Item]) LoadMatrixWithPos(width int, matrix []Item) {
slf.width = width
slf.matrix = matrix
slf.usePos = true
for k := range slf.links {
delete(slf.links, k)
}
for pos, item := range slf.matrix {
slf.buildRelationships(pos, item)
}
}
// Refresh 刷新特定位置的分布关系
// - 由于 LoadMatrix 的矩阵是复制后的矩阵,所以任何外部的改动都不会影响到分布图的变化,在这种情况下,刷新将没有任何意义
// - 需要通过直接刷新的方式请使用 LoadMatrixWithPos 加载矩阵,或者通过 RefreshWithItem 函数进行刷新
func (slf *DistributionPattern[Item]) Refresh(pos int) {
if !slf.usePos {
return
}
links, exist := slf.links[pos]
if !exist {
slf.buildRelationships(pos, slf.matrix[pos])
return
}
var positions []int
for tp := range links {
positions = append(positions, tp)
delete(slf.links, tp)
}
for _, tp := range positions {
slf.buildRelationships(tp, slf.matrix[tp])
}
}
// RefreshWithItem 通过特定的成员刷新特定位置的分布关系
// - 如果矩阵通过 LoadMatrixWithPos 加载,将会重定向至 Refresh
func (slf *DistributionPattern[Item]) RefreshWithItem(pos int, item Item) {
if slf.usePos {
slf.Refresh(pos)
return
}
slf.matrix[pos] = item
links, exist := slf.links[pos]
if !exist {
slf.buildRelationships(pos, slf.matrix[pos])
return
}
var positions []int
for tp := range links {
positions = append(positions, tp)
delete(slf.links, tp)
}
for _, tp := range positions {
slf.buildRelationships(tp, slf.matrix[tp])
}
}
// 构建关系
func (slf *DistributionPattern[Item]) buildRelationships(pos int, item Item) {
links, exist := slf.links[pos]
if !exist {
links = map[int]Item{pos: item}
slf.links[pos] = links
}
for _, tp := range geometry.GetAdjacentTranslatePos(slf.matrix, slf.width, pos) {
target := slf.matrix[tp]
if _, exist := links[tp]; exist || !slf.sameKindVerifyHandle(item, target) {
continue
}
slf.links[tp] = links
links[tp] = target
slf.buildRelationships(tp, target)
}
}