初始化项目

This commit is contained in:
皮蛋13361098506
2025-01-06 16:01:02 +08:00
commit 1b77f62820
575 changed files with 69193 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
package rank_util
import "fmt"
// Model
// @description: 排行榜对象
type Model struct {
// rank 排行
rank int
// key 唯一key
key string
// obj 携带的对象
obj interface{}
}
// GetObj
// @description: 获取对象附加信息
// parameter:
// @receiver m:
// return:
// @interface{}:
func (m *Model) GetObj() interface{} {
return m.obj
}
// GetRank
// @description: 获取对象排行
// parameter:
// @receiver m:
// return:
// @int:
func (m *Model) GetRank() int {
return m.rank
}
// String
// @description: 字符串
// parameter:
// @receiver m:
// return:
// @string:
func (m *Model) String() string {
return fmt.Sprintf("rank:%v, Key:%s, Obj:{%s}", m.rank, m.key, m.obj)
}

View File

@@ -0,0 +1,148 @@
package rank_util
import (
"fmt"
"goutil/mathUtil"
"math"
"strconv"
"sync"
"testing"
"time"
)
func Test_Rank(t *testing.T) {
r := NewRankUtil(20, compar)
dc := make(map[string]*rmodel)
for i := 1; i < 1000; i++ {
tk := strconv.Itoa(i)
m := &rmodel{k: tk, Fap: 0}
dc[m.k] = m
}
goCount := 10
srand := mathUtil.GetRand()
var wg sync.WaitGroup
wg.Add(goCount)
for i := 0; i < goCount; i++ {
go func() {
for i := 1; i < 1000; i++ {
tk := strconv.Itoa(i)
newf := srand.GetRandRangeInt(1, 1000)
m, _ := dc[tk]
isUp := m.Fap < newf
m.Fap = newf
r.Refresh(tk, m, isUp)
}
}()
time.Sleep(time.Second)
wg.Done()
}
wg.Wait()
items := r.GetAll()
if len(items) != r.maxCount {
t.Error("排行榜长度不为", r.maxCount)
}
//测试删除
r.Delete(r.GetItemForRank(1).key)
items = r.GetAll()
if len(items) != r.maxCount-1 {
t.Error("删除后的排行榜长度不为", r.maxCount-1)
}
//校验标准: 1.key不可以重复 2.fap越来越小
beforeFap := math.MaxInt
tempKeyDict := make(map[string]bool)
isPrintAll := false
for _, item := range items {
m := item.obj.(*rmodel)
if m.k != item.key {
t.Errorf("错误item.key!=m.k item.key:%s m.k:%s", item.key, m.k)
isPrintAll = true
}
// 校验1
if _, exist := tempKeyDict[item.key]; exist {
t.Errorf("错误item.key重复 item.key:%s m.k:%s", item.key, m.k)
isPrintAll = true
} else {
tempKeyDict[item.key] = false
}
// 校验2
if m.Fap > beforeFap {
t.Errorf("错误m.Fap大于前面的排行 beforeFap:%v curFap:%v", beforeFap, m.Fap)
isPrintAll = true
}
}
if isPrintAll {
for _, item := range items {
m := item.obj.(*rmodel)
t.Log(m)
}
}
}
func Test_Rank2(t *testing.T) {
r := NewRankUtil(5, compar)
r.Refresh("1", &rmodel{k: "1", Fap: 1}, true)
r.Refresh("2", &rmodel{k: "2", Fap: 2}, true)
r.Refresh("3", &rmodel{k: "3", Fap: 3}, true)
r.Refresh("4", &rmodel{k: "4", Fap: 4}, true)
r.Refresh("5", &rmodel{k: "5", Fap: 5}, true)
//把1挤出去
ischange, dm := r.Refresh("6", &rmodel{k: "6", Fap: 6}, true)
if ischange == false {
t.Errorf("把1挤出去错误排行榜未变动")
return
}
if dm.key != "1" {
t.Errorf("把1挤出去错误挤出的不是1")
return
}
t.Log("被挤出的对象信息-> ", dm)
//打印所有
items := r.GetAll()
for _, item := range items {
t.Log(item)
}
}
type rmodel struct {
k string
Fap int
}
func (m *rmodel) String() string {
return fmt.Sprintf("m.k:%s fap:%v", m.k, m.Fap)
}
// compar
// @description: 判断对象大小,返回含义 -1:a<b 0:a=b 1:a>b
// parameter:
//
// @a:对象a
// @b:对象b
//
// return:
//
// @int:
func compar(a, b interface{}) int {
af := a.(*rmodel).Fap
bf := b.(*rmodel).Fap
if af > bf {
return 1
} else if af == bf {
return 0
} else {
return -1
}
}

