mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2025-12-19 13:59:39 +08:00
✨ 🎨 🔥 优化代码结构
This commit is contained in:
parent
eaad8beb7b
commit
3838d74cb8
2
data
2
data
@ -1 +1 @@
|
|||||||
Subproject commit 431911b8755799e61f096c7853a05731743f3761
|
Subproject commit 349cde86290220b8fb3f2bc957d1be58b68c852c
|
||||||
77
plugin_wordle/pack.go
Normal file
77
plugin_wordle/pack.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
package wordle
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"unsafe"
|
||||||
|
|
||||||
|
goBinary "encoding/binary"
|
||||||
|
|
||||||
|
"github.com/FloatTech/zbputils/binary"
|
||||||
|
)
|
||||||
|
|
||||||
|
type wordpack [3]byte
|
||||||
|
|
||||||
|
func pack(word string) (w wordpack) {
|
||||||
|
if len(word) != 5 {
|
||||||
|
panic("word must be 5 letters")
|
||||||
|
}
|
||||||
|
r := []rune(word)
|
||||||
|
for i := range r {
|
||||||
|
if r[i] < 'k' { // 0-9
|
||||||
|
r[i] -= 'a' - '0'
|
||||||
|
} else {
|
||||||
|
r[i] -= 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
word = string(r)
|
||||||
|
n, err := strconv.ParseUint(word, 26, 32)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
wt := binary.SelectWriter()
|
||||||
|
wt.WriteUInt32LE(uint32(n))
|
||||||
|
copy(w[:], wt.Bytes())
|
||||||
|
binary.PutWriter(wt)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w wordpack) String() (word string) {
|
||||||
|
wt := binary.SelectWriter()
|
||||||
|
wt.Write(w[:])
|
||||||
|
wt.WriteByte(0)
|
||||||
|
n := goBinary.LittleEndian.Uint32(wt.Bytes())
|
||||||
|
binary.PutWriter(wt)
|
||||||
|
word = strconv.FormatUint(uint64(n), 26)
|
||||||
|
for len(word) < 5 {
|
||||||
|
word = "0" + word
|
||||||
|
}
|
||||||
|
r := []rune(word)
|
||||||
|
for i := range r {
|
||||||
|
if r[i] < 'a' { // 0-9
|
||||||
|
r[i] += 'a' - '0'
|
||||||
|
} else {
|
||||||
|
r[i] += 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
word = string(r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadwords(data []byte) (wordpacks []wordpack) {
|
||||||
|
(*slice)(unsafe.Pointer(&wordpacks)).data = (*slice)(unsafe.Pointer(&data)).data
|
||||||
|
(*slice)(unsafe.Pointer(&wordpacks)).len = len(data) / 3
|
||||||
|
(*slice)(unsafe.Pointer(&wordpacks)).cap = (*slice)(unsafe.Pointer(&data)).cap / 3
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// slice is the runtime representation of a slice.
|
||||||
|
// It cannot be used safely or portably and its representation may
|
||||||
|
// change in a later release.
|
||||||
|
//
|
||||||
|
// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the
|
||||||
|
// data it references will not be garbage collected.
|
||||||
|
type slice struct {
|
||||||
|
data unsafe.Pointer
|
||||||
|
len int
|
||||||
|
cap int
|
||||||
|
}
|
||||||
@ -2,26 +2,28 @@
|
|||||||
package wordle
|
package wordle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"image/color"
|
"image/color"
|
||||||
"image/png"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"sort"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/FloatTech/zbputils/binary"
|
||||||
"github.com/FloatTech/zbputils/control"
|
"github.com/FloatTech/zbputils/control"
|
||||||
"github.com/FloatTech/zbputils/control/order"
|
"github.com/FloatTech/zbputils/control/order"
|
||||||
"github.com/FloatTech/zbputils/ctxext"
|
"github.com/FloatTech/zbputils/ctxext"
|
||||||
|
"github.com/FloatTech/zbputils/file"
|
||||||
|
"github.com/FloatTech/zbputils/img/writer"
|
||||||
"github.com/fogleman/gg"
|
"github.com/fogleman/gg"
|
||||||
zero "github.com/wdvxdr1123/ZeroBot"
|
zero "github.com/wdvxdr1123/ZeroBot"
|
||||||
"github.com/wdvxdr1123/ZeroBot/message"
|
"github.com/wdvxdr1123/ZeroBot/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
var errLengthNotEnough = errors.New("length not enough")
|
var (
|
||||||
var errUnknownWord = errors.New("unknown word")
|
errLengthNotEnough = errors.New("length not enough")
|
||||||
var errTimesRunOut = errors.New("times run out")
|
errUnknownWord = errors.New("unknown word")
|
||||||
|
errTimesRunOut = errors.New("times run out")
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
match = iota
|
match = iota
|
||||||
@ -30,80 +32,98 @@ const (
|
|||||||
undone
|
undone
|
||||||
)
|
)
|
||||||
|
|
||||||
var colormap = map[int]color.RGBA{
|
var colors = [...]color.RGBA{
|
||||||
0: {125, 166, 108, 255},
|
{125, 166, 108, 255},
|
||||||
1: {199, 183, 96, 255},
|
{199, 183, 96, 255},
|
||||||
2: {123, 123, 123, 255},
|
{123, 123, 123, 255},
|
||||||
3: {219, 219, 219, 255},
|
{219, 219, 219, 255},
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
var words []wordpack
|
||||||
sort.Strings(words)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
control.Register("wordle", order.AcquirePrio(), &control.Options{
|
en := control.Register("wordle", order.AcquirePrio(), &control.Options{
|
||||||
DisableOnDefault: false,
|
DisableOnDefault: false,
|
||||||
Help: "猜单词\n" +
|
Help: "猜单词\n" +
|
||||||
"- 开始猜单词",
|
"- 开始猜单词",
|
||||||
}).OnFullMatch("猜单词").SetBlock(true).Limit(ctxext.LimitByUser).
|
PublicDataFolder: "Wordle",
|
||||||
|
})
|
||||||
|
go func() {
|
||||||
|
data, err := file.GetLazyData(en.DataFolder()+"words.bin", true, true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
words = loadwords(data)
|
||||||
|
}()
|
||||||
|
en.OnFullMatch("猜单词").SetBlock(true).Limit(ctxext.LimitByUser).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
game := wordle(words)
|
game := newWordleGame()
|
||||||
_, img, _ := game("")
|
_, img, _ := game("")
|
||||||
ctx.SendChain(message.ImageBytes(img), message.Text("请发送单词"))
|
ctx.SendChain(message.Image("base64://"+binary.BytesToString(img)), message.Text("请发送单词"))
|
||||||
// 没有图片就索取
|
// 没有图片就索取
|
||||||
next := zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^[A-Z]{5}$|^[a-z]{5}$`))
|
next := zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^[A-Z]{5}$|^[a-z]{5}$`))
|
||||||
recv, cancel := next.Repeat()
|
recv, cancel := next.Repeat()
|
||||||
defer cancel()
|
var msg message.Message
|
||||||
|
defer func() {
|
||||||
|
cancel()
|
||||||
|
ctx.Send(msg)
|
||||||
|
}()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-time.After(time.Second * 120):
|
case <-time.After(time.Second * 120):
|
||||||
return
|
return
|
||||||
case e := <-recv:
|
case e := <-recv:
|
||||||
win, img, err := game(e.Message.String())
|
win, img, err := game(e.Message.String())
|
||||||
if err == errLengthNotEnough {
|
msg = []message.MessageSegment{message.Image("base64://" + binary.BytesToString(img))}
|
||||||
ctx.SendChain(message.ImageBytes(img), message.Text("单词长度错误"))
|
switch err {
|
||||||
}
|
case nil:
|
||||||
if err == errUnknownWord {
|
|
||||||
ctx.SendChain(message.ImageBytes(img), message.Text("不存在这样的单词"))
|
|
||||||
}
|
|
||||||
if win {
|
if win {
|
||||||
ctx.SendChain(message.ImageBytes(img), message.Text("你赢了"))
|
msg = append(msg, message.Text("你赢了"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err == errTimesRunOut {
|
case errLengthNotEnough:
|
||||||
ctx.SendChain(message.ImageBytes(img), message.Text("你输了"))
|
msg = append(msg, message.Text("单词长度错误"))
|
||||||
|
case errUnknownWord:
|
||||||
|
msg = append(msg, message.Text("不存在这样的单词"))
|
||||||
|
case errTimesRunOut:
|
||||||
|
msg = append(msg, message.Text("你输了"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx.SendChain(message.ImageBytes(img))
|
ctx.Send(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func wordle(words []string) func(string) (bool, []byte, error) {
|
func newWordleGame() func(string) (bool, []byte, error) {
|
||||||
rand.Seed(time.Now().UnixMilli())
|
onhandpack := words[rand.Intn(len(words))]
|
||||||
index := rand.Intn(len(words))
|
onhand := onhandpack.String()
|
||||||
onhand := words[index]
|
|
||||||
record := make([]string, 0, len(onhand)+1)
|
record := make([]string, 0, len(onhand)+1)
|
||||||
return func(s string) (win bool, image []byte, err error) {
|
return func(s string) (win bool, base64Image []byte, err error) {
|
||||||
if s != "" {
|
if s != "" {
|
||||||
s = strings.ToLower(s)
|
s = strings.ToLower(s)
|
||||||
if onhand == s {
|
sp := pack(s)
|
||||||
|
if onhandpack == sp {
|
||||||
win = true
|
win = true
|
||||||
} else {
|
} else {
|
||||||
if len(s) != len(onhand) {
|
if len(s) != len(onhand) {
|
||||||
err = errLengthNotEnough
|
err = errLengthNotEnough
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := sort.SearchStrings(words, s)
|
i := 0
|
||||||
if i >= len(words) || words[i] != s {
|
for ; i < len(words); i++ {
|
||||||
|
if words[i] == sp {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i >= len(words) || words[i] != sp {
|
||||||
err = errUnknownWord
|
err = errUnknownWord
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(record) >= cap(record) {
|
if len(record) >= cap(record) {
|
||||||
err = errTimesRunOut
|
err = errTimesRunOut
|
||||||
|
return
|
||||||
}
|
}
|
||||||
record = append(record, s)
|
record = append(record, s)
|
||||||
}
|
}
|
||||||
@ -117,11 +137,11 @@ func wordle(words []string) func(string) (bool, []byte, error) {
|
|||||||
ctx.DrawRectangle(float64(10+j*(side+4)), float64(10+i*(side+4)), float64(side), float64(side))
|
ctx.DrawRectangle(float64(10+j*(side+4)), float64(10+i*(side+4)), float64(side), float64(side))
|
||||||
switch {
|
switch {
|
||||||
case record[i][j] == onhand[j]:
|
case record[i][j] == onhand[j]:
|
||||||
ctx.SetColor(colormap[match])
|
ctx.SetColor(colors[match])
|
||||||
case strings.IndexByte(onhand, record[i][j]) != -1:
|
case strings.IndexByte(onhand, record[i][j]) != -1:
|
||||||
ctx.SetColor(colormap[exist])
|
ctx.SetColor(colors[exist])
|
||||||
default:
|
default:
|
||||||
ctx.SetColor(colormap[notexist])
|
ctx.SetColor(colors[notexist])
|
||||||
}
|
}
|
||||||
ctx.Fill()
|
ctx.Fill()
|
||||||
ctx.SetColor(color.RGBA{255, 255, 255, 255})
|
ctx.SetColor(color.RGBA{255, 255, 255, 255})
|
||||||
@ -129,13 +149,12 @@ func wordle(words []string) func(string) (bool, []byte, error) {
|
|||||||
} else {
|
} else {
|
||||||
ctx.DrawRectangle(float64(10+j*(side+4)+1), float64(10+i*(side+4)+1), float64(side-2), float64(side-2))
|
ctx.DrawRectangle(float64(10+j*(side+4)+1), float64(10+i*(side+4)+1), float64(side-2), float64(side-2))
|
||||||
ctx.SetLineWidth(1)
|
ctx.SetLineWidth(1)
|
||||||
ctx.SetColor(colormap[undone])
|
ctx.SetColor(colors[undone])
|
||||||
ctx.Stroke()
|
ctx.Stroke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
buf := bytes.NewBuffer(make([]byte, 0))
|
base64Image, err = writer.ToBase64(ctx.Image())
|
||||||
_ = png.Encode(buf, ctx.Image())
|
return
|
||||||
return win, buf.Bytes(), err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15924
plugin_wordle/words.go
15924
plugin_wordle/words.go
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user