mirror of
https://github.com/FloatTech/ZeroBot-Plugin.git
synced 2025-12-19 13:59:39 +08:00
✨ 增加六阶七阶猜单词 (#140)
This commit is contained in:
parent
db6b558c75
commit
01e527abdb
@ -1,79 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
@ -3,6 +3,7 @@ package wordle
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"image/color"
|
"image/color"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"sort"
|
"sort"
|
||||||
@ -40,8 +41,19 @@ var colors = [...]color.RGBA{
|
|||||||
{219, 219, 219, 255},
|
{219, 219, 219, 255},
|
||||||
}
|
}
|
||||||
|
|
||||||
var words []string
|
var classdict = map[string]int{
|
||||||
var questions []string
|
"": 5,
|
||||||
|
"五阶": 5,
|
||||||
|
"六阶": 6,
|
||||||
|
"七阶": 7,
|
||||||
|
}
|
||||||
|
|
||||||
|
type dictionary map[int]struct {
|
||||||
|
dict []string
|
||||||
|
cet4 []string
|
||||||
|
}
|
||||||
|
|
||||||
|
var words = make(dictionary)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
en := control.Register("wordle", order.AcquirePrio(), &control.Options{
|
en := control.Register("wordle", order.AcquirePrio(), &control.Options{
|
||||||
@ -61,47 +73,50 @@ func init() {
|
|||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
go func() {
|
go func() {
|
||||||
questionsdata, err := file.GetLazyData(en.DataFolder()+"questions.bin", true, true)
|
for i := 5; i <= 7; i++ {
|
||||||
if err != nil {
|
dc, err := file.GetLazyData(fmt.Sprintf("%scet-4_%d.txt", en.DataFolder(), i), true, true)
|
||||||
panic(err)
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
c := strings.Split(string(dc), "\n")
|
||||||
|
sort.Strings(c)
|
||||||
|
dd, err := file.GetLazyData(fmt.Sprintf("%sdict_%d.txt", en.DataFolder(), i), true, true)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
d := strings.Split(string(dd), "\n")
|
||||||
|
sort.Strings(d)
|
||||||
|
words[i] = struct {
|
||||||
|
dict []string
|
||||||
|
cet4 []string
|
||||||
|
}{d, c}
|
||||||
}
|
}
|
||||||
questionspacks := loadwords(questionsdata)
|
|
||||||
questions = make([]string, len(questionspacks))
|
|
||||||
for i := range questionspacks {
|
|
||||||
questions[i] = questionspacks[i].String()
|
|
||||||
}
|
|
||||||
wordsdata, err := file.GetLazyData(en.DataFolder()+"words.bin", true, true)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
wordpacks := loadwords(wordsdata)
|
|
||||||
words = make([]string, len(wordpacks))
|
|
||||||
for i := range wordpacks {
|
|
||||||
words[i] = wordpacks[i].String()
|
|
||||||
}
|
|
||||||
sort.Strings(words)
|
|
||||||
}()
|
}()
|
||||||
en.OnRegex(`(个人|团队)猜单词`, zero.OnlyGroup).SetBlock(true).Limit(ctxext.LimitByUser).
|
en.OnRegex(`(个人|团队)(五阶|六阶|七阶)?猜单词`, zero.OnlyGroup).SetBlock(true).Limit(ctxext.LimitByUser).
|
||||||
Handle(func(ctx *zero.Ctx) {
|
Handle(func(ctx *zero.Ctx) {
|
||||||
target := questions[rand.Intn(len(questions))]
|
class := classdict[ctx.State["regex_matched"].([]string)[2]]
|
||||||
|
target := words[class].cet4[rand.Intn(len(words[class].cet4))]
|
||||||
game := newWordleGame(target)
|
game := newWordleGame(target)
|
||||||
_, img, cl, _ := game("")
|
_, img, cl, _ := game("")
|
||||||
typ := ctx.State["regex_matched"].([]string)[1]
|
|
||||||
ctx.Send(
|
ctx.Send(
|
||||||
message.ReplyWithMessage(ctx.Event.MessageID,
|
message.ReplyWithMessage(ctx.Event.MessageID,
|
||||||
message.ImageBytes(img),
|
message.ImageBytes(img),
|
||||||
message.Text("你有6次机会猜出单词,单词长度为5,请发送单词"),
|
message.Text("你有", class+1, "次机会猜出单词,单词长度为", class, ",请发送单词"),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
cl()
|
cl()
|
||||||
var next *zero.FutureEvent
|
var next *zero.FutureEvent
|
||||||
if typ == "个人" {
|
if ctx.State["regex_matched"].([]string)[1] == "个人" {
|
||||||
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^[A-Z]{5}$|^[a-z]{5}$`), zero.OnlyGroup, zero.CheckUser(ctx.Event.UserID))
|
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(fmt.Sprintf(`^([A-Z]|[a-z]){%d}$`, class)),
|
||||||
|
zero.OnlyGroup, zero.CheckUser(ctx.Event.UserID))
|
||||||
} else {
|
} else {
|
||||||
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(`^[A-Z]{5}$|^[a-z]{5}$`), zero.OnlyGroup, zero.CheckGroup(ctx.Event.GroupID))
|
next = zero.NewFutureEvent("message", 999, false, zero.RegexRule(fmt.Sprintf(`^([A-Z]|[a-z]){%d}$`, class)),
|
||||||
|
zero.OnlyGroup, zero.CheckGroup(ctx.Event.GroupID))
|
||||||
}
|
}
|
||||||
var win bool
|
var win bool
|
||||||
var err error
|
var err error
|
||||||
|
recv, cancel := next.Repeat()
|
||||||
|
defer cancel()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-time.After(time.Second * 120):
|
case <-time.After(time.Second * 120):
|
||||||
@ -111,7 +126,7 @@ func init() {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
case e := <-next.Next():
|
case e := <-recv:
|
||||||
win, img, cl, err = game(e.Message.String())
|
win, img, cl, err = game(e.Message.String())
|
||||||
switch {
|
switch {
|
||||||
case win:
|
case win:
|
||||||
@ -158,6 +173,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newWordleGame(target string) func(string) (bool, []byte, func(), error) {
|
func newWordleGame(target string) func(string) (bool, []byte, func(), error) {
|
||||||
|
var class = len(target)
|
||||||
record := make([]string, 0, len(target)+1)
|
record := make([]string, 0, len(target)+1)
|
||||||
return func(s string) (win bool, data []byte, cl func(), err error) {
|
return func(s string) (win bool, data []byte, cl func(), err error) {
|
||||||
if s != "" {
|
if s != "" {
|
||||||
@ -169,8 +185,8 @@ func newWordleGame(target string) func(string) (bool, []byte, func(), error) {
|
|||||||
err = errLengthNotEnough
|
err = errLengthNotEnough
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
i := sort.SearchStrings(words, s)
|
i := sort.SearchStrings(words[class].dict, s)
|
||||||
if i >= len(words) || words[i] != s {
|
if i >= len(words[class].dict) || words[class].dict[i] != s {
|
||||||
err = errUnknownWord
|
err = errUnknownWord
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -181,13 +197,14 @@ func newWordleGame(target string) func(string) (bool, []byte, func(), error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
var side = 20
|
var side = 20
|
||||||
ctx := gg.NewContext((side+2)*5+26, (side+2)*6+26)
|
var space = 10
|
||||||
|
ctx := gg.NewContext((side+4)*class+space*2-4, (side+4)*(class+1)+space*2-4)
|
||||||
ctx.SetColor(color.RGBA{255, 255, 255, 255})
|
ctx.SetColor(color.RGBA{255, 255, 255, 255})
|
||||||
ctx.Clear()
|
ctx.Clear()
|
||||||
for i := 0; i < len(target)+1; i++ {
|
for i := 0; i < class+1; i++ {
|
||||||
for j := 0; j < len(target); j++ {
|
for j := 0; j < class; j++ {
|
||||||
if len(record) > i {
|
if len(record) > i {
|
||||||
ctx.DrawRectangle(float64(10+j*(side+4)), float64(10+i*(side+4)), float64(side), float64(side))
|
ctx.DrawRectangle(float64(space+j*(side+4)), float64(space+i*(side+4)), float64(side), float64(side))
|
||||||
switch {
|
switch {
|
||||||
case record[i][j] == target[j]:
|
case record[i][j] == target[j]:
|
||||||
ctx.SetColor(colors[match])
|
ctx.SetColor(colors[match])
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user