summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile1
-rw-r--r--preroll.go92
3 files changed, 94 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 44ed24a..ef072ec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,6 +8,7 @@ daemon
hangman-helper
maildups
ord
+preroll
roll
tempmon
urldecode
diff --git a/Makefile b/Makefile
index b2178d4..214a903 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
+ }
+}