init commit

This commit is contained in:
flswld
2022-11-20 15:38:00 +08:00
parent eda2b643b9
commit 3efed3defe
5834 changed files with 636508 additions and 0 deletions

View File

@@ -0,0 +1,196 @@
package alg
const (
NODE_NONE = iota
NODE_START
NODE_END
NODE_BLOCK
)
type PathNode struct {
x int16
y int16
z int16
visit bool
state int
parent *PathNode
}
type BFS struct {
gMap map[int16]map[int16]map[int16]*PathNode
startPathNode *PathNode
endPathNode *PathNode
}
func NewBFS() (r *BFS) {
r = new(BFS)
return r
}
func (b *BFS) InitMap(terrain map[MeshMapPos]bool, start MeshMapPos, end MeshMapPos, extR int16) {
xLen := end.X - start.X
yLen := end.Y - start.Y
zLen := end.Z - start.Z
dx := int16(1)
dy := int16(1)
dz := int16(1)
if xLen < 0 {
dx = -1
xLen *= -1
}
if yLen < 0 {
dy = -1
yLen *= -1
}
if zLen < 0 {
dz = -1
zLen *= -1
}
b.gMap = make(map[int16]map[int16]map[int16]*PathNode)
for x := start.X - extR*dx; x != end.X+extR*dx; x += dx {
b.gMap[x] = make(map[int16]map[int16]*PathNode)
for y := start.Y - extR*dy; y != end.Y+extR*dy; y += dy {
b.gMap[x][y] = make(map[int16]*PathNode)
for z := start.Z - extR*dz; z != end.Z+extR*dz; z += dz {
state := -1
if x == start.X && y == start.Y && z == start.Z {
state = NODE_START
} else if x == end.X && y == end.Y && z == end.Z {
state = NODE_END
} else {
_, exist := terrain[MeshMapPos{
X: x,
Y: y,
Z: z,
}]
if exist {
state = NODE_NONE
} else {
state = NODE_BLOCK
}
}
node := &PathNode{
x: x,
y: y,
z: z,
visit: false,
state: state,
parent: nil,
}
b.gMap[x][y][z] = node
if node.state == NODE_START {
b.startPathNode = node
} else if node.state == NODE_END {
b.endPathNode = node
}
}
}
}
}
func (b *BFS) GetNeighbor(node *PathNode) []*PathNode {
neighborList := make([]*PathNode, 0)
dir := [][3]int16{
//
{1, 0, 0},
{-1, 0, 0},
{0, 1, 0},
{0, -1, 0},
{0, 0, 1},
{0, 0, -1},
//
{1, 1, 0},
{-1, 1, 0},
{-1, -1, 0},
{1, -1, 0},
//
{1, 0, 1},
{-1, 0, 1},
{-1, 0, -1},
{1, 0, -1},
//
{0, 1, 1},
{0, -1, 1},
{0, -1, -1},
{0, 1, -1},
//
{1, 1, 1},
{1, 1, -1},
{1, -1, 1},
{1, -1, -1},
{-1, 1, 1},
{-1, 1, -1},
{-1, -1, 1},
{-1, -1, -1},
}
for _, v := range dir {
x := node.x + v[0]
y := node.y + v[1]
z := node.z + v[2]
if _, exist := b.gMap[x]; !exist {
continue
}
if _, exist := b.gMap[x][y]; !exist {
continue
}
if _, exist := b.gMap[x][y][z]; !exist {
continue
}
neighborNode := b.gMap[x][y][z]
neighborList = append(neighborList, neighborNode)
}
return neighborList
}
func (b *BFS) GetPath() []*PathNode {
path := make([]*PathNode, 0)
if b.endPathNode.parent == nil {
return nil
}
node := b.endPathNode
for {
if node == nil {
break
}
path = append(path, node)
node = node.parent
}
if len(path) == 0 {
return nil
}
return path
}
func (b *BFS) Pathfinding() []MeshMapPos {
queue := NewALQueue[*PathNode]()
b.startPathNode.visit = true
queue.EnQueue(b.startPathNode)
for queue.Len() > 0 {
head := queue.DeQueue()
neighborList := b.GetNeighbor(head)
for _, neighbor := range neighborList {
if !neighbor.visit && neighbor.state != NODE_BLOCK {
neighbor.visit = true
neighbor.parent = head
queue.EnQueue(neighbor)
if neighbor.state == NODE_END {
break
}
}
}
}
path := b.GetPath()
if path == nil {
return nil
}
pathVectorList := make([]MeshMapPos, 0)
for i := len(path) - 1; i >= 0; i-- {
node := path[i]
pathVectorList = append(pathVectorList, MeshMapPos{
X: node.x,
Y: node.y,
Z: node.z,
})
}
return pathVectorList
}

