All extensions

@open-rgs/fill

Weighted draws, one cell at a time.

The strip replacement

Every cell drawn independently from one weighted set. This deliberately does not do adjacency - that belongs to markov, layered on top - because most balancing work is frequency work and should not require thinking about neighbours.

Every cell drawn independently from the same weighted set.
import { fillWeights } from "@open-rgs/fill";

const reels = fillWeights(SHAPE, { LOW: 55, MID: 25, HIGH: 12, WILD: 5, SC: 3 });

const board = reels(host.rng_next);

Per-column sets

The classic way to differentiate reels: a wild that can only land on the middle three. A short list is an authoring mistake that would otherwise surface as an undefined symbol mid-spin, so it throws at build time.

Per-column sets let a wild land only on the middle reels.
import { fillWeightsPerColumn } from "@open-rgs/fill";

const gated = fillWeightsPerColumn(SHAPE, [
  { LOW: 60, HIGH: 12, WILD: 0 },
  { LOW: 55, HIGH: 12, WILD: 5 },
  { LOW: 55, HIGH: 12, WILD: 5 },
  { LOW: 55, HIGH: 12, WILD: 5 },
  { LOW: 60, HIGH: 12, WILD: 0 },
]);

Counting without simulating

Cells are independent under these generators, so expectation is the sum of per-cell probabilities. That makes a whole class of questions arithmetic rather than a simulation run.

=0.9
How many scatters per spin, computed rather than measured.
import { expectedCount, cellProbability } from "@open-rgs/fill";

expectedCount(SHAPE, sets, "SC");
cellProbability(sets, 0, "WILD");