# utils/shuffle ## Purpose The `shuffle` module provides deterministic Fisher-Yates shuffling and single-element `choice` drawn from a user-supplied `Rng`. Because `Rng` is the canonical interface defined in `@suaveplan/types`, these utilities compose with every `SeededRng` implementation in this package as well as with the CSPRNG in `@suaveplan/random`. Shuffling is a building block for game-card dealing, playlist generation, A/B assignment, and deterministic test data. Isolating it here ensures every downstream package uses the same unbiased Fisher-Yates algorithm rather than re-implementing it (which frequently introduces subtle bias). ## Features - `shuffle(input, rng)` — non-mutating, returns a new shuffled array - `shuffleInPlace(arr, rng)` — mutates the argument, returns it - `choice(input, rng)` — uniformly random element; typed `PseudoRandomError` on empty input - Draws exactly `n - 1` uint32 values per shuffle — counts are predictable for replay ## Usage: Basic Example ```ts import { Mulberry32Rng } from "@suaveplan/pseudo-random"; import { shuffle } from "@suaveplan/pseudo-random/utils"; const rng = new Mulberry32Rng(42); const deck = shuffle(["A", "K", "Q", "J"], rng); ``` ## Usage: Advanced Example ```ts import { Sfc32Rng } from "@suaveplan/pseudo-random"; import { choice, shuffleInPlace } from "@suaveplan/pseudo-random/utils"; const rng = new Sfc32Rng("round-12"); const deck = ["clubs", "hearts", "diamonds", "spades"]; shuffleInPlace(deck, rng); const first = choice(deck, rng); ``` ## API Reference - `shuffle(input: ReadonlyArray, rng: Rng): T[]` — returns a new array. - `shuffleInPlace(arr: T[], rng: Rng): T[]` — mutates and returns. - `choice(input: ReadonlyArray, rng: Rng): T` — throws `PseudoRandomError.ARG.EMPTY_ARRAY` on empty input. ## Implementation Notes The Fisher-Yates loop walks from `n-1` down to `1`, swapping `arr[i]` with `arr[j]` where `j = rng.nextUint32() % (i+1)`. The modulo introduces a negligible bias when `i+1` does not divide 2^32 evenly (max bias ≈ `n / 2^32`); for any `n` short of 2^32 elements this is statistically undetectable and matches the behaviour every other mainstream library ships. If you need provably unbiased sampling for large `n`, use `@suaveplan/random`'s `randomInt`, which re-draws on biased samples.