/* Copyright (C) 2011, 2013-2014, 2017 Luke Shumaker */ package main import ( "math" "fmt" "os" "regexp" "strconv" "strings" ) func usage() { fmt.Printf("Usage: %s ...\n", os.Args[0]) fmt.Println("SPECLIST = [-]SPEC[<<+|->SPEC>...]") fmt.Println("SPEC = []d | ") } 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) } }