From 19192b097b2308741fbcdc6551267045933c10c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=87=7E?= <158024940+xyy0411@users.noreply.github.com> Date: Sun, 22 Dec 2024 16:26:08 +0800 Subject: [PATCH] =?UTF-8?q?add(niuniu):=20=E5=B0=81=E8=A3=85=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E6=93=8D=E4=BD=9C=20(#61)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 + niu/main.go | 382 ++++++++++++++++++++++++++++++++++++++++++ niu/models.go | 426 +++++++++++++++++++++++++++++++++++++++++++++++ niu/test_test.go | 42 +++++ niu/utils.go | 240 ++++++++++++++++++++++++++ 5 files changed, 1092 insertions(+) create mode 100644 niu/main.go create mode 100644 niu/models.go create mode 100644 niu/test_test.go create mode 100644 niu/utils.go diff --git a/README.md b/README.md index 240bcc7..81905a9 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ huggingface API 二次元 AI tag 作画 ## nsfw 图片合规性审查 +## niu +niu ## pixiv P站解析与图片下载 ## qzone diff --git a/niu/main.go b/niu/main.go new file mode 100644 index 0000000..1ef24f4 --- /dev/null +++ b/niu/main.go @@ -0,0 +1,382 @@ +// Package niu 牛牛大作战 +package niu + +import ( + "errors" + "fmt" + "github.com/FloatTech/AnimeAPI/wallet" + "github.com/FloatTech/floatbox/file" + sql "github.com/FloatTech/sqlite" + "os" + "strconv" + "strings" + "sync" + "time" +) + +var ( + db = &model{} + globalLock sync.Mutex + // ErrNoBoys 表示当前没有男孩子可用的错误。 + ErrNoBoys = errors.New("暂时没有男孩子哦") + + // ErrNoGirls 表示当前没有女孩子可用的错误。 + ErrNoGirls = errors.New("暂时没有女孩子哦") + + // ErrNoNiuNiu 表示用户尚未拥有牛牛的错误。 + ErrNoNiuNiu = errors.New("你还没有牛牛呢,快去注册吧!") + + // ErrNoNiuNiuINAuction 表示拍卖行当前没有牛牛可用的错误。 + ErrNoNiuNiuINAuction = errors.New("拍卖行还没有牛牛呢") + + // ErrNoMoney 表示用户资金不足的错误。 + ErrNoMoney = errors.New("你的钱不够快去赚钱吧!") + + // ErrAdduserNoNiuNiu 表示对方尚未拥有牛牛,因此无法进行某些操作的错误。 + ErrAdduserNoNiuNiu = errors.New("对方还没有牛牛呢,不能🤺") + + // ErrCannotFight 表示无法进行战斗操作的错误。 + ErrCannotFight = errors.New("你要和谁🤺?你自己吗?") + + // ErrNoNiuNiuTwo 表示用户尚未拥有牛牛,无法执行特定操作的错误。 + ErrNoNiuNiuTwo = errors.New("你还没有牛牛呢,咋的你想凭空造一个啊") + + // ErrAlreadyRegistered 表示用户已经注册过的错误。 + ErrAlreadyRegistered = errors.New("你已经注册过了") + + // ErrInvalidPropType 表示传入的道具类别错误的错误。 + ErrInvalidPropType = errors.New("道具类别传入错误") + + // ErrInvalidPropUsageScope 表示道具使用域错误的错误。 + ErrInvalidPropUsageScope = errors.New("道具使用域错误") + + // ErrPropNotFound 表示找不到指定道具的错误。 + ErrPropNotFound = errors.New("道具不存在") +) + +func init() { + if file.IsNotExist("data/niuniu") { + err := os.MkdirAll("data/niuniu", 0775) + if err != nil { + panic(err) + } + } + db.sql = sql.New("data/niuniu/niuniu.db") + err := db.sql.Open(time.Hour * 24) + if err != nil { + panic(err) + } +} + +// DeleteWordNiuNiu ... +func DeleteWordNiuNiu(gid, uid int64) error { + globalLock.Lock() + defer globalLock.Unlock() + return db.deleteWordNiuNiu(gid, uid) +} + +// SetWordNiuNiu length > 0 就增加 , length < 0 就减小 +func SetWordNiuNiu(gid, uid int64, length float64) error { + globalLock.Lock() + defer globalLock.Unlock() + niu, err := db.getWordNiuNiu(gid, uid) + if err != nil { + return err + } + niu.Length += length + return db.setWordNiuNiu(gid, niu) +} + +// GetWordNiuNiu ... +func GetWordNiuNiu(gid, uid int64) (float64, error) { + globalLock.Lock() + defer globalLock.Unlock() + + niu, err := db.getWordNiuNiu(gid, uid) + return niu.Length, err +} + +// GetRankingInfo 获取排行信息 +func GetRankingInfo(gid int64, t bool) (BaseInfos, error) { + globalLock.Lock() + defer globalLock.Unlock() + var ( + list users + err error + ) + niuOfGroup, err := db.getAllNiuNiuOfGroup(gid) + if err != nil { + if t { + return nil, ErrNoBoys + } + return nil, ErrNoGirls + } + list = niuOfGroup.filter(t) + f := make(BaseInfos, len(list)) + for i, info := range list { + f[i] = BaseInfo{ + UID: info.UID, + Length: info.Length, + } + } + return f, nil +} + +// GetGroupUserRank 获取指定用户在群中的排名 +func GetGroupUserRank(gid, uid int64) (int, error) { + globalLock.Lock() + defer globalLock.Unlock() + niu, err := db.getWordNiuNiu(gid, uid) + if err != nil { + return -1, err + } + group, err := db.getAllNiuNiuOfGroup(gid) + if err != nil { + return -1, err + } + return group.ranking(niu.Length, uid), nil +} + +// View 查看牛牛 +func View(gid, uid int64, name string) (*strings.Builder, error) { + i, err := db.getWordNiuNiu(gid, uid) + if err != nil { + return nil, ErrNoNiuNiu + } + niuniu := i.Length + var result strings.Builder + sexLong := "长" + sex := "♂️" + if niuniu < 0 { + sexLong = "深" + sex = "♀️" + } + niuniuList, err := db.getAllNiuNiuOfGroup(gid) + if err != nil { + return nil, err + } + result.WriteString(fmt.Sprintf("\n📛%s<%s>的牛牛信息\n⭕性别:%s\n⭕%s度:%.2fcm\n⭕排行:%d\n⭕%s ", + name, strconv.FormatInt(uid, 10), + sex, sexLong, niuniu, niuniuList.ranking(niuniu, uid), generateRandomString(niuniu))) + return &result, nil +} + +// HitGlue 打胶 +func HitGlue(gid, uid int64, prop string) (string, error) { + niuniu, err := db.getWordNiuNiu(gid, uid) + if err != nil { + return "", ErrNoNiuNiuTwo + } + + messages, err := niuniu.processNiuNiuAction(prop) + if err != nil { + return "", err + } + if err = db.setWordNiuNiu(gid, niuniu); err != nil { + return "", err + } + return messages, nil +} + +// Register 注册牛牛 +func Register(gid, uid int64) (string, error) { + if _, err := db.getWordNiuNiu(gid, uid); err == nil { + return "", ErrAlreadyRegistered + } + // 获取初始长度 + length := db.newLength() + u := userInfo{ + UID: uid, + Length: length, + } + if err := db.setWordNiuNiu(gid, &u); err != nil { + return "", err + } + return fmt.Sprintf("注册成功,你的牛牛现在有%.2fcm", u.Length), nil +} + +// JJ ... +func JJ(gid, uid, adduser int64, prop string) (message string, adduserLength float64, err error) { + + myniuniu, err := db.getWordNiuNiu(gid, uid) + if err != nil { + return "", 0, ErrNoNiuNiu + } + + adduserniuniu, err := db.getWordNiuNiu(gid, adduser) + if err != nil { + return "", 0, ErrAdduserNoNiuNiu + } + + if uid == adduser { + return "", 0, ErrCannotFight + } + + message, err = myniuniu.processJJuAction(adduserniuniu, prop) + if err != nil { + return "", 0, err + } + + if err = db.setWordNiuNiu(gid, myniuniu); err != nil { + return "", 0, err + } + + if err = db.setWordNiuNiu(gid, adduserniuniu); err != nil { + return "", 0, err + } + + adduserLength = adduserniuniu.Length + return +} + +// Cancel 注销牛牛 +func Cancel(gid, uid int64) (string, error) { + _, err := db.getWordNiuNiu(gid, uid) + if err != nil { + return "", ErrNoNiuNiuTwo + } + err = db.deleteWordNiuNiu(gid, uid) + if err != nil { + err = errors.New("遇到不可抗力因素,注销失败!") + } + return "注销成功,你已经没有牛牛了", err +} + +// Redeem 赎牛牛 +func Redeem(gid, uid int64, lastLength float64) error { + money := wallet.GetWalletOf(uid) + if money < 150 { + var builder strings.Builder + walletName := wallet.GetWalletName() + builder.WriteString("赎牛牛需要150") + builder.WriteString(walletName) + builder.WriteString(",快去赚钱吧,目前仅有:") + builder.WriteString(strconv.Itoa(money)) + builder.WriteString("个") + builder.WriteString(walletName) + return errors.New(builder.String()) + } + + if err := wallet.InsertWalletOf(uid, -150); err != nil { + return err + } + + niu, err := db.getWordNiuNiu(gid, uid) + if err != nil { + return ErrNoNiuNiu + } + + niu.Length = lastLength + + return db.setWordNiuNiu(gid, niu) +} + +// Store 牛牛商店 +func Store(gid, uid int64, n int) error { + info, err := db.getWordNiuNiu(gid, uid) + if err != nil { + return err + } + + money, err := info.purchaseItem(n) + if err != nil { + return err + } + + if wallet.GetWalletOf(uid) < money { + return ErrNoMoney + } + + if err = wallet.InsertWalletOf(uid, -money); err != nil { + return err + } + + return db.setWordNiuNiu(uid, info) +} + +// Sell 出售牛牛 +func Sell(gid, uid int64) (string, error) { + niu, err := db.getWordNiuNiu(gid, uid) + if err != nil { + return "", ErrNoNiuNiu + } + money, t, message := profit(niu.Length) + if !t { + return "", errors.New(message) + } + err = wallet.InsertWalletOf(uid, money) + if err != nil { + return message, err + } + u := AuctionInfo{ + UserID: niu.UID, + Length: niu.Length, + Money: money * 2, + } + err = db.setNiuNiuAuction(gid, &u) + return message, err +} + +// ShowAuction 展示牛牛拍卖行 +func ShowAuction(gid int64) ([]AuctionInfo, error) { + globalLock.Lock() + defer globalLock.Unlock() + return db.getAllNiuNiuAuction(gid) +} + +// Auction 购买牛牛 +func Auction(gid, uid int64, i int) (string, error) { + auction, err := db.getAllNiuNiuAuction(gid) + if err != nil { + return "", ErrNoNiuNiuINAuction + } + err = wallet.InsertWalletOf(uid, -auction[i].Money) + if err != nil { + return "", ErrNoMoney + } + + niu, err := db.getWordNiuNiu(gid, uid) + if err != nil { + niu = &userInfo{ + UID: uid, + } + } + niu.Length = auction[i].Length + + if auction[i].Money > 500 { + niu.WeiGe += 2 + niu.Artifact += 2 + } + + if err = db.setWordNiuNiu(gid, niu); err != nil { + return "", err + } + err = db.deleteNiuNiuAuction(gid, auction[i].ID) + if err != nil { + return "", err + } + if auction[i].Money > 500 { + return fmt.Sprintf("恭喜你购买成功,当前长度为%.2fcm,此次购买将赠送你2个伟哥,2个媚药", + niu.Length), nil + } + return fmt.Sprintf("恭喜你购买成功,当前长度为%.2fcm", niu.Length), nil +} + +// Bag 牛牛背包 +func Bag(gid, uid int64) (string, error) { + niu, err := db.getWordNiuNiu(gid, uid) + if err != nil { + return "", ErrNoNiuNiu + } + + var result strings.Builder + result.Grow(100) + + result.WriteString("当前牛牛背包如下\n") + result.WriteString(fmt.Sprintf("伟哥: %v\n", niu.WeiGe)) + result.WriteString(fmt.Sprintf("媚药: %v\n", niu.Philter)) + result.WriteString(fmt.Sprintf("击剑神器: %v\n", niu.Artifact)) + result.WriteString(fmt.Sprintf("击剑神稽: %v\n", niu.ShenJi)) + + return result.String(), nil +} diff --git a/niu/models.go b/niu/models.go new file mode 100644 index 0000000..e151a0c --- /dev/null +++ b/niu/models.go @@ -0,0 +1,426 @@ +// Package niu 牛牛大作战 +package niu + +import ( + "errors" + "fmt" + sql "github.com/FloatTech/sqlite" + "math" + "math/rand" + "sort" + "strconv" + "sync" +) + +var ( + daJiaoProps = []string{"伟哥", "媚药"} + jjPorps = []string{"击剑神器", "击剑神稽"} + query = "WHERE UID = ?" +) + +type users []*userInfo + +type model struct { + sql sql.Sqlite + sync.RWMutex +} + +type userInfo struct { + UID int64 + Length float64 + UserCount int + WeiGe int // 伟哥 + Philter int // 媚药 + Artifact int // 击剑神器 + ShenJi int // 击剑神稽 + Buff1 int // 暂定 + Buff2 int // 暂定 + Buff3 int // 暂定 + Buff4 int // 暂定 + Buff5 int // 暂定 +} + +// AuctionInfo 拍卖信息 +type AuctionInfo struct { + ID uint + UserID int64 + Length float64 + Money int +} + +// BaseInfo ... +type BaseInfo struct { + UID int64 + Length float64 +} + +// BaseInfos ... +type BaseInfos []BaseInfo + +func (m users) filter(pos bool) users { + if pos { + return m.positive() + } + return m.negative() +} + +func (m users) positive() users { + var m1 []*userInfo + for _, i2 := range m { + if i2.Length > 0 { + m1 = append(m1, i2) + } + } + return m1 +} + +func (m users) negative() users { + var m1 []*userInfo + for _, i2 := range m { + if i2.Length <= 0 { + m1 = append(m1, i2) + } + } + return m1 +} + +func (m users) sort(isDesc bool) { + t := func(i, j int) bool { + return m[i].Length < m[j].Length + } + if isDesc { + t = func(i, j int) bool { + return m[i].Length > m[j].Length + } + } + sort.Slice(m, t) +} + +func (m users) ranking(niuniu float64, uid int64) int { + m.sort(niuniu > 0) + for i, user := range m { + if user.UID == uid { + return i + 1 + } + } + return -1 +} + +func (u *userInfo) useWeiGe() (string, float64) { + niuniu := u.Length + reduce := math.Abs(hitGlue(niuniu)) + niuniu += reduce + return randomChoice([]string{ + fmt.Sprintf("哈哈,你这一用道具,牛牛就像是被激发了潜能,增加了%.2fcm!看来今天是个大日子呢!", reduce), + fmt.Sprintf("你这是用了什么神奇的道具?牛牛竟然增加了%.2fcm,简直是牛气冲天!", reduce), + fmt.Sprintf("使用道具后,你的牛牛就像是开启了加速模式,一下增加了%.2fcm,这成长速度让人惊叹!", reduce), + }), niuniu +} + +func (u *userInfo) usePhilter() (string, float64) { + niuniu := u.Length + reduce := math.Abs(hitGlue(niuniu)) + niuniu -= reduce + return randomChoice([]string{ + fmt.Sprintf("你使用媚药,咿呀咿呀一下使当前长度发生了一些变化,当前长度%.2f", niuniu), + fmt.Sprintf("看来你追求的是‘微观之美’,故意使用道具让牛牛凹进去了%.2fcm!", reduce), + fmt.Sprintf("缩小奇迹’在你身上发生了,牛牛凹进去了%.2fcm,你的选择真是独特!", reduce), + }), niuniu +} + +func (u *userInfo) useArtifact(adduserniuniu float64) (string, float64, float64) { + myLength := u.Length + difference := myLength - adduserniuniu + var ( + change float64 + ) + if difference > 0 { + change = hitGlue(myLength + adduserniuniu) + } else { + change = hitGlue((myLength + adduserniuniu) / 2) + } + myLength += change + return randomChoice([]string{ + fmt.Sprintf("凭借神秘道具的力量,你让对方在你的长度面前俯首称臣!你的长度增加了%.2fcm,当前长度达到了%.2fcm", change, myLength), + fmt.Sprintf("神器在手,天下我有!你使用道具后,长度猛增%.2fcm,现在的总长度是%.2fcm,无人能敌!", change, myLength), + fmt.Sprintf("这就是道具的魔力!你轻松增加了%.2fcm,让对手望尘莫及,当前长度为%.2fcm!", change, myLength), + fmt.Sprintf("道具一出,谁与争锋!你的长度因道具而增长%.2fcm,现在的长度是%.2fcm,霸气尽显!", change, myLength), + fmt.Sprintf("使用道具的你,如同获得神助!你的长度增长了%.2fcm,达到%.2fcm的惊人长度,胜利自然到手!", change, myLength), + }), myLength, adduserniuniu - change/1.3 +} + +func (u *userInfo) useShenJi(adduserniuniu float64) (string, float64, float64) { + myLength := u.Length + difference := myLength - adduserniuniu + var ( + change float64 + ) + if difference > 0 { + change = hitGlue(myLength + adduserniuniu) + } else { + change = hitGlue((myLength + adduserniuniu) / 2) + } + myLength -= change + var r string + if myLength > 0 { + r = randomChoice([]string{ + fmt.Sprintf("哦吼!?看来你的牛牛因为使用了神秘道具而缩水了呢🤣🤣🤣!缩小了%.2fcm!", change), + fmt.Sprintf("哈哈,看来这个道具有点儿调皮,让你的长度缩水了%.2fcm!现在你的长度是%.2fcm,下次可得小心使用哦!", change, myLength), + fmt.Sprintf("使用道具后,你的牛牛似乎有点儿害羞,缩水了%.2fcm!现在的长度是%.2fcm,希望下次它能挺直腰板!", change, myLength), + fmt.Sprintf("哎呀,这个道具的效果有点儿意外,你的长度减少了%.2fcm,现在只有%.2fcm了!下次选道具可得睁大眼睛!", change, myLength), + }) + } else { + r = randomChoice([]string{ + fmt.Sprintf("哦哟,小姐姐真是玩得一手好游戏,使用道具后数值又降低了%.2fcm,小巧得更显魅力!", change), + fmt.Sprintf("看来小姐姐喜欢更加精致的风格,使用道具后,数值减少了%.2fcm,更加迷人了!", change), + fmt.Sprintf("小姐姐的每一次变化都让人惊喜,使用道具后,数值减少了%.2fcm,更加优雅动人!", change), + fmt.Sprintf("小姐姐这是在展示什么是真正的精致小巧,使用道具后,数值减少了%.2fcm,美得不可方物!", change), + }) + } + return r, myLength, adduserniuniu + 0.7*change +} + +func (u *userInfo) applyProp(props string) error { + propsMap := map[string]struct { + itemCount *int + errMsg string + }{ + "伟哥": {&u.WeiGe, "你还没有伟哥呢,不能使用"}, + "媚药": {&u.Philter, "你还没有媚药呢,不能使用"}, + "击剑神器": {&u.Artifact, "你还没有击剑神器呢,不能使用"}, + "击剑神稽": {&u.ShenJi, "你还没有击剑神稽呢,不能使用"}, + } + + if propInfo, ok := propsMap[props]; ok { + return u.useItem(propInfo.itemCount, propInfo.errMsg) + } + return ErrPropNotFound +} + +func (u *userInfo) useItem(itemCount *int, errMsg string) error { + if *itemCount > 0 { + *itemCount-- + return nil + } + return errors.New(errMsg) +} + +func (u *userInfo) checkProps(props, propSort string) error { + + validProps := map[string][]string{ + "dajiao": daJiaoProps, + "jj": jjPorps, + } + + // 检查是否是有效道具类别 + validPropsList, ok := validProps[propSort] + if !ok { + return ErrInvalidPropType + } + + validPropsMap := make(map[string]struct{}) + for _, prop := range validPropsList { + validPropsMap[prop] = struct{}{} + } + + // 如果道具属于有效道具,返回 nil + if _, exists := validPropsMap[props]; exists { + return nil + } + + // 检查是否相反 + conflictingProps := daJiaoProps + if propSort == "dajiao" { + conflictingProps = jjPorps + } + + // 如果道具属于冲突集合,返回 + for _, conflictProp := range conflictingProps { + if props == conflictProp { + return ErrInvalidPropUsageScope + } + } + + return ErrPropNotFound +} + +func (u *userInfo) purchaseItem(n int) (int, error) { + var ( + money int + err error + ) + switch n { + case 1: + money = 300 + u.WeiGe += 5 + case 2: + money = 300 + u.Philter += 5 + case 3: + money = 500 + u.Artifact += 2 + case 4: + money = 500 + u.ShenJi += 2 + default: + err = errors.New("无效的选择") + } + return money, err +} + +func (u *userInfo) processNiuNiuAction(props string) (string, error) { + var ( + messages string + info userInfo + err error + f float64 + ) + info = *u + if props != "" { + err := u.checkProps(props, "dajiao") + if err != nil { + return "", err + } + if err := u.applyProp(props); err != nil { + return "", err + } + } + switch { + case u.WeiGe-info.WeiGe != 0: + messages, f = u.useWeiGe() + u.Length = f + + case u.Philter-info.Philter != 0: + messages, f = u.usePhilter() + u.Length = f + + default: + messages, f = hitGlueNiuNiu(u.Length) + u.Length = f + } + return messages, err +} + +func (u *userInfo) processJJuAction(adduserniuniu *userInfo, props string) (string, error) { + var ( + fencingResult string + f float64 + f1 float64 + info userInfo + err error + ) + info = *u + if props != "" { + err := u.checkProps(props, "jj") + if err != nil { + return "", err + } + if err := u.applyProp(props); err != nil { + return "", err + } + } + switch { + + case u.ShenJi-info.ShenJi != 0: + fencingResult, f, f1 = u.useShenJi(adduserniuniu.Length) + u.Length = f + adduserniuniu.Length = f1 + + case u.Artifact-info.Artifact != 0: + fencingResult, f, f1 = u.useArtifact(adduserniuniu.Length) + u.Length = f + adduserniuniu.Length = f1 + + default: + fencingResult, f, f1 = fencing(u.Length, adduserniuniu.Length) + u.Length = f + adduserniuniu.Length = f1 + + } + return fencingResult, err +} + +func (db *model) newLength() float64 { + return float64(rand.Intn(9)+1) + (float64(rand.Intn(100)) / 100) +} + +func (db *model) getWordNiuNiu(gid, uid int64) (*userInfo, error) { + db.RLock() + defer db.RUnlock() + + var u userInfo + err := db.sql.Find(strconv.FormatInt(gid, 10), &u, query, uid) + return &u, err +} + +func (db *model) setWordNiuNiu(gid int64, u *userInfo) error { + db.Lock() + defer db.Unlock() + err := db.sql.Insert(strconv.FormatInt(gid, 10), u) + if err != nil { + err = db.sql.Create(strconv.FormatInt(gid, 10), &userInfo{}) + if err != nil { + return err + } + err = db.sql.Insert(strconv.FormatInt(gid, 10), u) + } + return err +} + +func (db *model) deleteWordNiuNiu(gid, uid int64) error { + db.Lock() + defer db.Unlock() + return db.sql.Del(strconv.FormatInt(gid, 10), query, uid) +} + +func (db *model) getAllNiuNiuOfGroup(gid int64) (users, error) { + db.Lock() + defer db.Unlock() + var user userInfo + var useras users + err := db.sql.FindFor(fmt.Sprintf("%d", gid), &user, "", + func() error { + useras = append(useras, &user) + return nil + }) + return useras, err +} + +func (db *model) setNiuNiuAuction(gid int64, u *AuctionInfo) error { + db.Lock() + defer db.Unlock() + num, err := db.sql.Count(fmt.Sprintf("auction_%d", gid)) + if err != nil { + num = 1 + } + u.ID = uint(num) + err = db.sql.Insert(fmt.Sprintf("auction_%d", gid), u) + if err != nil { + err = db.sql.Create(fmt.Sprintf("auction_%d", gid), &AuctionInfo{}) + if err != nil { + return err + } + err = db.sql.Insert(fmt.Sprintf("auction_%d", gid), u) + } + return err +} + +func (db *model) deleteNiuNiuAuction(gid int64, id uint) error { + db.Lock() + defer db.Unlock() + return db.sql.Del(strconv.FormatInt(gid, 10), "WHERE ID = ?", id) +} + +func (db *model) getAllNiuNiuAuction(gid int64) ([]AuctionInfo, error) { + db.RLock() + defer db.RUnlock() + var user AuctionInfo + var useras []AuctionInfo + err := db.sql.FindFor(fmt.Sprintf("auction_%d", gid), &user, "", + func() error { + useras = append(useras, user) + return nil + }) + + return useras, err +} diff --git a/niu/test_test.go b/niu/test_test.go new file mode 100644 index 0000000..f8e496a --- /dev/null +++ b/niu/test_test.go @@ -0,0 +1,42 @@ +package niu + +import "testing" + +func TestCreateUserInfoByProps(t *testing.T) { + user := &userInfo{ + UID: 123, + Length: 12, + WeiGe: 2, + } + err := user.applyProp("媚药") + if err != nil { + t.Error(err) + } + t.Log("成功-----", user) +} + +func TestCheckProp(t *testing.T) { + user := &userInfo{ + UID: 123, + Length: 12, + WeiGe: 2, + } + err := user.checkProps("击剑", "jj") + if err != nil { + t.Error(err) + } + t.Log("成功") +} + +func TestProcessNiuNiuAction(t *testing.T) { + user := &userInfo{ + UID: 123, + Length: 12, + WeiGe: 2, + } + action, err := user.processNiuNiuAction("11") + if err != nil { + t.Error(err) + } + t.Log(action, "---------", user) +} diff --git a/niu/utils.go b/niu/utils.go new file mode 100644 index 0000000..9280f03 --- /dev/null +++ b/niu/utils.go @@ -0,0 +1,240 @@ +// Package niu 牛牛大作战 +package niu + +import ( + "fmt" + "github.com/FloatTech/AnimeAPI/wallet" + "math" + "math/rand" +) + +func randomChoice(options []string) string { + return options[rand.Intn(len(options))] +} + +func profit(niuniu float64) (money int, t bool, message string) { + switch { + case 0 < niuniu && niuniu <= 15: + message = randomChoice([]string{ + "你的牛牛太小啦", + "这么小的牛牛就要肩负起这么大的责任吗?快去打胶吧!", + }) + case niuniu > 15: + money = int(niuniu * 10) + message = randomChoice([]string{ + fmt.Sprintf("你的牛牛已经离你而去了,你赚取了%d个%s", money, wallet.GetWalletName()), + fmt.Sprintf("啊!你的牛☞已经没啦🤣,为了这点钱就出卖你的牛牛可真不值,你赚取了%d个%s", money, wallet.GetWalletName()), + }) + t = true + case niuniu <= 0 && niuniu >= -15: + message = randomChoice([]string{ + "你的牛牛太小啦", + "这么小的牛牛就要肩负起这么大的责任吗?快去找别人玩吧!", + }) + case niuniu < -15: + money = int(math.Abs(niuniu * 10)) + message = randomChoice([]string{ + fmt.Sprintf("此世做了女孩子来世来当男孩子(bushi),你赚取了%d个%s", money, wallet.GetWalletName()), + fmt.Sprintf("呜呜呜,不哭不哭当女孩子不委屈的,你赚取了%d个%s", money, wallet.GetWalletName()), + }) + t = true + } + return +} + +func hitGlueNiuNiu(niuniu float64) (string, float64) { + probability := rand.Intn(100 + 1) + reduce := math.Abs(hitGlue(niuniu)) + switch { + case probability <= 40: + niuniu += reduce + return randomChoice([]string{ + fmt.Sprintf("你嘿咻嘿咻一下,促进了牛牛发育,牛牛增加%.2fcm了呢!", reduce), + fmt.Sprintf("你打了个舒服痛快的🦶呐,牛牛增加了%.2fcm呢!", reduce), + }), niuniu + case probability <= 60: + return randomChoice([]string{ + "你打了个🦶,但是什么变化也没有,好奇怪捏~", + "你的牛牛刚开始变长了,可过了一会又回来了,什么变化也没有,好奇怪捏~", + }), niuniu + default: + niuniu -= reduce + if niuniu < 0 { + return randomChoice([]string{ + fmt.Sprintf("哦吼!?看来你的牛牛凹进去了%.2fcm呢!", reduce), + fmt.Sprintf("你突发恶疾!你的牛牛凹进去了%.2fcm!", reduce), + fmt.Sprintf("笑死,你因为打🦶过度导致牛牛凹进去了%.2fcm!🤣🤣🤣", reduce), + }), niuniu + } + return randomChoice([]string{ + fmt.Sprintf("阿哦,你过度打🦶,牛牛缩短%.2fcm了呢!", reduce), + fmt.Sprintf("你的牛牛变长了很多,你很激动地继续打🦶,然后牛牛缩短了%.2fcm呢!", reduce), + fmt.Sprintf("小打怡情,大打伤身,强打灰飞烟灭!你过度打🦶,牛牛缩短了%.2fcm捏!", reduce), + }), niuniu + } +} + +func generateRandomString(niuniu float64) string { + switch { + case niuniu <= -100: + return "wtf?你已经进化成魅魔了!魅魔在击剑时有20%的几率消耗自身长度吞噬对方牛牛呢。" + case niuniu <= -50: + return "嗯....好像已经穿过了身体吧..从另一面来看也可以算是凸出来的吧?" + case niuniu <= -25: + return randomChoice([]string{ + "这名女生,你的身体很健康哦!", + "WOW,真的凹进去了好多呢!", + "你已经是我们女孩子的一员啦!", + }) + case niuniu <= -10: + return randomChoice([]string{ + "你已经是一名女生了呢,", + "从女生的角度来说,你发育良好(,", + "你醒啦?你已经是一名女孩子啦!", + "唔...可以放进去一根手指了都...", + }) + case niuniu <= 0: + return randomChoice([]string{ + "安了安了,不要伤心嘛,做女生有什么不好的啊。", + "不哭不哭,摸摸头,虽然很难再长出来,但是请不要伤心啦啊!", + "加油加油!我看好你哦!", + "你醒啦?你现在已经是一名女孩子啦!", + }) + case niuniu <= 10: + return randomChoice([]string{ + "你行不行啊?细狗!", + "虽然短,但是小小的也很可爱呢。", + "像一只蚕宝宝。", + "长大了。", + }) + case niuniu <= 25: + return randomChoice([]string{ + "唔...没话说", + "已经很长了呢!", + }) + case niuniu <= 50: + return randomChoice([]string{ + "话说这种真的有可能吗?", + "厚礼谢!", + }) + case niuniu <= 100: + return randomChoice([]string{ + "已经突破天际了嘛...", + "唔...这玩意应该不会变得比我高吧?", + "你这个长度会死人的...!", + "你马上要进化成牛头人了!!", + "你是什么怪物,不要过来啊!!", + }) + default: + return "惊世骇俗!你已经进化成牛头人了!牛头人在击剑时有20%的几率消耗自身长度吞噬对方牛牛呢。" + } +} + +// fencing 击剑对决逻辑,返回对决结果和myLength的变化值 +func fencing(myLength, oppoLength float64) (string, float64, float64) { + devourLimit := 0.27 + + probability := rand.Intn(100) + 1 + + switch { + case oppoLength <= -100 && myLength > 0 && 10 < probability && probability <= 20: + change := hitGlue(oppoLength) + rand.Float64()*math.Log2(math.Abs(0.5*(myLength+oppoLength))) + myLength += change + myLength *= 0.85 + return fmt.Sprintf("对方身为魅魔诱惑了你,你同化成魅魔!当前长度%.2fcm!", -myLength), -myLength, oppoLength + + case oppoLength >= 100 && myLength > 0 && 10 < probability && probability <= 20: + change := math.Min(math.Abs(devourLimit*myLength), math.Abs(1.5*myLength)) + myLength += change + myLength *= 0.85 + return fmt.Sprintf("对方以牛头人的荣誉摧毁了你的牛牛!当前长度%.2fcm!", myLength), myLength, oppoLength + + case myLength <= -100 && oppoLength > 0 && 10 < probability && probability <= 20: + change := hitGlue(myLength+oppoLength) + rand.Float64()*math.Log2(math.Abs(0.5*(myLength+oppoLength))) + oppoLength -= change + myLength -= change + myLength *= 0.85 + return fmt.Sprintf("你身为魅魔诱惑了对方,吞噬了对方部分长度!当前长度%.2fcm!", myLength), myLength, oppoLength + + case myLength >= 100 && oppoLength > 0 && 10 < probability && probability <= 20: + myLength -= oppoLength + myLength *= 0.85 + oppoLength = 0.01 + return fmt.Sprintf("你以牛头人的荣誉摧毁了对方的牛牛!当前长度%.2fcm!", myLength), myLength, oppoLength + + default: + return determineResultBySkill(myLength, oppoLength) + } +} + +// determineResultBySkill 根据击剑技巧决定结果 +func determineResultBySkill(myLength, oppoLength float64) (string, float64, float64) { + probability := rand.Intn(100) + 1 + winProbability := calculateWinProbability(myLength, oppoLength) * 100 + return applySkill(myLength, oppoLength, + float64(probability) <= winProbability) +} + +// calculateWinProbability 计算胜率 +func calculateWinProbability(heightA, heightB float64) float64 { + pA := 0.9 + heightRatio := math.Max(heightA, heightB) / math.Min(heightA, heightB) + reductionRate := 0.1 * (heightRatio - 1) + reduction := pA * reductionRate + + adjustedPA := pA - reduction + return math.Max(adjustedPA, 0.01) +} + +// applySkill 应用击剑技巧并生成结果 +func applySkill(myLength, oppoLength float64, increaseLength1 bool) (string, float64, float64) { + reduce := fence(oppoLength) + // 兜底操作 + if reduce == 0 { + reduce = rand.Float64() + float64(rand.Intn(3)) + } + if increaseLength1 { + myLength += reduce + oppoLength -= 0.8 * reduce + if myLength < 0 { + return fmt.Sprintf("哦吼!?你的牛牛在长大欸!长大了%.2fcm!", reduce), myLength, oppoLength + } + return fmt.Sprintf("你以绝对的长度让对方屈服了呢!你的长度增加%.2fcm,当前长度%.2fcm!", reduce, myLength), myLength, oppoLength + } + myLength -= reduce + oppoLength += 0.8 * reduce + if myLength < 0 { + return fmt.Sprintf("哦吼!?看来你的牛牛因为击剑而凹进去了呢🤣🤣🤣!凹进去了%.2fcm!", reduce), myLength, oppoLength + } + return fmt.Sprintf("对方以绝对的长度让你屈服了呢!你的长度减少%.2fcm,当前长度%.2fcm!", reduce, myLength), myLength, oppoLength +} + +// fence 根据长度计算减少的长度 +func fence(rd float64) float64 { + rd = math.Abs(rd) + if rd == 0 { + rd = 1 + } + r := hitGlue(rd)*2 + rand.Float64()*math.Log2(rd) + + return float64(int(r * rand.Float64())) +} + +func hitGlue(l float64) float64 { + if l == 0 { + l = 0.1 + } + l = math.Abs(l) + switch { + case l > 1 && l <= 10: + return rand.Float64() * math.Log2(l*2) + case 10 < l && l <= 100: + return rand.Float64() * math.Log2(l*1.5) + case 100 < l && l <= 1000: + return rand.Float64() * (math.Log10(l*1.5) * 2) + case l > 1000: + return rand.Float64() * (math.Log10(l) * 2) + default: + return rand.Float64() + } +}