All extensions

@open-rgs/weights

The number you read is the number you get.

Probability you can read

A reel strip encodes odds indirectly - you move symbols around an array to shift them. A weighted set answers the question directly, and that is the whole balancing story: RTP is a sum of probability times payout.

The pointer lands in each band exactly as often as its declared weight.
import { sampler } from "@open-rgs/weights";

const symbols = sampler({ LOW: 60, MID: 30, HIGH: 9, WILD: 1 });

symbols.probabilityOf("WILD");
symbols.distribution();
symbols.pick(host.rng_next());

Zero weight means unreachable

A symbol that exists in the game but cannot be drawn in this mode is a real thing - a scatter excluded from a respin set. It stays in the set, reports probability zero, and never comes out at any draw.

Unreachable at every value, including the very top of the range.
const respin = sampler({ COIN: 70, BLANK: 30, SC: 0 });

respin.probabilityOf("SC");
respin.pick(0.999999);

Refusing beats under-delivering

A placement that declared three symbols has already priced three into its RTP. Handing back two would corrupt the model with nothing downstream able to notice, so it throws instead.

pickDistinct draws without replacement, one value per item.
import { pickDistinct } from "@open-rgs/weights";

const highs = sampler({ H1: 1, H2: 1, H3: 1 });

pickDistinct(highs, 3, host.rng_next);
pickDistinct(highs, 4, host.rng_next);