123 lines
3 KiB
Go
123 lines
3 KiB
Go
|
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
|
||
|
}
|