Overview
Every rotation — regardless of mode — passes through three stages:
The rotation mode controls when these stages run and which selection algorithm is used. The shuffle strength setting only affects stage 2 and only in Per Round mode.
All courts rotate together. Nobody gets a new game until every active court has submitted a result.
Each court rotates independently the moment its result is confirmed. No waiting for other courts.
Like Per Round, but player selection prioritizes equal game time over sit fairness.
Per Round
All courts rotate simultaneously. Nobody gets a new game until every active court has submitted a result. The admin sees a ROTATE ALL COURTS button (or auto-rotate fires if enabled).
When a round ends
_assign_round() runs once for the entire session.Per Court
Each court rotates independently the moment its result is confirmed. There is no global rotate — each court shows CONFIRM & ROTATE individually. Ideal for courts that finish at different speeds.
When a single court confirms a result
Time-Based
Structurally identical to Per Round (all courts rotate together), but player selection prioritizes equal game time rather than sit fairness. Best for ensuring nobody is left out disproportionately.
The random assignment in this mode is intentional: when the goal is equal time, skill-balancing court assignments would work against variety and the fairness goal.
Player Selection
The first job of every rotation is deciding who plays. The number of playing spots is always a multiple of 4 (full courts only):
Players marked as sitting out are excluded from both the count and selection entirely.
Sit-Fairness Score
Used by Per Round and Per Court. Players with higher scores get picked to play first.
Consecutive-Sit Safety Swap
After the initial sort, any sitting player with consecutive_sits ≥ 2 triggers a forced swap:
consecutive_sits == 0 (have not sat recently).This prevents anyone from sitting three or more rounds in a row regardless of score.
Time-Based Score
Used by Time-Based mode only. Equal game time is the sole priority.
The same consecutive-sit safety swap applies. When choosing the swap candidate in this mode, the playing player with the most session games is swapped out (rather than the lowest priority score).
Court Assignment
After selection, the playing players are divided into groups of 4 — one group per court. The method depends on mode.
| Mode | Method |
|---|---|
| Per Round | Elo banding with shuffle strength |
| Per Court | Priority score sort — top 4 stay on the court, rest back to queue |
| Time-Based | Random shuffle, then sliced into groups of 4 |
Shuffle Strength
Applies to Per Round mode only. Players are first sorted by adjusted seed (highest to lowest), then the strength setting controls how much that order is disrupted before slicing into courts.
0 — Pure Elo
No shuffle. Players are sliced in strict seed order: positions 1–4 go to court 1, 5–8 to court 2, and so on. The strongest players always play each other.
1–99 — Partial Shuffle
A controlled random displacement is applied to each player's position before slicing:
Each player is randomly swapped with another player within ±max_shift positions of their sorted rank. Higher strength = wider possible displacement.
max_shift = max(1, floor(16 × 0.25 × 0.5)) = 2
A player ranked 5th can end up anywhere between positions 3 and 7.
Example — 16 players, strength 75:
max_shift = max(1, floor(16 × 0.75 × 0.5)) = 6
A player ranked 5th can land anywhere between positions 1 and 11.
100 — Full Random
The sorted list is completely shuffled before slicing. Elo has no effect on which court a player ends up on.
Performance-Adjusted Seed
The sort key used in Elo banding is not raw Elo but a value adjusted for recent performance:
A player on a winning streak ranks slightly higher than their Elo alone suggests; a player on a losing streak ranks slightly lower. The maximum effect is ±30 points — subtle enough not to override Elo significantly, but enough to keep hot and cold players in more appropriate courts between Elo updates.
Team Pairing Optimizer
Once 4 players are assigned to a court, they must be split into two teams. Given players A, B, C, D there are exactly three possible pairings:
All three are evaluated and the one with the lowest total penalty is chosen.
Penalty Formula
|elo(A) + elo(B) − elo(C) − elo(D)|The primary driver of skill-balanced games. A perfectly balanced court scores 0 here.
+40 — same pairing as the immediately previous game+25 — same pairing as two games agoA player can incur up to +40 points if they would be paired with the same partner they just played with. Applied for both teams.
+15 — this opponent was faced in one of the last 2 games+8 — this opponent was faced in games 3 or 4 games agoPrevents the same two people from facing off every round.
A pairing with balanced teams and fresh partners and opponents scores near zero. A repeated, lopsided pairing can exceed 100 points and will never be chosen if any alternative exists.
Elo Ratings
After every confirmed game, Elo ratings update using the standard formula. Team Elo is the average of the two players' ratings.
Each player on the winning team gains the same number of points; each player on the losing team loses the same number. Elo cannot fall below the configured floor (default 1000).
K-Factor (sensitivity by experience)
New players' ratings move quickly so they reach their correct level fast. Experienced players' ratings are more stable.
Player Metadata (Per Session)
The following values are tracked per player throughout a session and reset when a new session starts.
| Field | Description |
|---|---|
| consecutive_sits | Rounds sat in a row without playing. Resets to 0 on any game played. |
| total_sits | Total rounds sat this session. |
| session_games | Games played this session. Used in both selection score formulas. |
| recent_partners | Last 2 partners. Used for partner penalty and novelty score. |
| recent_opponents | Last 4 opponents. Used for opponent penalty and novelty score. |
| recent_results | Last 3 results (win/loss). Used for streak bonus in adjusted seed. |
Quick Reference
| Per Round | Per Court | Time-Based | |
|---|---|---|---|
| Rotation trigger | All courts done | Single court done | All courts done |
| Selection algorithm | Sit-fairness score | Sit-fairness score | Equal-time score |
| Court assignment | Elo banding + shuffle | Priority sort top-4 | Random |
| Shuffle strength applies | Yes | No | No |
| Pairing optimizer | Yes | Yes | Yes |
| Consecutive-sit swap | Yes | Yes | Yes |