View File

@@ -0,0 +1,7 @@
package alg
type MeshMapPos struct {
X int16
Y int16
Z int16
}

127
common/utils/alg/queue.go Normal file
View File

@@ -0,0 +1,127 @@
package alg
type LinkList struct {
value any
frontNode *LinkList
nextNode *LinkList
}
// LinkListQueue 无界队列 每个元素可存储不同数据结构
type LLQueue struct {
headPtr *LinkList
tailPtr *LinkList
len uint64
}
func NewLLQueue() *LLQueue {
return &LLQueue{
headPtr: nil,
tailPtr: nil,
len: 0,
}
}
func (q *LLQueue) Len() uint64 {
return q.len
}
func (q *LLQueue) EnQueue(value any) {
if q.headPtr == nil || q.tailPtr == nil {
q.headPtr = new(LinkList)
q.tailPtr = q.headPtr
} else {
q.tailPtr.nextNode = new(LinkList)
q.tailPtr.nextNode.frontNode = q.tailPtr
q.tailPtr = q.tailPtr.nextNode
}
q.tailPtr.value = value
q.len++
}
func (q *LLQueue) DeQueue() any {
if q.Len() == 0 || q.headPtr == nil {
return nil
}
ret := q.headPtr.value
q.len--
q.headPtr = q.headPtr.nextNode
return ret
}
// ArrayListQueue 无界队列 泛型
type ALQueue[T any] struct {
array []T
}
func NewALQueue[T any]() *ALQueue[T] {
return &ALQueue[T]{
array: make([]T, 0),
}
}
func (q *ALQueue[T]) Len() uint64 {
return uint64(len(q.array))
}
func (q *ALQueue[T]) EnQueue(value T) {
q.array = append(q.array, value)
}
func (q *ALQueue[T]) DeQueue() T {
if q.Len() == 0 {
var null T
return null
}
ret := q.array[0]
q.array = q.array[1:]
return ret
}
// RingArrayQueue 有界队列 性能最好
type RAQueue[T any] struct {
ringArray []T
ringArrayLen uint64
headPtr uint64
tailPtr uint64
len uint64
}
func NewRAQueue[T any](size uint64) *RAQueue[T] {
return &RAQueue[T]{
ringArray: make([]T, size),
ringArrayLen: size,
headPtr: 0,
tailPtr: 0,
len: 0,
}
}
func (q *RAQueue[T]) Len() uint64 {
return q.len
}
func (q *RAQueue[T]) EnQueue(value T) {
if q.len >= q.ringArrayLen {
return
}
q.ringArray[q.tailPtr] = value
q.tailPtr++
if q.tailPtr >= q.ringArrayLen {
q.tailPtr = 0
}
q.len++
}
func (q *RAQueue[T]) DeQueue() T {
if q.Len() == 0 {
var null T
return null
}
ret := q.ringArray[q.headPtr]
q.headPtr++
if q.headPtr >= q.ringArrayLen {
q.headPtr = 0
}
q.len--
return ret
}

View File

@@ -0,0 +1,92 @@
package alg
import (
"fmt"
"testing"
)
func TestLLQueue(t *testing.T) {
queue := NewLLQueue()
queue.EnQueue(float32(100.123))
queue.EnQueue(uint8(66))
queue.EnQueue("aaa")
queue.EnQueue(int64(-123456789))
queue.EnQueue(true)
queue.EnQueue(5)
for queue.Len() > 0 {
value := queue.DeQueue()
fmt.Println(value)
}
}
func TestALQueue(t *testing.T) {
queue := NewALQueue[uint8]()
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(8)
queue.EnQueue(9)
for queue.Len() > 0 {
value := queue.DeQueue()
fmt.Println(value)
}
}
func TestRAQueue(t *testing.T) {
queue := NewRAQueue[uint8](1000)
queue.EnQueue(1)
queue.EnQueue(2)
queue.EnQueue(8)
queue.EnQueue(9)
for queue.Len() > 0 {
value := queue.DeQueue()
fmt.Println(value)
}
}
func BenchmarkLLQueue(b *testing.B) {
data := ""
for i := 0; i < 1024; i++ {
data += "X"
}
queue := NewLLQueue()
for i := 0; i < b.N; i++ {
for i := 0; i < 100; i++ {
queue.EnQueue(&data)
}
for i := 0; i < 100; i++ {
queue.DeQueue()
}
}
}
func BenchmarkALQueue(b *testing.B) {
data := ""
for i := 0; i < 1024; i++ {
data += "X"
}
queue := NewALQueue[*string]()
for i := 0; i < b.N; i++ {
for i := 0; i < 100; i++ {
queue.EnQueue(&data)
}
for i := 0; i < 100; i++ {
queue.DeQueue()
}
}
}
func BenchmarkRAQueue(b *testing.B) {
data := ""
for i := 0; i < 1024; i++ {
data += "X"
}
queue := NewRAQueue[*string](1000)
for i := 0; i < b.N; i++ {
for i := 0; i < 100; i++ {
queue.EnQueue(&data)
}
for i := 0; i < 100; i++ {
queue.DeQueue()
}
}
}

