diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | preroll.go | 92 |
3 files changed, 94 insertions, 0 deletions
@@ -8,6 +8,7 @@ daemon hangman-helper maildups ord +preroll roll tempmon urldecode @@ -18,6 +18,7 @@ BINFILES = \ hangman-helper \ maildups \ ord \ + preroll \ roll \ tempmon \ urldecode \ diff --git a/preroll.go b/preroll.go new file mode 100644 index 0000000..ae9d5a3 --- /dev/null +++ b/preroll.go @@ -0,0 +1,92 @@ +/* Copyright (C) 2011, 2013-2014, 2017 Luke Shumaker <lukeshu@sbcglobal.net> */ +package main + +import ( + "math" + "fmt" + "os" + "regexp" + "strconv" + "strings" +) + +func usage() { + fmt.Printf("Usage: %s <SPECSLIST>...\n", os.Args[0]) + fmt.Println("SPECLIST = [-]SPEC[<<+|->SPEC>...]") + fmt.Println("SPEC = [<COUNT>]d<SIZE> | <MOD>") +} + +var parser = regexp.MustCompile("^(([0-9]*)d)?([0-9]+)$") + +func rollSpec(spec string) (mean float64, variance float64) { + parts := parser.FindStringSubmatch(spec) + if len(parts) < 4 { + usage() + os.Exit(1) + } + + if parts[1] == "" { + mean, _ := strconv.Atoi(parts[3]) + return float64(mean), 0 + } else { + dice, _ := strconv.Atoi(parts[2]) + die_size, _ := strconv.Atoi(parts[3]) + if dice < 1 { + dice = 1 + } + + // mean is E(X) + mean = float64(1 + die_size)/2.0 + + // sum is Σi² for i=1..die_size + sum := (die_size*(die_size+1)*(2*die_size+1))/6 + // mean2 is E(X²) + mean2 := float64(sum)/float64(die_size) + variance = mean2-(mean*mean) + + mean *= float64(dice) + variance *= float64(dice) + + return + } +} + +func roll(speclist string) { + var mean, variance float64 + + 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] + } + + _mean, _variance := rollSpec(spec) + if neg { + _mean = -_mean + } + mean += _mean + variance += _variance + + if sep < 0 { + break + } + neg = speclist[sep] == '-' + speclist = speclist[sep+1:] + } + + fmt.Printf("µ=%v σ=%.2v\n", mean, math.Sqrt(variance)) +} + +func main() { + if len(os.Args) < 2 { + usage() + } + for _, arg := range os.Args[1:] { + roll(arg) + } +} |