167 lines
2.8 KiB
Go
167 lines
2.8 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"fmt"
|
|
"math/big"
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
func globalRand(n int) int {
|
|
r, err := rand.Int(rand.Reader, big.NewInt(int64(n)))
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return int(r.Int64())
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) == 0 {
|
|
panic("No arguments (d2, d4, d6, d8, d10, d12, d20, d100)")
|
|
}
|
|
die := os.Args[1]
|
|
rolls := 1
|
|
|
|
if len(os.Args) == 3 {
|
|
r, err := strconv.Atoi(os.Args[2])
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
if r < 1 {
|
|
panic("Cannot roll fewer than 1 times")
|
|
}
|
|
|
|
rolls = r
|
|
}
|
|
|
|
var dieFunc func() int
|
|
var critGood = []int{}
|
|
var critBad = []int{}
|
|
var critNeut = []int{}
|
|
switch die {
|
|
case "d2":
|
|
dieFunc = d2
|
|
case "d4":
|
|
dieFunc = d4
|
|
case "d6":
|
|
dieFunc = d6
|
|
case "d8":
|
|
dieFunc = d8
|
|
case "d10":
|
|
dieFunc = d10
|
|
critGood = []int{10}
|
|
critBad = []int{1}
|
|
case "d12":
|
|
dieFunc = d12
|
|
critGood = []int{12}
|
|
critBad = []int{1}
|
|
case "d20":
|
|
dieFunc = d20
|
|
critGood = []int{20}
|
|
critBad = []int{1}
|
|
case "d100":
|
|
dieFunc = d100
|
|
critNeut = []int{11, 22, 33, 44, 55, 66, 77, 88, 99}
|
|
critBad = []int{100}
|
|
critGood = []int{1}
|
|
default:
|
|
panic("Invalid die choice (d2, d4, d6, d8, d10, d12, d20, d100)")
|
|
}
|
|
|
|
sum := 0
|
|
for r := 0; r < rolls; r++ {
|
|
bouncesMin := 2
|
|
bouncesMax := 5
|
|
|
|
if rolls == 1 {
|
|
bouncesMin = 5
|
|
bouncesMax = 11
|
|
}
|
|
sum += simulate(dieFunc, bouncesMin, bouncesMax, critNeut, critGood, critBad)
|
|
}
|
|
|
|
if rolls > 1 {
|
|
fmt.Printf("Roll total: %v\n", sum)
|
|
}
|
|
|
|
}
|
|
|
|
func simulate(dieFunc func() int, bouncesMin int, bouncesMax int, critNeut []int, critGood []int, critBad []int) int {
|
|
bounces := globalRand(bouncesMax-bouncesMin) + bouncesMin
|
|
|
|
fmt.Print("")
|
|
|
|
for b := 0; b < bounces; b++ {
|
|
preroll := dieFunc()
|
|
fmt.Printf("\r>\033[34m%3d\033[0m", preroll) // purple while rolling
|
|
|
|
rwait := globalRand(50) + 25
|
|
time.Sleep(time.Millisecond * time.Duration(rwait))
|
|
}
|
|
|
|
actualRoll := dieFunc()
|
|
colour := "\033[34m" // Blue
|
|
if isIn(critNeut, actualRoll) {
|
|
colour += "\033[1m\033[35m" // Purple
|
|
} else if isIn(critBad, actualRoll) {
|
|
colour = "\033[1m\033[31m" // Red
|
|
} else if isIn(critGood, actualRoll) {
|
|
colour = "\033[1m\033[32m" // Green
|
|
}
|
|
|
|
fmt.Printf("\r%v%4d\033[0m\n", colour, actualRoll)
|
|
|
|
return actualRoll
|
|
}
|
|
|
|
func isIn(slice []int, item int) bool {
|
|
for _, i := range slice {
|
|
if i == item {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func d2() int {
|
|
return globalRand(2) + 1
|
|
}
|
|
|
|
func d4() int {
|
|
return globalRand(4) + 1
|
|
}
|
|
|
|
func d6() int {
|
|
return globalRand(6) + 1
|
|
}
|
|
|
|
func d8() int {
|
|
return globalRand(8) + 1
|
|
}
|
|
|
|
func d10() int {
|
|
return globalRand(10) + 1
|
|
}
|
|
|
|
func d12() int {
|
|
return globalRand(12) + 1
|
|
}
|
|
|
|
func d20() int {
|
|
return globalRand(20) + 1
|
|
}
|
|
|
|
func d100() int {
|
|
roll10 := globalRand(10)
|
|
roll100 := globalRand(10) * 10
|
|
roll := roll100 + roll10
|
|
|
|
if roll == 0 {
|
|
roll = 100
|
|
}
|
|
|
|
return roll
|
|
}
|