View File

@@ -0,0 +1,89 @@
package alg
import (
"sync"
"time"
)
// 雪花算法的基本实现
// snowflake ID 是一个64位的int数据 由四部分组成
// A-B-C-D
// A 1位 最高位不使用
// B 41位 时间戳
// C 10位 节点ID
// D 12位 毫秒内序列号
// 时间戳 节点ID 毫秒内序列号 位数可按需调整
const (
workerBits uint8 = 10 // 节点ID位数 2^10=1024
numberBits uint8 = 12 // 毫秒内序列号位数 2^12=4096
workerMax int64 = -1 ^ (-1 << workerBits) // 节点ID最大值
numberMax int64 = -1 ^ (-1 << numberBits) // 毫秒内序列号最大值
timeShift = workerBits + numberBits // 时间戳向左偏移量
workerShift = numberBits // 节点ID向左偏移量
/*
* 原始算法使用41位字节作为时间戳数值
* 大约68年也就是2038年就会用完
* 这里做个偏移以增加可用时间
* !!!这个一旦定义且开始生成ID后千万不要改了!!!
* 不然可能会生成相同的ID
*/
epoch int64 = 1657148827000 // 2022-07-07 07:07:07
)
type SnowflakeWorker struct {
lock sync.Mutex // 互斥锁
timestamp int64 // 记录时间戳
workerId int64 // 节点ID
number int64 // 当前毫秒内已经生成的ID序列号 从0开始累加
}
func NewSnowflakeWorker(workerId int64) *SnowflakeWorker {
if workerId < 0 || workerId > workerMax {
// worker id error
return nil
}
worker := &SnowflakeWorker{
timestamp: 0,
workerId: workerId,
number: 0,
}
return worker
}
func (s *SnowflakeWorker) GenId() int64 {
s.lock.Lock()
defer s.lock.Unlock()
// 当前毫秒时间戳
now := time.Now().UnixNano() / 1e6
if s.timestamp > now {
// 发生了时钟回拨
if s.timestamp-now > 1000 {
// 时钟回拨太严重
return -1
}
for now <= s.timestamp {
// 自旋等待当前时间超过上一次ID生成的时间
now = time.Now().UnixNano() / 1e6
}
}
if s.timestamp == now {
s.number++
if s.number > numberMax {
// 当前毫秒内生成ID数量超过限制
for now <= s.timestamp {
// 自旋等待
now = time.Now().UnixNano() / 1e6
}
}
}
if s.timestamp < now {
// 新的毫秒到来重置序列号和时间戳
s.number = 0
s.timestamp = now
}
// 生成ID
id := (now-epoch)<<timeShift | (s.workerId << workerShift) | (s.number)
return id
}

View File

@@ -0,0 +1,50 @@
package alg
import (
"fmt"
"sync"
"testing"
)
type UniqueID interface {
~int64 | ~string
}
func idDupCheck[T UniqueID](genIdFunc func() T) {
var wg sync.WaitGroup
totalIdList := make(map[int]*[]T)
for i := 0; i < 1000; i++ {
wg.Add(1)
_idList := make([]T, 0)
_idListPtr := &_idList
totalIdList[i] = _idListPtr
go func(idListPtr *[]T) {
defer wg.Done()
for ii := 0; ii < 10000; ii++ {
id := genIdFunc()
*idListPtr = append(*idListPtr, id)
}
}(_idListPtr)
}
wg.Wait()
dupCheck := make(map[T]bool)
for gid, idListPtr := range totalIdList {
for _, id := range *idListPtr {
value, exist := dupCheck[id]
if exist && value == true {
fmt.Printf("find dup id, gid: %v, id: %v\n", gid, id)
} else {
dupCheck[id] = true
}
}
}
fmt.Printf("check finish\n")
}
func TestSnowflakeGenId(t *testing.T) {
snowflake := NewSnowflakeWorker(1)
if snowflake == nil {
panic("create snowflake worker error")
}
idDupCheck(snowflake.GenId)
}