View File

@@ -0,0 +1,54 @@
提供游戏内的实时排行榜功能,建议最大长度设定<=200
使用方式:
```go
package main
import (
rank_util "goutil/rank-util"
)
func main() {
// 构造对象
r := rank_util.NewRankUtil(20, compar)
// 刷新排行榜
m := &rmodel{k: "byrontest", Fap: 110}
ifChangeRank, dm := r.Refresh(m.k, m, true)
// 获取全部排行榜
tempList := r.GetAll()
// 删除某个key
isok := r.Delete("byrontest")
}
// compar
// @description: 判断对象大小,返回含义 -1:a<b 0:a=b 1:a>b
// parameter:
// @a:对象a
// @b:对象b
// return:
// @int:
func compar(a, b interface{}) int {
af := a.(*rmodel).Fap
bf := b.(*rmodel).Fap
if af > bf {
return 1
} else if af == bf {
return 0
} else {
return -1
}
}
type rmodel struct {
k string
Fap int
}
```

View File

@@ -0,0 +1,343 @@
package rank_util
import (
"sync"
)
// RankUtil
// @description:排行工具类
type RankUtil struct {
// maxCount 排行榜最大数量
maxCount int
// compar 对比函数 返回含义 -1:a<b 0:a=b 1:a>b
compar func(a, b interface{}) int
// dataList 排行数据
dataList []*Model
// dataDict 数据字典
dataDict map[string]*Model
// dataLock 数据锁
dataLock sync.RWMutex
}
// NewRankUtil
// @description: 构造排行对象
// parameter:
// @mc:最大容量
// @comp:元素比对方法
// return:
func NewRankUtil(mc int, comp func(a, b interface{}) int) *RankUtil {
result := &RankUtil{
maxCount: mc,
compar: comp,
dataList: make([]*Model, 0, mc),
dataDict: make(map[string]*Model, mc),
}
return result
}
// GetMaxCount
// @description: 获取排行榜最大数量
// parameter:
// @receiver r:
// return:
// @int:
func (r *RankUtil) GetMaxCount() int {
return r.maxCount
}
// GetCount
// @description: 获取排行榜当前数量
// parameter:
// @receiver r:
// return:
// @int:
func (r *RankUtil) GetCount() int {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
return len(r.dataList)
}
// IsFull
// @description: 判断排行榜是否已经满了
// parameter:
// @receiver r:
// return:
// @bool:
func (r *RankUtil) IsFull() bool {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
return len(r.dataList) == r.maxCount
}
// GetAll
// @description: 获取排行榜内容
// parameter:
// @receiver r:
// return:
// @[]*Model:
func (r *RankUtil) GetAll() []*Model {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
result := make([]*Model, 0, len(r.dataList))
for _, item := range r.dataList {
if item == nil || item.obj == nil {
break
}
result = append(result, item)
}
return result
}
// GetRankListBySkip
// @description: 获取排行榜内容
// parameter:
// @receiver r:
// @skip:跳过的数量
// @count:跳过后需要返回的数量
// return:
// @[]*Model:
func (r *RankUtil) GetRankListBySkip(skip, count int) []*Model {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
result := make([]*Model, 0, count)
cn := len(r.dataList)
if skip >= cn {
return result
}
for i := 0; i < count; i++ {
item := r.dataList[skip+i]
if item == nil || item.obj == nil {
break
}
result = append(result, item)
}
return result
}
// GetItemForK
// @description: 根据key获取对象
// parameter:
// @receiver r:
// @k:key
// return:
// @*Model:
func (r *RankUtil) GetItemForK(k string) *Model {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
item, _ := r.dataDict[k]
return item
}
// GetItemForRank
// @description: 根据排名获取对应对象
// parameter:
// @receiver r:
// @rank:排名
// return:
// @*Model:
func (r *RankUtil) GetItemForRank(rank int) *Model {
r.dataLock.RLock()
defer r.dataLock.RUnlock()
if len(r.dataList) < rank {
return nil
}
return r.dataList[rank-1]
}
// Refresh
// @description: 刷新排行榜
// parameter:
// @receiver r:
// @k:key
// @o:排行持有的对象,业务层不应该持有该对象。否则业务层更改内容,会导致排行榜内容被改变
// @isup:变动是否升高
// return:
// @changeRank:排行是否变动
// @dm:如果有对象因为排行变动导致掉出排行榜则返回该对象否则返回nil
func (r *RankUtil) Refresh(k string, o interface{}, isup bool) (changeRank bool, dm *Model) {
r.dataLock.Lock()
defer r.dataLock.Unlock()
changeRank = false
curItem, exists := r.dataDict[k]
if isup {
if !exists {
newRank := len(r.dataList) + 1
curItem = &Model{rank: newRank, key: k, obj: o}
// 排行榜未满,必定入榜,则先加入排行榜
if newRank <= r.maxCount {
r.dataList = append(r.dataList, curItem)
r.dataDict[curItem.key] = curItem
changeRank = true
_, dm = r.upRank(curItem)
} else {
changeRank, dm = r.upRank(curItem)
}
} else {
curItem.obj = o
changeRank, dm = r.upRank(curItem)
}
} else {
// 如果在排行榜内,从之前往下比较
if exists {
curItem.obj = o
changeRank = r.downRank(curItem)
} else {
// 如果不在排行榜内,直接结束
}
}
return
}
// Delete
// @description: 删除k指定的对象,很耗性能,不建议高频使用
// parameter:
// @receiver r:
// @k:key
// return:
// @bool:true:代表key存在排行榜中并且删除成功 false:其他情况
func (r *RankUtil) Delete(k string) bool {
r.dataLock.Lock()
defer r.dataLock.Unlock()
m, exists := r.dataDict[k]
if !exists {
return false
}
//从当前位置向后移动,到最后的时候,删除
for {
if m.rank >= len(r.dataList) {
break
}
am := r.dataList[m.rank]
r.exchange(m, am)
m = am
}
//最后一个应该是要删除的对象
r.dataList = append(r.dataList[:m.rank-1:r.maxCount], r.dataList[m.rank:]...)
delete(r.dataDict, k)
return true
}
// upRank
// @description: 排行升高
// parameter:
// @receiver r:
// @curItem:当前对象
// return:
// @changeRank:排行是否变动
// @dm:因排行变动被移除排行的对象
func (r *RankUtil) upRank(curItem *Model) (changeRank bool, dm *Model) {
changeRank = false
for {
// rank=1,排在第一位下标为0故这里需要-2为上一位的下标
beforeIndex := curItem.rank - 2
if beforeIndex < 0 {
break
}
beforeItem := r.dataList[beforeIndex]
if r.compar(curItem.obj, beforeItem.obj) <= 0 {
break
}
// 交换操作
tdm := r.exchange(curItem, beforeItem)
if tdm != nil {
dm = tdm
}
curItem = beforeItem
changeRank = true
}
return
}
// downRank
// @description: 排行降低
// parameter:
// @receiver r:
// @curItem:当前对象
// return:
// @bool:
func (r *RankUtil) downRank(curItem *Model) bool {
changeRank := false
for {
// rank=1,排在第一位下标为0需要对比rank=2的下标为1故这里直接取rank即可
afterIndex := curItem.rank
if afterIndex >= len(r.dataList) {
break
}
afterItem := r.dataList[afterIndex]
if r.compar(afterItem.obj, curItem.obj) <= 0 {
break
}
// 交换操作
r.exchange(curItem, afterItem)
curItem = afterItem
changeRank = true
}
return changeRank
}
// exchange
// @description: 排行对象交换
// parameter:
// @receiver r:
// @a:对象a
// @b:对象b
// return:
// @delRank:因交换被移除排行榜的对象
func (r *RankUtil) exchange(a, b *Model) (dm *Model) {
tempObj := a.obj
tempKey := a.key
a.obj = b.obj
a.key = b.key
b.obj = tempObj
b.key = tempKey
if a.rank > r.maxCount {
delete(r.dataDict, a.key)
dm = a
} else {
r.dataDict[a.key] = a
}
if b.rank > r.maxCount {
delete(r.dataDict, b.key)
dm = b
} else {
r.dataDict[b.key] = b
}
return
}