vRp.CD2g_test/utils/times/line.go

261 lines
7.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package times
import (
"fmt"
"github.com/kercylan98/minotaur/utils/collection"
"github.com/kercylan98/minotaur/utils/generic"
"strings"
"time"
)
// NewStateLine 创建一个从左向右由早到晚的状态时间线
func NewStateLine[State generic.Basic](zero State) *StateLine[State] {
return &StateLine[State]{
states: []State{zero},
points: []time.Time{{}},
trigger: [][]func(){{}},
}
}
// StateLine 状态时间线
type StateLine[State generic.Basic] struct {
states []State // 每个时间点对应的状态
points []time.Time // 每个时间点
trigger [][]func() // 每个时间点对应的触发器
}
// Check 根据状态顺序检查时间线是否合法
// - missingAllowed: 是否允许状态缺失,如果为 true则状态可以不连续如果为 false则状态必须连续
//
// 状态不连续表示时间线中存在状态缺失,例如:
// - 状态为 [1, 2, 3, 4, 5] 的时间线,如果 missingAllowed 为 true则状态为 [1, 3, 5] 也是合法的
// - 状态为 [1, 2, 3, 4, 5] 的时间线,如果 missingAllowed 为 false则状态为 [1, 3, 5] 是不合法的
func (slf *StateLine[State]) Check(missingAllowed bool, states ...State) bool {
var indexStored int
var indexInput int
for indexStored < len(slf.states) && indexInput < len(states) {
if slf.states[indexStored] == states[indexInput] {
indexStored++
indexInput++
} else if missingAllowed {
indexInput++
} else {
return false
}
}
//如果存储序列还有剩余, 而输入序列已经遍历完
if indexStored != len(slf.states) && indexInput == len(states) {
return false
}
// 如果输入序列还有剩余, 而存储序列已经遍历完
if indexStored == len(slf.states) && indexInput != len(states) && !missingAllowed {
return false
}
return true
}
// GetMissingStates 获取缺失的状态
func (slf *StateLine[State]) GetMissingStates(states ...State) []State {
var missing = make([]State, 0, len(states))
for _, state := range states {
if !collection.InComparableSlice(slf.states, state) {
missing = append(missing, state)
}
}
return missing
}
// HasState 检查时间线中是否包含指定状态
func (slf *StateLine[State]) HasState(state State) bool {
return collection.InComparableSlice(slf.states, state)
}
// String 获取时间线的字符串表示
func (slf *StateLine[State]) String() string {
var parts []string
for i := 0; i < len(slf.states); i++ {
parts = append(parts, fmt.Sprintf("[%v] %v", slf.states[i], slf.points[i]))
}
return strings.Join(parts, " > ")
}
// AddState 添加一个状态到时间线中,状态不能与任一时间点重合,否则将被忽略
// - onTrigger: 该状态绑定的触发器,该触发器不会被主动执行,需要主动获取触发器执行
func (slf *StateLine[State]) AddState(state State, t time.Time, onTrigger ...func()) *StateLine[State] {
if collection.InComparableSlice(slf.states, state) {
return slf
}
// 将 t 按照从左到右由早到晚的顺序插入到 points 中
for i := 0; i < len(slf.points); i++ {
if slf.points[i].After(t) {
slf.points = append(slf.points[:i], append([]time.Time{t}, slf.points[i:]...)...)
slf.states = append(slf.states[:i], append([]State{state}, slf.states[i:]...)...)
slf.trigger = append(slf.trigger[:i], append([][]func(){onTrigger}, slf.trigger[i:]...)...)
return slf
}
}
slf.points = append(slf.points, t)
slf.states = append(slf.states, state)
slf.trigger = append(slf.trigger, onTrigger)
return slf
}
// GetTimeByState 获取指定状态的时间点
func (slf *StateLine[State]) GetTimeByState(state State) time.Time {
for i := 0; i < len(slf.states); i++ {
if slf.states[i] == state {
return slf.points[i]
}
}
return time.Time{}
}
// GetNextTimeByState 获取指定状态的下一个时间点
func (slf *StateLine[State]) GetNextTimeByState(state State) time.Time {
for i := 0; i < len(slf.states); i++ {
if slf.states[i] == state && i+1 < len(slf.points) {
return slf.points[i+1]
}
}
return slf.points[0]
}
// GetLastState 获取最后一个状态
func (slf *StateLine[State]) GetLastState() State {
return slf.states[len(slf.states)-1]
}
// GetPrevTimeByState 获取指定状态的上一个时间点
func (slf *StateLine[State]) GetPrevTimeByState(state State) time.Time {
for i := len(slf.states) - 1; i >= 0; i-- {
if slf.states[i] == state && i > 0 {
return slf.points[i-1]
}
}
return time.Time{}
}
// GetIndexByState 获取指定状态的索引
func (slf *StateLine[State]) GetIndexByState(state State) int {
for i := 0; i < len(slf.states); i++ {
if slf.states[i] == state {
return i
}
}
return -1
}
// GetStateByTime 获取指定时间点的状态
func (slf *StateLine[State]) GetStateByTime(t time.Time) State {
for i := len(slf.points) - 1; i >= 0; i-- {
point := slf.points[i]
if point.Before(t) || point.Equal(t) {
return slf.states[i]
}
}
return slf.states[len(slf.points)-1]
}
// GetTimeByIndex 获取指定索引的时间点
func (slf *StateLine[State]) GetTimeByIndex(index int) time.Time {
return slf.points[index]
}
// Move 时间线整体移动
func (slf *StateLine[State]) Move(d time.Duration) *StateLine[State] {
for i := 0; i < len(slf.points); i++ {
slf.points[i] = slf.points[i].Add(d)
}
return slf
}
// GetNextStateTimeByIndex 获取指定索引的下一个时间点
func (slf *StateLine[State]) GetNextStateTimeByIndex(index int) time.Time {
return slf.points[index+1]
}
// GetPrevStateTimeByIndex 获取指定索引的上一个时间点
func (slf *StateLine[State]) GetPrevStateTimeByIndex(index int) time.Time {
return slf.points[index-1]
}
// GetStateIndexByTime 获取指定时间点的索引
func (slf *StateLine[State]) GetStateIndexByTime(t time.Time) int {
for i := len(slf.points) - 1; i >= 0; i-- {
var point = slf.points[i]
if point.Before(t) || point.Equal(t) {
return i
}
}
return -1
}
// GetStateCount 获取状态数量
func (slf *StateLine[State]) GetStateCount() int {
return len(slf.states)
}
// GetStateByIndex 获取指定索引的状态
func (slf *StateLine[State]) GetStateByIndex(index int) State {
return slf.states[index]
}
// GetTriggerByTime 获取指定时间点的触发器
func (slf *StateLine[State]) GetTriggerByTime(t time.Time) []func() {
for i := len(slf.points) - 1; i >= 0; i-- {
var point = slf.points[i]
if point.Before(t) || point.Equal(t) {
return slf.trigger[i]
}
}
return nil
}
// GetTriggerByIndex 获取指定索引的触发器
func (slf *StateLine[State]) GetTriggerByIndex(index int) []func() {
return slf.trigger[index]
}
// GetTriggerByState 获取指定状态的触发器
func (slf *StateLine[State]) GetTriggerByState(state State) []func() {
for i := 0; i < len(slf.states); i++ {
if slf.states[i] == state {
return slf.trigger[i]
}
}
return nil
}
// AddTriggerToState 给指定状态添加触发器
func (slf *StateLine[State]) AddTriggerToState(state State, onTrigger ...func()) *StateLine[State] {
for i := 0; i < len(slf.states); i++ {
if slf.states[i] == state {
slf.trigger[i] = append(slf.trigger[i], onTrigger...)
return slf
}
}
return slf
}
// Range 按照时间顺序遍历时间线
func (slf *StateLine[State]) Range(handler func(index int, state State, t time.Time) bool) {
for i := 0; i < len(slf.points); i++ {
if !handler(i, slf.states[i], slf.points[i]) {
return
}
}
}
// RangeReverse 按照时间逆序遍历时间线
func (slf *StateLine[State]) RangeReverse(handler func(index int, state State, t time.Time) bool) {
for i := len(slf.points) - 1; i >= 0; i-- {
if !handler(i, slf.states[i], slf.points[i]) {
return
}
}
}