first commit
This commit is contained in:
46
docs/foundation/random/pseudo-random/src/utils/shuffle.md
Normal file
46
docs/foundation/random/pseudo-random/src/utils/shuffle.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# 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<T>(input: ReadonlyArray<T>, rng: Rng): T[]` — returns a new array.
|
||||
- `shuffleInPlace<T>(arr: T[], rng: Rng): T[]` — mutates and returns.
|
||||
- `choice<T>(input: ReadonlyArray<T>, 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.
|
||||
Reference in New Issue
Block a user