catbase/plugins/quotegame/quotegame.go

160 lines
3.7 KiB
Go

package quotegame
import (
"fmt"
bh "github.com/timshannon/bolthold"
"github.com/velour/catbase/plugins/fact"
"math/rand"
"regexp"
"strings"
"time"
"github.com/rs/zerolog/log"
"github.com/velour/catbase/bot"
"github.com/velour/catbase/config"
)
type QuoteGame struct {
b bot.Bot
c *config.Config
store *bh.Store
handlers []bot.HandlerSpec
currentGame *time.Timer
currentName string
}
func New(b bot.Bot) *QuoteGame {
p := &QuoteGame{
b: b,
c: b.Config(),
store: b.Store(),
currentGame: nil,
}
p.register()
return p
}
func (p *QuoteGame) register() {
log.Debug().Msg("registering quote handlers")
p.handlers = []bot.HandlerSpec{
{
Kind: bot.Message, IsCmd: false,
Regex: regexp.MustCompile(`(?i)^quote game$`),
HelpText: "Start a quote game",
Handler: p.startGame,
},
{
Kind: bot.Message, IsCmd: false,
Regex: regexp.MustCompile(`(?i)^guess:\s?(?P<name>.+)$`),
Handler: p.guess,
},
}
p.b.RegisterTable(p, p.handlers)
}
type quote struct {
Fact string
Tidbit string
}
func (p *QuoteGame) getAllQuotes() ([]fact.Factoid, error) {
threshold := p.c.GetInt("quotegame.threshold", 10)
facts := []fact.Factoid{}
res, err := p.store.FindAggregate(fact.Factoid{},
bh.Where("Fact").RegExp(regexp.MustCompile(`.+\squotes$`)),
"Fact")
for _, group := range res {
if group.Count() > threshold {
// keep this group
//factName := ""
//group.Group(&factName)
fact := &fact.Factoid{}
group.Reduction(&fact)
facts = append(facts, *fact)
}
}
if err != nil {
return nil, err
}
return facts, nil
// todo: remove
//q := `select fact, tidbit from factoid where fact like '%quotes' group by fact having count(fact) > ?`
//quotes := []fact.Factoid{}
//err := p.store.Find(&quotes, bh.Where("Fact").RegExp(regexp.MustCompile(`.*quotes$`)))
//err := p.db.Select(&quotes, q, threshold)
//if err != nil {
// return nil, err
//}
//return quotes, nil
}
func (p *QuoteGame) getRandomquote() (string, string, error) {
quotes, err := p.getAllQuotes()
if err != nil {
return "", "", err
}
quote := quotes[rand.Intn(len(quotes))]
who := strings.ReplaceAll(quote.Fact, " quotes", "")
what := strings.ReplaceAll(quote.Tidbit, who, "")
what = strings.Trim(what, " <>")
return who, what, nil
}
func (p *QuoteGame) startGame(r bot.Request) bool {
log.Debug().Msg("startGame called")
if p.currentGame != nil {
p.b.Send(r.Conn, bot.Message, r.Msg.Channel, "There is already a quote game running.")
return true
}
who, quote, err := p.getRandomquote()
if err != nil {
log.Error().Err(err).Msg("problem getting quote")
p.b.Send(r.Conn, bot.Message, r.Msg.Channel, "Error: "+err.Error())
return true
}
length := time.Duration(p.c.GetInt("quotegame.length", 120))
p.currentGame = time.AfterFunc(length*time.Second, func() {
p.currentGame = nil
p.currentName = ""
p.b.Send(r.Conn, bot.Message, r.Msg.Channel,
fmt.Sprintf("The quote game ended and nobody won. The answer was %s", who))
})
p.currentName = who
msg := fmt.Sprintf("Quote game: Who said \"%s\"?\nYou have %d seconds to guess.\nUse `guess: name` to guess who.", quote, length)
p.b.Send(r.Conn, bot.Message, r.Msg.Channel, msg)
return true
}
func (p *QuoteGame) guess(r bot.Request) bool {
log.Debug().Msg("quote game message check")
if p.currentGame == nil {
return false
}
if r.Values["name"] == p.currentName {
msg := fmt.Sprintf("%s won the quote game!", r.Msg.User.Name)
p.b.Send(r.Conn, bot.Message, r.Msg.Channel, msg)
p.currentName = ""
p.currentGame.Stop()
p.currentGame = nil
return true
}
p.b.Send(r.Conn, bot.Message, r.Msg.Channel,
fmt.Sprintf("Sorry %s, that's not correct.", r.Msg.User.Name))
return true
}