/* Copyright (C) 2011, 2013-2014, 2017 Luke Shumaker */ package main import ( "crypto/rand" "fmt" "math/big" "os" "regexp" "strconv" "strings" ) func usage() { fmt.Printf("Usage: %s ...\n", os.Args[0]) fmt.Println("SPECLIST = [-]SPEC[<<+|->SPEC>...]") fmt.Println("SPEC = []d | ") } func rollDie(size int) int { num, err := rand.Int(rand.Reader, big.NewInt(int64(size))) if err != nil { panic(err) } return int(num.Int64()) + 1 } var parser = regexp.MustCompile("^(([0-9]*)d)?([0-9]+)$") func rollSpec(spec string) (string, int) { parts := parser.FindStringSubmatch(spec) if len(parts) < 4 { usage() os.Exit(1) } var str string var num int if parts[1] == "" { str = parts[3] num, _ = strconv.Atoi(str) } else { dice, _ := strconv.Atoi(parts[2]) die_size, _ := strconv.Atoi(parts[3]) if dice < 1 { dice = 1 } var rolls []string for i := 0; i < dice; i++ { v := rollDie(die_size) rolls = append(rolls, strconv.Itoa(v)) num += v } str = "(" + strings.Join(rolls, "+") + ")" } return str, num } func roll(speclist string) { var strs []string var total int neg := strings.HasPrefix(speclist, "-") speclist = strings.TrimPrefix(speclist, "-") for { sep := strings.IndexAny(speclist, "+-") var spec string if sep < 0 { spec = speclist } else { spec = speclist[:sep] } str, num := rollSpec(spec) if neg { str = "-" + str num = -num } strs = append(strs, str) total += num if sep < 0 { break } neg = speclist[sep] == '-' speclist = speclist[sep+1:] } fmt.Printf("%s = %d\n", strings.Join(strs, " + "), total) } func main() { if len(os.Args) < 2 { usage() } for _, arg := range os.Args[1:] { roll(arg) } }