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 }