mirror of
https://github.com/tiennm99/tiennm99bot.git
synced 2026-10-14 06:18:06 +00:00
/wordle and /loldle now send the wordle and loldle BotFather games in an unlimited mode: each player gets their own word or champion, saved after every guess, with a New game button. Cards the bot did not record as unlimited, including the daily cards, play the daily puzzle. The helper commands keep working on the player's round. /loldledaily mirrors /wordledaily: one champion per day at 07:00 ICT, subscribe and unsubscribe, the morning recap and the live group results. The daily and unlimited machinery is shared in util/guessgame, the old in-chat wordle module is removed, and a one-time startup migration carries each player's stats and unfinished round over without changing old data.
67 lines
1.9 KiB
Go
67 lines
1.9 KiB
Go
package loldle
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/tiennm99/tiennm99bot/internal/storage"
|
|
)
|
|
|
|
// MaxGuesses is the default unlimited round length and the fixed daily one.
|
|
// /loldle_setmax overrides the unlimited length per chat, up to
|
|
// MaxGuessesCap.
|
|
const (
|
|
MaxGuesses = 8
|
|
MaxGuessesCap = 10
|
|
)
|
|
|
|
// roundConfig stores a chat's unlimited round length. Stored only when
|
|
// /loldle_setmax has been run; the absence of this record means "use
|
|
// default". The subject is the chat id in a group and the user id in a
|
|
// private chat.
|
|
type roundConfig struct {
|
|
MaxGuesses int `json:"maxGuesses" bson:"maxGuesses"`
|
|
}
|
|
|
|
// ConfigStore is the loldle module's typed config store.
|
|
type ConfigStore = storage.DocStore[roundConfig]
|
|
|
|
func configKey(subject string) string { return "config:" + subject }
|
|
|
|
func validMaxGuesses(n int) bool {
|
|
return n >= 1 && n <= MaxGuessesCap
|
|
}
|
|
|
|
func normalizeMaxGuesses(n int) int {
|
|
if validMaxGuesses(n) {
|
|
return n
|
|
}
|
|
return MaxGuesses
|
|
}
|
|
|
|
// getMaxGuesses returns the effective round length: the per-subject override
|
|
// if set and in range, otherwise MaxGuesses. Out-of-range values are
|
|
// silently ignored — better to serve the default than 500 the user.
|
|
func getMaxGuesses(ctx context.Context, cfg ConfigStore, subject string) (int, error) {
|
|
c, _, err := cfg.Get(ctx, configKey(subject))
|
|
if err != nil {
|
|
if errors.Is(err, storage.ErrNotFound) {
|
|
return MaxGuesses, nil
|
|
}
|
|
return 0, fmt.Errorf("loldle getMaxGuesses: %w", err)
|
|
}
|
|
return normalizeMaxGuesses(c.MaxGuesses), nil
|
|
}
|
|
|
|
// setMaxGuesses validates and persists the per-subject override.
|
|
func setMaxGuesses(ctx context.Context, cfg ConfigStore, subject string, n int) error {
|
|
if !validMaxGuesses(n) {
|
|
return fmt.Errorf("loldle: maxGuesses must be in [1, %d], got %d", MaxGuessesCap, n)
|
|
}
|
|
if err := cfg.Put(ctx, configKey(subject), roundConfig{MaxGuesses: n}); err != nil {
|
|
return fmt.Errorf("loldle setMaxGuesses: %w", err)
|
|
}
|
|
return nil
|
|
}
|