random
Seedable random numbers, picks, shuffles and strings for games, sampling and test data, and when to use crypto instead.
import "std:random"std:random makes pseudo-random values: dice rolls, picks from a list, shuffles, random text. It is fast and, importantly, repeatable: seed it and the same sequence comes out every time, which makes games, simulations and tests reproducible.
It is not safe for secrets. Passwords, tokens and keys need std:crypto, because a seeded generator can be predicted.
Examples on this page that print raw random values are marked as varying, since their output changes on every run. The ones that call random.seed first always print the same thing.
Numbers#
random.number() is from 0 up to but not including 1. Give it one bound for 0 up to that, or two for a range. random.int(min, max) is a whole number and includes both ends, so random.int(1, 6) is a die.
import "std:random"
log random.number()
log random.number(10)
log random.number(5, 10)
log random.int(1, 6)You can rely on the ranges even when you can't predict the value. Here we roll a thousand dice and check every roll was a legal one:
import "std:random"
auto ok = true
for _ in 1 to 1000 (
auto roll = random.int(1, 6)
if roll < 1 or roll > 6 ( ok = false )
)
log okSeeding#
random.seed(n) restarts the generator. Seed it with the same number and every call after that repeats:
import "std:random"
random.seed(42)
auto first = [random.int(1, 100), random.int(1, 100), random.int(1, 100)]
random.seed(42)
auto second = [random.int(1, 100), random.int(1, 100), random.int(1, 100)]
log first == secondWithout a call to random.seed, each run starts differently. Seed with a fixed number in tests, and with something like the time (date.now().unix()) when you want a repeatable value you can also record and replay later.
Choosing and sampling#
random.item(items) picks one item, typed as the array's items are. random.sample(items, count) picks several different ones, in random order. Neither changes the array.
import "std:random"
random.seed(7)
string[] names = ["Ada", "Bo", "Cy", "Di", "Ed"]
string winner = random.item(names)
string[] team = random.sample(names, 3)
log names.contains(winner)
log team.len
log team.deDupe().len
log names.lenteam.deDupe().len being 3 shows the picks are all different. Asking for more items than the array has returns them all, shuffled.
Shuffling#
random.shuffle(items) returns a shuffled copy and leaves the original alone:
import "std:random"
random.seed(1)
auto deck = [1, 2, 3, 4, 5, 6, 7, 8]
auto shuffled = random.shuffle(deck)
log deck
log shuffled.len
log shuffled.toSorted() == deckSorting the shuffled copy gives the deck back, so nothing was lost or duplicated. That is a good property to test: you can't assert the order, but you can assert what must stay the same.
Chance#
random.bool() is a coin flip. Give it a probability from 0 to 1 to weight it. 0 never gives true and 1 always does:
import "std:random"
log random.bool(1)
log random.bool(0)
random.seed(3)
int hits = 0
for _ in 1 to 1000 (
if random.bool(0.25) ( hits++ )
)
log hits > 150 and hits < 350Bell curves#
random.gaussian() has mean 0 and standard deviation 1. Pass a mean and a standard deviation for another curve. Most values fall near the mean, which suits heights, noise and anything natural:
import "std:random"
import "std:math"
random.seed(5)
number[] heights = []
for _ in 1 to 2000 (
heights.append(random.gaussian(170, 10))
)
auto mean = math.avg(heights).unwrap()
log mean > 168 and mean < 172Random text#
random.string() gives 16 letters and digits. Pass a length, and optionally an alphabet to draw from:
import "std:random"
random.seed(9)
log random.string().len
log random.string(8).len
string bits = random.string(10, "01")
log bits.len
log bits.replace("0", "").replace("1", "").lenThe last line removes every 0 and 1 and finds nothing left, so only the alphabet was used. Use this for test data, throwaway ids and filler. For tokens that protect something, use std:crypto.
Pattern: a seeded game#
Seeding makes a whole game reproducible: the same seed is the same dungeon. Share the seed and players share the map.
import "std:random"
def rollDice(int count) int[] (
int[] rolls = []
for _ in 1 to count (
rolls.append(random.int(1, 6))
)
return rolls
)
random.seed(2024)
auto a = rollDice(5)
random.seed(2024)
auto b = rollDice(5)
log a == b
log a.lenA test needs the same "random" shuffle on every run. What do you do?
A fair die
Finish roll so it returns a random whole number from 1 to sides, both ends included. The loop rolls a thousand times and checks every roll was legal.
true
API reference#
9 members, generated from the std:random source of OSL 9.3.0.
Functions
random.bool(any ...probability) booleanbool returns true or false with equal odds, or true with the given probability from 0 to 1, as in random.bool(0.25). Throws ValueError for a probability outside 0 to 1.
random.gaussian(any ...meanAndStdDev) numbergaussian returns a normally distributed number: gaussian() has mean 0 and standard deviation 1, and gaussian(mean, stdDev) uses the given ones. Throws ValueError for a negative stdDev.
random.int(int min, int max) intint returns a whole number from min to max, including both ends, so random.int(1, 6) rolls a die. The bounds may come in either order.
random.item(array items) anyitem returns a random item of items, typed as the array's items are, or null (the item type's zero value for a typed array) when items is empty.
random.number(any ...bounds) numbernumber returns a random number. number() is from 0 up to but not including 1, as JavaScript's Math.random() is, number(max) from 0 up to max, and number(min, max) from min up to max.
random.sample(array items, int count) arraysample returns count different items of items in random order, typed as items is, or all of them shuffled when count is larger than items. Throws ValueError for a negative count.
random.seed(int seed)seed restarts the generator from seed, so the same seed always produces the same sequence of results from every random function.
random.shuffle(array items) arrayshuffle returns a shuffled copy of items, typed as items is, and leaves items unchanged.
random.string(any ...lengthAndAlphabet) stringstring returns random characters: string() gives 16 letters and digits, string(length) gives length of them, and string(length, alphabet) draws from the characters of alphabet instead. Throws ValueError for a negative length, one over 16777216, or an empty alphabet, and TypeError for other argument types.