2.7 KiB
tournament-standings.internal
Purpose
Pure helper utilities for the standings table inside a tournament:
applying a win/loss outcome, marking participants eliminated, locating a
match by id, and flipping a round to completed. Extracted from
tournament-manager.ts to keep that file under the project's 300-line
hard limit while preserving full behaviour through the public API.
The helpers are stateless and take their targets by reference so the
manager retains exclusive ownership of mutability. They are covered
indirectly via the manager's public surface tests rather than directly,
which is the standard pattern for .internal.ts modules in this repo.
Features
applyStanding— write outcome + resort + re-rank in one call.markEliminated— seteliminated = trueby participant id.findMatch— linear scan across rounds (small N).markRoundCompleteIfDone— flip round completion idempotently.
Usage: Basic
import { applyStanding } from "./tournament-standings.internal.js";
applyStanding(standings, winner, loser, 3, 0);
Usage: Advanced
import {
applyStanding,
findMatch,
markEliminated,
markRoundCompleteIfDone,
} from "./tournament-standings.internal.js";
applyStanding(tournament.standings, winner, loser, winPoints, lossPoints);
markEliminated(tournament.standings, loser.id);
const next = findMatch(tournament.rounds, currentMatch.nextMatchId!);
markRoundCompleteIfDone(tournament.rounds, currentMatch);
API Reference
applyStanding(standings, winner, loser, winPoints, lossPoints): voidmarkEliminated(standings, id): voidfindMatch(rounds, matchId): Match | nullmarkRoundCompleteIfDone(rounds, match): void
Implementation Notes
The standings sort is stable on points first, then wins, then losses
ascending — the conventional Swiss-style ordering. Re-sorting after every
outcome is O(N log N) per result; for typical bracket sizes (≤ 256
participants) this is well under a millisecond and avoids the
bookkeeping complexity of an incremental order-statistic structure.
findMatch is a linear scan across all rounds. Bracket-size rounds grow
logarithmically with participant count in single-elimination and
linearly in round-robin, so the total match count stays small relative to
typical scan budgets. A hot-path id-to-match index would be premature
optimisation here and would force the manager to keep two structures in
sync.
markRoundCompleteIfDone treats bye and completed as equivalent
terminal states so a round consisting entirely of byes is reported as
done immediately after start(), which keeps getStats().currentRound
advancing through automatic walkovers without manual intervention.