Bunyip a game engine in Go GitHub

Package github.com/matjam/bunyip/rng

rng

Package rng provides a small, fast, seedable random number generator (PCG32) for games. The same seed always gives the same sequence on every platform, streams can be forked so systems do not disturb each other, and the state can be saved and restored.

To make a source, call New with a seed. Fork derives an independent stream from it, so a dungeon generator, loot tables and particle jitter each take their own, and adding a call to one never changes what another produces, which keeps seeds shareable and replays exact. Besides the integer and float draws there are game helpers: Roll for dice (Roll(2, 6) is 2d6), Chance, Range and Between, Pick, WeightedIndex, Shuffle and Normal. State and Restore put the generator into a save file. Sources are not safe for concurrent use; fork one per goroutine.

Index

Functions

WeightedIndex source

func WeightedIndex(r *Rand, weights []float32) int

WeightedIndex picks an index with probability proportional to its weight; weights at or below zero are never chosen. It returns -1 when nothing can be picked. Weights and their positive sum must be finite.

Types

type Rand source

type Rand struct {
	// contains filtered or unexported fields
}

Rand is one PCG32 stream. It also satisfies math/rand/v2's Source.

New source

func New(seed uint64) *Rand

New seeds a generator.

Example
package main

import (
	"fmt"

	"github.com/matjam/bunyip/rng"
)

func main() {
	// The same seed gives the same sequence on every platform.
	r := rng.New(42)
	fmt.Println(r.Intn(100), r.Intn(100), r.Intn(100))
	fmt.Println(r.Roll(2, 6) >= 2)
}
Output
44 23 95
true

NewStream source

func NewStream(seed, stream uint64) *Rand

NewStream seeds a generator on a particular stream. Only the low 63 bits of stream select the sequence; stream values differing solely in the highest bit select the same sequence.

Between source

func (r *Rand) Between(lo, hi float32) float32

Between returns a value in [lo, hi).

Chance source

func (r *Rand) Chance(p float32) bool

Chance reports true with probability p: p <= 0 is always false and p >= 1 is always true. Every call advances the generator.

Float source

func (r *Rand) Float() float32

Float returns a value in [0, 1).

Float64 source

func (r *Rand) Float64() float64

Float64 returns a value in [0, 1).

Fork source

func (r *Rand) Fork() *Rand

Fork derives an independent generator from this one's next values, so a subsystem can take its own stream without disturbing the parent's sequence any further.

Example
package main

import (
	"fmt"

	"github.com/matjam/bunyip/rng"
)

func main() {
	// Forked streams let one system roll dice without disturbing another.
	world := rng.New(1)
	combat := world.Fork()
	a := combat.Intn(1000)
	combat2 := rng.New(1).Fork()
	fmt.Println(a == combat2.Intn(1000))
}
Output
true

Intn source

func (r *Rand) Intn(n int) int

Intn returns a value in [0, n). It panics when n is not positive.

Normal source

func (r *Rand) Normal(mean, stddev float32) float32

Normal returns a normally distributed value (Box-Muller).

Pick source

func (r *Rand) Pick[T any](items []T) T

Pick returns a random element; it panics on an empty slice.

Example
package main

import (
	"fmt"

	"github.com/matjam/bunyip/rng"
)

func main() {
	r := rng.New(7)
	loot := []string{"sword", "shield", "potion"}
	fmt.Println(r.Pick(loot))
	r.Shuffle(loot)
	fmt.Println(len(loot))
}
Output
potion
3

Range source

func (r *Rand) Range(lo, hi int) int

Range returns a value in [lo, hi], inclusive at both ends, swapping reversed bounds. The inclusive range width must fit in a positive int.

Restore source

func (r *Rand) Restore(state, inc uint64)

Restore sets the state returned by State.

Roll source

func (r *Rand) Roll(dice, sides int) int

Roll sums dice of the given sides, as in Roll(2, 6) for 2d6.

Shuffle source

func (r *Rand) Shuffle[T any](items []T)

Shuffle permutes the slice in place (Fisher-Yates).

State source

func (r *Rand) State() (state, inc uint64)

State returns the generator's full state for saving.

Uint32 source

func (r *Rand) Uint32() uint32

Uint32 returns the next 32 random bits.

Uint64 source

func (r *Rand) Uint64() uint64

Uint64 returns the next 64 random bits.

Source files

example_test.go rng.go rng_test.go