210 lines
5.4 KiB
Go
210 lines
5.4 KiB
Go
package bot
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"log"
|
|
"matrix-bot/game"
|
|
"matrix-bot/wordleimg"
|
|
"matrix-bot/words"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"maunium.net/go/mautrix"
|
|
"maunium.net/go/mautrix/event"
|
|
)
|
|
|
|
var dict *words.Dictionary
|
|
|
|
type roomUserPair struct {
|
|
room string
|
|
user string
|
|
}
|
|
|
|
var wordleGames = make(map[roomUserPair]game.Wordle)
|
|
var userSettings = make(map[string]map[string]string)
|
|
|
|
var defaultSettings = map[string]string{
|
|
"wordletheme": "dark",
|
|
}
|
|
|
|
func Load() {
|
|
var err error
|
|
wordListPath := os.Getenv("MATRIX_WORDLIST")
|
|
if wordListPath == "" {
|
|
wordListPath = "sowpods.csv"
|
|
}
|
|
dict, err = words.New(wordListPath)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func HandleCommand(body string, sender string, roomID string,
|
|
ctx context.Context, client *mautrix.Client, evt *event.Event, replyTo *event.RelatesTo) []interface{} {
|
|
pair := roomUserPair{roomID, sender}
|
|
part := strings.Fields(strings.ToLower(body))
|
|
|
|
_, e := userSettings[sender]
|
|
if !e {
|
|
userSettings[sender] = make(map[string]string)
|
|
for key, value := range defaultSettings {
|
|
userSettings[sender][key] = value
|
|
}
|
|
}
|
|
us := userSettings[sender]
|
|
|
|
if equals(part[0], "!settings", "!setts", "!stns", "!?") {
|
|
if len(part) < 2 {
|
|
} else if equals(part[1], "set", "add", "s", "a") {
|
|
if len(part) == 4 {
|
|
userSettings[sender][part[2]] = part[3]
|
|
us = userSettings[sender]
|
|
}
|
|
} else if equals(part[1], "delete", "del", "remove", "rem", "d", "r") {
|
|
if len(part) == 3 {
|
|
delete(userSettings[sender], part[2])
|
|
}
|
|
}
|
|
b := strings.Builder{}
|
|
b.WriteString("Your settings: ")
|
|
for k, s := range us {
|
|
b.WriteString("\n" + k + " : " + s)
|
|
}
|
|
return jia(txt(b.String(), replyTo))
|
|
} else if equals(part[0], "!wordle", "!wrdl", "!w") {
|
|
wg, wgEx := wordleGames[pair]
|
|
wordleState := func() event.MessageEventContent {
|
|
state := wg.GetState()
|
|
if setting(us, "wordletheme") == "ascii" {
|
|
return txt(state, nil)
|
|
} else {
|
|
theme, e := wordleimg.Themes[setting(us, "wordletheme")]
|
|
if !e {
|
|
theme = wordleimg.Themes["dark"]
|
|
}
|
|
imgData, w, h, err := wordleimg.RenderHistoryImage(state, theme, len(wg.GetSecret()), 6)
|
|
if err != nil {
|
|
log.Println("Image render error:", err)
|
|
}
|
|
return img(imgData, w, h, state, ctx, client)
|
|
}
|
|
}
|
|
if len(part) < 2 {
|
|
part = append(part, "daily")
|
|
}
|
|
if equals(part[1], "daily", "day", "d") {
|
|
if wgEx {
|
|
return jia(txt("Wordle:\nAlready exist", replyTo))
|
|
}
|
|
word := dict.DailyWord(5)
|
|
wordleGames[pair] = game.NewWordle(word, 6)
|
|
return jia(txt("Wordle:\nDaily started ("+roomID+" "+sender+")\nLength: "+
|
|
strconv.Itoa(len(word))+"\n[CAN BE PLAYED ONCE A DAY, DO NOT END!]", replyTo))
|
|
} else if equals(part[1], "normal", "play", "p") {
|
|
if wgEx {
|
|
return jia(txt("Wordle:\nAlready exist", replyTo))
|
|
}
|
|
length := 5
|
|
if len(part) > 2 {
|
|
if l, err := strconv.Atoi(part[2]); err == nil {
|
|
length = l
|
|
}
|
|
}
|
|
word, err := dict.RandomWord(length)
|
|
if err != nil {
|
|
return jia(txt("Wordle:\nNo words of that length", replyTo))
|
|
}
|
|
wordleGames[pair] = game.NewWordle(word, 6)
|
|
return jia(txt("Wordle:\nInitilized ("+roomID+" "+sender+")\nLength: "+strconv.Itoa(length), replyTo))
|
|
} else if equals(part[1], "guess", "gus", "g") && len(part) > 2 {
|
|
if !wgEx {
|
|
return jia(txt("Wordle:\nNot found (use !wordle play)", replyTo))
|
|
} else if !wg.ValidLength(part[2]) {
|
|
return jia(txt("Wordle:\nWord guess length is bad", replyTo))
|
|
} else if !dict.Contains(part[2]) {
|
|
return jia(txt("Wordle:\nSorry but idk that word", replyTo))
|
|
}
|
|
sig := wg.Guess(part[2])
|
|
if sig == 0 {
|
|
return jia(txt("Wordle:", replyTo), wordleState())
|
|
}
|
|
delete(wordleGames, pair)
|
|
switch sig {
|
|
case -1:
|
|
return jia(txt("Wordle:\nEnded in lost, word was "+wg.GetSecret(), replyTo), wordleState())
|
|
case 1:
|
|
return jia(txt("Wordle:\nYou guessed right!", replyTo), wordleState())
|
|
}
|
|
} else if equals(part[1], "status", "stat", "s") {
|
|
if !wgEx {
|
|
return jia(txt("Wordle:\nNone found", replyTo))
|
|
}
|
|
return jia(txt("Wordle:", replyTo), wordleState())
|
|
} else if equals(part[1], "forfit", "end", "e") {
|
|
if !wgEx {
|
|
return jia(txt("Wordle:\nNone to end", replyTo))
|
|
}
|
|
delete(wordleGames, pair)
|
|
return jia(txt("Wordle:\nEnded", replyTo))
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func jia(i ...interface{}) []interface{} {
|
|
return i
|
|
}
|
|
|
|
func txt(body string, relates *event.RelatesTo) event.MessageEventContent {
|
|
return event.MessageEventContent{
|
|
MsgType: event.MsgText,
|
|
Body: body,
|
|
RelatesTo: relates,
|
|
}
|
|
}
|
|
|
|
func img(data []byte, width int, height int, body string, ctx context.Context, client *mautrix.Client) event.MessageEventContent {
|
|
uploadResp, err := client.UploadMedia(
|
|
ctx,
|
|
mautrix.ReqUploadMedia{
|
|
FileName: "temp.png",
|
|
Content: bytes.NewReader(data),
|
|
ContentType: "image/png",
|
|
},
|
|
)
|
|
if err != nil {
|
|
log.Println("Upload error:", err)
|
|
return event.MessageEventContent{}
|
|
}
|
|
|
|
return event.MessageEventContent{
|
|
MsgType: event.MsgImage,
|
|
Body: body,
|
|
URL: uploadResp.ContentURI.CUString(),
|
|
Info: &event.FileInfo{
|
|
MimeType: "image/png",
|
|
Size: len(data),
|
|
Height: height,
|
|
Width: width,
|
|
},
|
|
}
|
|
}
|
|
|
|
func setting(us map[string]string, key string) string {
|
|
if v, e := us[key]; e {
|
|
return v
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func equals(body string, prefixes ...string) bool {
|
|
for _, prefix := range prefixes {
|
|
if strings.Compare(body, prefix) == 0 {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|