The problem, in plain terms
Imagine you're running a pickleball night: 16 players, 4 courts, 7 rounds. Everybody wants to:
- play with as many different partners as possible (nobody wants the same partner all night),
- play against lots of different people,
- rotate around the courts instead of being stuck on court 4,
- sit out fairly, if anyone has to sit out at all,
- and respect the rules you've set, like "Bill and Ted must always partner" or "Sue and Ann should never share a court."
Doing this by hand with a clipboard falls apart fast. The number of possible schedules is astronomically large — for 16 players and 7 rounds there are more possibilities than atoms in the universe. The app can't try them all, so it uses a smarter three-step strategy: start from a mathematically perfect skeleton, surgically fix any rule violations, then polish.
Step 1: Start from a perfect pattern (the "Whist" rotation)
There's a piece of 19th-century math, originally invented for whist card tournaments, that solves the partner-variety problem exactly. It's called the circle method, and you can picture it like this:
Put one player in the center of a circle and arrange everyone else around the ring. Draw lines to pair people up: the center player pairs with the person at the top of the ring, then each remaining person pairs with the person directly across from them. That's round 1. For round 2, keep the center player fixed and rotate the ring by one seat, then draw the same lines again. Keep rotating for each round.
The app shuffles who sits where in the circle first (so every game night gets a different-looking schedule), but the underlying rotation keeps its guarantee.
While it deals out each round, the app also chooses which court each group lands on. For small games it literally tries every possible court arrangement (with 4 courts there are only 24 ways) and picks the one that keeps everyone's court visits most even. For big games (up to 24 courts) trying everything would be too slow, so it assigns groups one at a time, each to whichever court that player group has visited least — a "good enough, fast" version of the same idea.
Step 2: Surgically repair any broken rules
The perfect rotation doesn't know about your custom rules — "these two never partner," "keep those two on separate courts," "these two must start together." After dealing the skeleton, the app checks every round against every rule.
Here's the key insight that makes this fixable: every rule is local to a single round. If Sue and Ann ended up on the same court in round 3, that problem lives entirely inside round 3 — fixing it can't break round 5. So the repairer walks round by round, finds each violation, and performs a targeted swap: it looks for another player in that round who can trade places without creating a new violation, like rearranging seats at a dinner party so two feuding relatives aren't side by side. Because the Whist pattern spreads people around so thoroughly, violations are rare and there's almost always a safe swap available.
One rule gets special treatment: "must always partner." A permanent fixed pair fundamentally fights the rotation (which is designed to never repeat a partnership), so when you use that rule the app skips the Whist skeleton and builds the schedule a different way from scratch.
Step 3: Polish with "simulated annealing" (educated trial and error)
The schedule is now valid, but there's still room for improvement — court rotation could be smoother, matches could be more evenly rated. For this the app uses a classic technique called simulated annealing, named after the way blacksmiths strengthen metal by heating it and cooling it slowly.
- Score the schedule. Every flaw adds penalty points: a repeated matchup costs points, uneven court rotation costs points, lopsided teams cost points (if you've entered player ratings), unfair sit-outs cost points. Lower score = better schedule.
- Try a small random change. Swap two players, trade two teams between courts, reorder two rounds.
- Keep it or undo it. If the change lowered the score, keep it. If it made things worse, sometimes keep it anyway — and here's why: always insisting on improvement gets you stuck, like hiking downhill in fog and stopping in the first small dip you find instead of reaching the valley floor. Accepting an occasional uphill step lets you escape the dip.
- Cool down. Early on ("hot"), the algorithm is adventurous and accepts lots of bad moves to explore. As thousands of tries go by, the "temperature" drops and it gets pickier, until at the end it only accepts genuine improvements. The cooling speed is matched to the time budget, so a quick schedule and a long one both finish properly "cold."
Two hard boundaries are enforced during all this trial and error, like guardrails:
- The perfection lock. Any random change that would break the Whist guarantee — creating a repeat partnership (doubles) or repeat opponent (singles) — is rejected instantly, no matter how much it would improve anything else. The mathematical guarantee from Step 1 survives the entire polish phase untouched.
- The rules lock. Same for your custom pairing rules: once Step 2 has everything satisfied, no random change that re-breaks a rule is ever accepted. This matters because at a big session (say, 96 players on 24 courts) the sheer volume of "variety" points could otherwise tempt the algorithm into sacrificing a rule for a shinier score.
The three flavors you can pick
The scoring weights change depending on the mode you choose when creating a game:
| Mode | What the scoring emphasizes |
|---|---|
| Random | Maximum variety — different partners and opponents above all |
| Seeded | Groups players of similar skill onto the same courts (strong with strong) |
| Balanced | Every court has roughly the same total skill, so no court is a blowout |
An interesting subtlety: in Balanced mode, "make the courts equal in total strength" and "make each individual match close" quietly work against each other. Equal court totals mean putting a strong pair and a weak pair on the same court — which is exactly a lopsided match. When the two goals were weighted almost equally they canceled out and the algorithm just drifted. Letting court balance clearly dominate fixed it: the schedules it produces now match what a brute-force search proves is the best possible grouping.
When your rules are simply impossible
If you write contradictory rules (say, enough "never" constraints that no valid arrangement exists), no algorithm can satisfy them. The app doesn't pretend otherwise and doesn't throw your schedule away: it hands back the best attempt with a warning banner telling you some rules couldn't be honored, and you decide whether to play it or loosen a rule.
Why this design instead of just "shuffle and pray"?
Pure random shuffling gives you repeat partners by round 3 — with 16 players, chance alone practically guarantees it. Pure trial-and-error polishing without the perfect skeleton would need millions of tries to stumble into what the circle method hands us for free. And trusting penalty points alone to protect your custom rules fails at scale, because a mountain of small variety bonuses can outweigh one big rule penalty.
The three-step combination — provably perfect skeleton → targeted repair → guarded polish — gets the best of all worlds: mathematical guarantees where math can give them, deterministic fixes where rules are concerned, and a few seconds of educated tinkering for everything that's merely "nice to have." All of it runs on your phone, off the main thread, in about two and a half seconds even for a 24-court session — so when you hit GO!, the schedule is just there.