matrix-bot/wordleimg/wordleimg.go
shinya 64b6e71b0e
Some checks failed
Deploy Matrix Bot / deploy (push) Waiting to run
Docker Build / build (push) Failing after 20m2s
new init without secrets
2026-03-04 22:00:42 +01:00

190 lines
4.3 KiB
Go

package wordleimg
import (
"bytes"
"strings"
"github.com/fogleman/gg"
)
type Theme struct {
BG string
Nah string
Not string
Nearly string
Good string
Txt string
}
var Themes = map[string]Theme{
"light": {
BG: "#d7dadc",
Nah: "#161618",
Not: "#3a3a3c",
Nearly: "#b59f3b",
Good: "#538d4e",
Txt: "#d7dadc",
},
"dark": {
BG: "#121213",
Nah: "#161618",
Not: "#3a3a3c",
Nearly: "#b59f3b",
Good: "#538d4e",
Txt: "#d7dadc",
},
"nixos": {
BG: "#121213",
Nah: "#161618",
Not: "#4C6eb5",
Nearly: "#f8ac0d",
Good: "#029839",
Txt: "#d7dadc",
},
"catppuccin": {
BG: "#1e1e2e",
Nah: "#313244",
Not: "#b4befe",
Nearly: "#cba6f7",
Good: "#a6e3a1",
Txt: "#6c7086",
},
"grayscale": {
BG: "#121213",
Nah: "#161618",
Not: "#202020",
Nearly: "#505050",
Good: "#a0a0a0",
Txt: "#f0f0f0",
},
"bloody": {
BG: "#121213",
Nah: "#161618",
Not: "#8B0000",
Nearly: "#ff4500",
Good: "#92ad32",
Txt: "#d7dadc",
},
}
const box float64 = 40 * 2
const boxEdge float64 = 4 * 2
const smallBox float64 = 25 * 2
const smallBoxEdge float64 = 2 * 2
const frameEdge float64 = 20 * 2
const round float64 = 4 * 2
var keyboard = []rune("QWERTYUIOPASDFGHJKLZXCVBNM")
var keyboardRows = []float64{0, 10, 19, 26}
var krMax float64 = 10
func RenderHistoryImage(history string, theme Theme, wordSize int, maxGuesses int) ([]byte, int, int, error) {
keyboardValidity := make([]rune, 128)
lines := strings.Split(history, "\n")
sus := max(float64(wordSize), krMax/(box/smallBox))
gc := gg.NewContext(
int((box*sus)+
(2*frameEdge)+((sus-1)*boxEdge)),
int(((box+boxEdge)*float64(maxGuesses))+
(2*frameEdge)+(3*(smallBox+smallBoxEdge))))
edging := ((box * sus) + ((sus - 1) * boxEdge) - (float64(wordSize)*box + (float64(wordSize)-1)*boxEdge)) / 2
gc.SetHexColor(theme.BG)
gc.Clear()
if err := gc.LoadFontFace("./wordleimg/static/Roboto_Condensed-Regular.ttf", 24*2); err != nil {
return nil, 0, 0, err
}
for i := 0.0; i < float64(maxGuesses); i++ {
if i < float64(len(lines)) && len(lines[int(i)]) >= wordSize*3 {
runes := []rune(lines[int(i)])
for n := 0.0; n < float64(wordSize); n++ {
switch runes[int(3*n)] {
case '[':
gc.SetHexColor(theme.Good)
keyboardValidity[runes[int(3*n+1)]] = 2
case '(':
gc.SetHexColor(theme.Nearly)
if keyboardValidity[runes[int(3*n+1)]] != 2 {
keyboardValidity[runes[int(3*n+1)]] = 1
}
case '.':
gc.SetHexColor(theme.Not)
keyboardValidity[runes[int(3*n+1)]] = -1
default:
gc.SetHexColor(theme.Nah)
}
gc.DrawRoundedRectangle(
edging+frameEdge+n*(box+boxEdge),
frameEdge+i*(box+boxEdge),
box, box, round)
gc.Fill()
gc.SetHexColor(theme.Txt)
gc.DrawStringAnchored(string(runes[int(3*n+1)]), edging+
frameEdge+n*(box+boxEdge)+(box/2),
frameEdge+i*(box+boxEdge)+(box/2),
0.5, 0.5)
}
} else {
for n := 0.0; n < float64(wordSize); n++ {
gc.SetHexColor(theme.Not)
gc.DrawRoundedRectangle(
edging+frameEdge+n*(box+boxEdge),
frameEdge+i*(box+boxEdge),
box, box, round)
gc.Fill()
gc.SetHexColor(theme.BG)
gc.DrawRoundedRectangle(
edging+frameEdge+n*(box+boxEdge)+boxEdge/2,
frameEdge+i*(box+boxEdge)+boxEdge/2,
box-boxEdge, box-boxEdge, round)
gc.Fill()
}
}
}
row := 1
for n := 0.0; n < float64(len(keyboard)); n++ {
switch keyboardValidity[keyboard[int(n)]] {
case 2:
gc.SetHexColor(theme.Good)
case 1:
gc.SetHexColor(theme.Nearly)
case 0:
gc.SetHexColor(theme.Not)
case -1:
gc.SetHexColor(theme.Nah)
}
corrector := (krMax - keyboardRows[row] + keyboardRows[row-1]) / 2.0
x := frameEdge + (n-keyboardRows[row-1]+corrector)*(smallBox+smallBoxEdge)
y := frameEdge + (box+boxEdge)*float64(maxGuesses) + smallBoxEdge + float64(row-1)*(smallBox+smallBoxEdge)
gc.DrawRoundedRectangle(x, y,
smallBox, smallBox, round)
gc.Fill()
gc.SetHexColor(theme.Txt)
gc.DrawStringAnchored(string(keyboard[int(n)]),
x+(smallBox/2),
y+(smallBox/2),
0.5, 0.5)
if int(n) == int(keyboardRows[row])-1 {
row++
}
}
var buf bytes.Buffer
err := gc.EncodePNG(&buf)
if err != nil {
return nil, 0, 0, err
}
return buf.Bytes(), gc.Width(), gc.Height(), nil
}