diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | go.mod | 3 | ||||
-rw-r--r-- | main.go | 62 |
3 files changed, 66 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e8b747f --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +roll @@ -0,0 +1,3 @@ +module bnbl.io/roll + +go 1.13 @@ -0,0 +1,62 @@ +package main + +import ( + "crypto/rand" + "fmt" + "math/big" + "os" + "strconv" + "strings" +) + +func main() { + if len(os.Args) != 2 { + fmt.Printf("usage: %s <die[+die...]>\n", os.Args[0]) + os.Exit(1) + } + dice := strings.Split(os.Args[1], "+") + var sum int64 + for _, die := range dice { + if result, err := resolve(die); err != nil { + fmt.Printf("%v\n", err) + os.Exit(1) + } else { + sum += result + } + } + fmt.Printf("%d\n", sum) +} + +func resolve(die string) (int64, error) { + // try parsing as a die e.g. 2d6 + var ( + num int + sides int64 + ) + if fields, err := fmt.Sscanf(die, "%dd%d", &num, &sides); err == nil && fields == 2 { + var sum int64 + for i := 0; i < num; i++ { + if r, err := roll(sides); err != nil { + return 0, err + } else { + sum += r + } + } + return sum, nil + } + + // try just parsing as a number, e.g. +5 + if x, err := strconv.Atoi(die); err != nil { + return 0, fmt.Errorf("unrecognized die: %s", die) + } else { + return int64(x), nil + } +} + +func roll(sides int64) (int64, error) { + r, err := rand.Int(rand.Reader, big.NewInt(sides)) + if err != nil { + return 0, err + } + return 1 + r.Int64(), nil +} |