2017-11-03 18:01:49 +00:00
|
|
|
package sisyphus
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"math/rand"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2019-03-07 16:35:42 +00:00
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
|
2017-11-03 18:01:49 +00:00
|
|
|
"github.com/velour/catbase/bot"
|
|
|
|
"github.com/velour/catbase/bot/msg"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
BOULDER = ":full_moon:"
|
|
|
|
MOUNTAIN = ":new_moon:"
|
|
|
|
)
|
|
|
|
|
|
|
|
type SisyphusPlugin struct {
|
|
|
|
Bot bot.Bot
|
|
|
|
listenFor map[string]*game
|
|
|
|
}
|
|
|
|
|
|
|
|
type game struct {
|
|
|
|
id string
|
|
|
|
channel string
|
|
|
|
bot bot.Bot
|
|
|
|
who string
|
|
|
|
start time.Time
|
|
|
|
size int
|
|
|
|
current int
|
|
|
|
nextPush time.Time
|
|
|
|
nextDec time.Time
|
|
|
|
timers [2]*time.Timer
|
|
|
|
ended bool
|
|
|
|
nextAns int
|
|
|
|
}
|
|
|
|
|
2019-02-05 15:54:13 +00:00
|
|
|
func NewRandomGame(b bot.Bot, channel, who string) *game {
|
2017-11-03 18:01:49 +00:00
|
|
|
size := rand.Intn(9) + 2
|
|
|
|
g := game{
|
2017-11-06 19:32:49 +00:00
|
|
|
channel: channel,
|
2019-02-05 15:54:13 +00:00
|
|
|
bot: b,
|
2017-11-06 19:32:49 +00:00
|
|
|
who: who,
|
|
|
|
start: time.Now(),
|
|
|
|
size: size,
|
|
|
|
current: size / 2,
|
2017-11-03 18:01:49 +00:00
|
|
|
}
|
2019-02-05 18:33:18 +00:00
|
|
|
g.id, _ = b.Send(bot.Message, channel, g.toMessageString())
|
2017-11-03 18:01:49 +00:00
|
|
|
|
|
|
|
g.schedulePush()
|
|
|
|
g.scheduleDecrement()
|
|
|
|
|
|
|
|
return &g
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *game) scheduleDecrement() {
|
|
|
|
if g.timers[0] != nil {
|
|
|
|
g.timers[0].Stop()
|
|
|
|
}
|
2019-01-22 00:16:57 +00:00
|
|
|
minDec := g.bot.Config().GetInt("Sisyphus.MinDecrement", 10)
|
|
|
|
maxDec := g.bot.Config().GetInt("Sisyphus.MaxDecrement", 30)
|
2017-11-06 19:40:43 +00:00
|
|
|
g.nextDec = time.Now().Add(time.Duration((minDec + rand.Intn(maxDec))) * time.Minute)
|
2017-11-03 18:01:49 +00:00
|
|
|
go func() {
|
|
|
|
t := time.NewTimer(g.nextDec.Sub(time.Now()))
|
|
|
|
g.timers[0] = t
|
|
|
|
select {
|
|
|
|
case <-t.C:
|
|
|
|
g.handleDecrement()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *game) schedulePush() {
|
|
|
|
if g.timers[1] != nil {
|
|
|
|
g.timers[1].Stop()
|
|
|
|
}
|
2019-01-22 00:16:57 +00:00
|
|
|
minPush := g.bot.Config().GetInt("Sisyphus.MinPush", 1)
|
|
|
|
maxPush := g.bot.Config().GetInt("Sisyphus.MaxPush", 10)
|
2017-11-06 19:40:43 +00:00
|
|
|
g.nextPush = time.Now().Add(time.Duration(rand.Intn(maxPush)+minPush) * time.Minute)
|
2017-11-03 18:01:49 +00:00
|
|
|
go func() {
|
|
|
|
t := time.NewTimer(g.nextPush.Sub(time.Now()))
|
|
|
|
g.timers[1] = t
|
|
|
|
select {
|
|
|
|
case <-t.C:
|
|
|
|
g.handleNotify()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *game) endGame() {
|
|
|
|
for _, t := range g.timers {
|
|
|
|
t.Stop()
|
|
|
|
}
|
|
|
|
g.ended = true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *game) handleDecrement() {
|
|
|
|
g.current++
|
2019-02-05 15:54:13 +00:00
|
|
|
g.bot.Send(bot.Edit, g.channel, g.toMessageString(), g.id)
|
2017-11-03 18:01:49 +00:00
|
|
|
if g.current > g.size-2 {
|
2019-02-05 15:54:13 +00:00
|
|
|
g.bot.Send(bot.Reply, g.channel, "you lose", g.id)
|
2017-11-03 18:01:49 +00:00
|
|
|
msg := fmt.Sprintf("%s just lost the game after %s", g.who, time.Now().Sub(g.start))
|
2019-02-05 15:54:13 +00:00
|
|
|
g.bot.Send(bot.Message, g.channel, msg)
|
2017-11-03 18:01:49 +00:00
|
|
|
g.endGame()
|
|
|
|
} else {
|
|
|
|
g.scheduleDecrement()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *game) handleNotify() {
|
2019-02-05 15:54:13 +00:00
|
|
|
g.bot.Send(bot.Reply, g.channel, "You can push now.\n"+g.generateQuestion(), g.id)
|
2017-11-03 18:01:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (g *game) generateQuestion() string {
|
|
|
|
n1 := rand.Intn(99) + (rand.Intn(9)+1)*100
|
|
|
|
n2 := rand.Intn(99) + (rand.Intn(9)+1)*100
|
|
|
|
var op string
|
|
|
|
switch i := rand.Intn(3); i {
|
|
|
|
case 0:
|
|
|
|
// times
|
|
|
|
g.nextAns = n1 * n2
|
|
|
|
op = "*"
|
|
|
|
case 1:
|
|
|
|
// plus
|
|
|
|
g.nextAns = n1 + n2
|
|
|
|
op = "+"
|
|
|
|
case 2:
|
|
|
|
// minus
|
|
|
|
g.nextAns = n1 - n2
|
|
|
|
op = "-"
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("What is %d %s %d?", n1, op, n2)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *game) checkAnswer(ans string) bool {
|
|
|
|
if strings.Contains(ans, strconv.Itoa(g.nextAns)) {
|
|
|
|
g.current--
|
|
|
|
if g.current < 0 {
|
|
|
|
g.current = 0
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (g *game) toMessageString() string {
|
|
|
|
out := ""
|
|
|
|
for i := 0; i < g.size; i++ {
|
|
|
|
for j := 0; j < i; j++ {
|
|
|
|
out = out + MOUNTAIN
|
|
|
|
}
|
|
|
|
if i == g.current {
|
|
|
|
out = out + BOULDER
|
|
|
|
} else if i == g.current+1 {
|
|
|
|
out = out + ":" + g.who + ":"
|
|
|
|
}
|
|
|
|
out = out + "\n"
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(b bot.Bot) *SisyphusPlugin {
|
2019-02-05 19:41:38 +00:00
|
|
|
sp := &SisyphusPlugin{
|
2017-11-03 18:01:49 +00:00
|
|
|
Bot: b,
|
|
|
|
listenFor: map[string]*game{},
|
|
|
|
}
|
2019-02-05 19:41:38 +00:00
|
|
|
b.Register(sp, bot.Message, sp.message)
|
|
|
|
b.Register(sp, bot.Reply, sp.replyMessage)
|
|
|
|
b.Register(sp, bot.Help, sp.help)
|
|
|
|
return sp
|
2017-11-03 18:01:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-05 19:41:38 +00:00
|
|
|
func (p *SisyphusPlugin) message(kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
2017-11-03 18:01:49 +00:00
|
|
|
if strings.ToLower(message.Body) == "start sisyphus" {
|
|
|
|
b := NewRandomGame(p.Bot, message.Channel, message.User.Name)
|
|
|
|
p.listenFor[b.id] = b
|
2019-02-05 15:54:13 +00:00
|
|
|
p.Bot.Send(bot.Reply, message.Channel, "Over here.", b.id)
|
2017-11-03 18:01:49 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2019-02-05 19:41:38 +00:00
|
|
|
func (p *SisyphusPlugin) help(kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
|
|
|
p.Bot.Send(bot.Message, message.Channel, "https://en.wikipedia.org/wiki/Sisyphus")
|
|
|
|
return true
|
2017-11-03 18:01:49 +00:00
|
|
|
}
|
|
|
|
|
2019-02-05 19:41:38 +00:00
|
|
|
func (p *SisyphusPlugin) replyMessage(kind bot.Kind, message msg.Message, args ...interface{}) bool {
|
|
|
|
identifier := args[0].(string)
|
2019-01-22 00:16:57 +00:00
|
|
|
if strings.ToLower(message.User.Name) != strings.ToLower(p.Bot.Config().Get("Nick", "bot")) {
|
2017-11-03 18:01:49 +00:00
|
|
|
if g, ok := p.listenFor[identifier]; ok {
|
|
|
|
|
2019-03-07 16:35:42 +00:00
|
|
|
log.Debug().Msgf("got message on %s: %+v", identifier, message)
|
2017-11-03 18:01:49 +00:00
|
|
|
|
|
|
|
if g.ended {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if strings.ToLower(message.Body) == "end game" {
|
|
|
|
g.endGame()
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if time.Now().After(g.nextPush) {
|
|
|
|
if g.checkAnswer(message.Body) {
|
2019-02-05 15:54:13 +00:00
|
|
|
p.Bot.Send(bot.Edit, message.Channel, g.toMessageString(), identifier)
|
2017-11-03 18:01:49 +00:00
|
|
|
g.schedulePush()
|
|
|
|
msg := fmt.Sprintf("Ok. You can push again in %s", g.nextPush.Sub(time.Now()))
|
2019-02-05 15:54:13 +00:00
|
|
|
p.Bot.Send(bot.Reply, message.Channel, msg, identifier)
|
2017-11-03 18:01:49 +00:00
|
|
|
} else {
|
2019-02-05 15:54:13 +00:00
|
|
|
p.Bot.Send(bot.Reply, message.Channel, "you lose", identifier)
|
2017-11-03 18:01:49 +00:00
|
|
|
msg := fmt.Sprintf("%s just lost the sisyphus game after %s", g.who, time.Now().Sub(g.start))
|
2019-02-05 15:54:13 +00:00
|
|
|
p.Bot.Send(bot.Message, message.Channel, msg)
|
2017-11-03 18:01:49 +00:00
|
|
|
g.endGame()
|
|
|
|
}
|
|
|
|
} else {
|
2019-02-05 15:54:13 +00:00
|
|
|
p.Bot.Send(bot.Reply, message.Channel, "you cannot push yet", identifier)
|
2017-11-03 18:01:49 +00:00
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|