1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
/* Copyright (C) 2011, 2013-2014, 2017, 2019 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
}
// - Let 'd' be the die_size
// - Let 'X' be the the uniform random variable that is the result of a 1d${d} roll
// - E(X) = (1+d)/2
mean = float64(1 + die_size)/2.0
// - Var(X) = E(X²)-E(X)²
// - E(X²) = (Σi² for i=1..d) / d
// = ¹/₆d(d+1)(2d+1) / d
// = d(d+1)(2d+1) / (6d)
// ∴ Var(X) = (d(d+1)(2d+1) / (6d)) - ((1+d)/2)²
// = ¹/₁₂(d+1)(d-1)
variance = float64((die_size+1)*(die_size-1))/12.0
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)
}
}
|