# tournament-bracket.internal ## Purpose Pure bracket-generation helpers used by `TournamentManager`. Extracted to a sibling internal module to keep `tournament-manager.ts` under the project's 300-line hard limit while preserving full coverage of the generation paths through the manager's public surface. The helpers are deliberately framework-free — they accept an injectable `createMatch` factory so the manager retains exclusive ownership of match ids, OTel counters, and other side-effecting machinery, leaving these helpers as deterministic pure functions over the participant + match type domain. ## Features - `roundName(round, total)` — human-readable round labels. - `shuffleWithRng(arr, rng)` — in-place Fisher-Yates via injectable `Rng`. - `padToPowerOfTwo(participants)` — null-padding for single-elim. - `buildSingleElim(...)` — bracket with first-round byes. - `buildRoundRobin(...)` — circle-method scheduling. ## Usage: Basic ```ts import { buildSingleElim } from "./tournament-bracket.internal.js"; const rounds = buildSingleElim(participants, (round, position) => createMatch(round, position) ); ``` ## Usage: Advanced ```ts import { buildRoundRobin, shuffleWithRng, } from "./tournament-bracket.internal.js"; shuffleWithRng(participants, rng); const rounds = buildRoundRobin(participants, (round, position) => ({ id: nextId(), round, position, participant1: null, participant2: null, status: "pending", result: null, nextMatchId: null, })); ``` ## API Reference - `roundName(round: number, total: number): string` - `shuffleWithRng(arr: T[], rng: Rng | undefined): void` - `padToPowerOfTwo(participants: Participant[]): (Participant | null)[]` - `buildSingleElim(participants, createMatch): Round[]` - `buildRoundRobin(participants, createMatch): Round[]` ## Implementation Notes `buildSingleElim` throws `INVALID_BRACKET_SIZE` if the padded size is not a power of two — this should be unreachable in practice since `padToPowerOfTwo` always pads to a power of two, but the guard catches caller misuse (e.g. handing in a pre-padded list) without silent corruption of the bracket shape. `buildRoundRobin` uses the standard circle method: one participant is fixed and the others rotate around it. For an odd participant count a `null` slot is injected so each round contains exactly `floor(n/2)` matches; pairs with `null` are filtered out before emitting matches so they don't appear in the bracket. This yields `n - 1` rounds for `n` even and `n` rounds for `n` odd, matching the conventional schedule. Shuffle is unbiased Fisher-Yates and uses `Rng.nextIntInRange` — implementations of `Rng` that do not provide it (it is optional in the core contract) leave the order untouched, which is the conservative default for any tournament harness that prefers explicit error over silent non-determinism.