twitch-bot-tools/dice/main.go

123 lines
3 KiB
Go
Raw Normal View History

package main
import (
"bytes"
"crypto/rand"
"encoding/json"
"fmt"
"math/big"
"os"
"text/template"
log "github.com/sirupsen/logrus"
"github.com/Luzifer/rconfig/v2"
"github.com/Luzifer/twitch-bot/v3/plugins"
)
var (
cfg = struct {
BotRespond bool `flag:"bot-respond,b" default:"false" description:"Wrap output in a respond directive for twitch-bot"`
Count int64 `flag:"count,c" default:"1" description:"How many dice to throw?"`
LogLevel string `flag:"log-level" default:"info" description:"Log level (debug, info, warn, error, fatal)"`
Sides int64 `flag:"sides,s" default:"6" description:"How many sides does the dice have?"`
Template string `flag:"template" vardefault:"tpl" description:"Template to format the result with"`
Type string `flag:"type,t" default:"dice" description:"What to throw (coin, dice)"`
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
}{}
version = "dev"
)
func init() {
rconfig.AutoEnv(true)
rconfig.SetVariableDefaults(map[string]string{
"tpl": `I threw {{.count}}x {{if eq .type "coin"}}coin{{else}}W{{.sides}}{{end}} for you and got:{{ range .results}} {{ if eq $.type "coin" }}{{ if eq . 1 }}Head{{ else }}Number{{ end }}{{ else }}{{ . }}{{ end }}{{ end }}`,
})
if err := rconfig.ParseAndValidate(&cfg); err != nil {
log.Fatalf("Unable to parse commandline options: %s", err)
}
if cfg.VersionAndExit {
fmt.Printf("dice %s\n", version)
os.Exit(0)
}
if l, err := log.ParseLevel(cfg.LogLevel); err != nil {
log.WithError(err).Fatal("Unable to parse log level")
} else {
log.SetLevel(l)
}
}
func main() {
var (
results []int64
sum int64
)
switch cfg.Type {
case "coin":
results, sum = getResults(2, cfg.Count)
case "dice":
if cfg.Sides == 0 {
// There is no [0..0] dice.
log.Fatal("There is no 0-sided dice")
}
results, sum = getResults(cfg.Sides, cfg.Count)
default:
log.WithField("type", cfg.Type).Fatal("Don't know how to throw that")
}
t, err := template.New("output").Parse(cfg.Template)
if err != nil {
log.WithError(err).Fatal("Unable to parse template")
}
text := new(bytes.Buffer)
if err = t.Execute(text, map[string]interface{}{
"count": cfg.Count,
"results": results,
"sides": cfg.Sides,
"sum": sum,
"type": cfg.Type,
}); err != nil {
log.WithError(err).Fatal("Unable to execute template")
}
if !cfg.BotRespond {
fmt.Println(text.String())
return
}
output := []plugins.RuleAction{
{
Type: "respond",
Attributes: plugins.FieldCollectionFromData(map[string]any{
"message": text.String(),
}),
},
}
if err = json.NewEncoder(os.Stdout).Encode(output); err != nil {
log.WithError(err).Fatal("Unable to encode bot response")
}
}
func getRandomNumber(sides int64) int64 {
n, _ := rand.Int(rand.Reader, big.NewInt(sides))
return n.Int64()
}
func getResults(sides, count int64) (res []int64, sum int64) {
for i := int64(0); i < count; i++ {
v := getRandomNumber(sides) + 1
res = append(res, v)
sum += v
}
return res, sum
}