Les appariements suisses : l'algorithme derrière l'équité d'un tournoi

Organiser un tournoi avec 40 joueurs pose un problème d'appariement avant même de poser un problème d'échecs. Un round-robin (chacun affronte tout le monde) demande 39 rondes. Une élimination directe élimine la moitié du plateau après une seule partie, souvent perdue par malchance plus que par niveau. Le système suisse, implémenté dans kotlin-chess-tournament et utilisé par EloChessPlanner, résout ce problème précis : garder tout le monde en jeu, en un nombre de rondes raisonnable, tout en appariant des joueurs de niveau comparable.
Le principe : apparier par groupe de score
Après la première ronde, les joueurs sont répartis en groupes selon leur score cumulé (les joueurs à 1 point, ceux à 0,5, ceux à 0). L'appariement se fait à l'intérieur de chaque groupe, jamais entre joueurs de scores trop différents : ça garantit qu'à mi-tournoi, chaque partie oppose des joueurs qui ont un parcours comparable jusque-là.
Score 3 ─┬─ Joueur A ── Joueur D
└─ Joueur B ── Joueur C
Score 2.5 ─┬─ Joueur E ── Joueur H
└─ Joueur F ── Joueur G
La méthode Dutch, en détail
Dans chaque groupe de score, la méthode Dutch (la plus répandue, implémentée par bbpPairings que kotlin-chess-tournament référence comme alternative C++/Pascal) suit une séquence précise :
- Trier le groupe par score puis par classement Elo (départage initial).
- Diviser en deux moitiés : la moitié supérieure (les mieux classés du groupe) et la moitié inférieure.
- Apparier position par position : le premier de la moitié haute affronte le premier de la moitié basse, le deuxième affronte le deuxième, ainsi de suite.
- Éviter les répétitions : si un appariement recréerait une partie déjà jouée dans le tournoi, permuter avec le candidat suivant dans la moitié basse plutôt que de forcer la répétition.
Moitié haute Moitié basse
Joueur A ──── Joueur C
Joueur B ──── Joueur D
Si Joueur A a déjà affronté Joueur C lors d'une ronde précédente, l'algorithme essaie Joueur A contre Joueur D à la place, et réajuste le reste des appariements du groupe en conséquence.
Ce qui arrive quand un groupe a un nombre impair de joueurs
Un groupe de score avec un nombre impair de joueurs ne peut pas s'apparier entièrement en interne : un joueur doit descendre (float down) dans le groupe de score immédiatement inférieur pour y trouver un adversaire. La règle FIDE précise qui doit descendre en priorité (généralement le joueur le moins bien classé du groupe), pour que ce ne soit jamais arbitraire ni toujours le même profil de joueur qui en fasse les frais d'une ronde à l'autre.
Le bye : une règle simple, un piège fréquent
Avec un nombre impair total de joueurs, quelqu'un ne joue pas cette ronde et reçoit un bye (souvent compté comme une victoire, parfois comme une demi-victoire selon le règlement). La règle qui semble évidente, mais que beaucoup d'implémentations artisanales ratent : le bye doit tourner, un même joueur ne peut pas recevoir deux byes tant qu'un autre joueur éligible n'en a pas encore reçu un. Sans ce suivi explicite, un joueur peut se retrouver à recevoir un bye deux fois alors qu'un autre n'en a jamais eu, ce qui fausse silencieusement l'équité du tournoi sans qu'aucune règle d'appariement à proprement parler n'ait été violée.
L'équilibrage des couleurs, la contrainte qu'on oublie
Un bon appariement suisse ne se limite pas au score et à l'évitement des répétitions : il doit aussi équilibrer les couleurs, en évitant qu'un joueur reçoive les blancs (ou les noirs) trois fois de suite. Cette contrainte s'ajoute aux précédentes, ce qui veut dire qu'un algorithme d'appariement naïf qui optimiserait uniquement le score peut produire un appariement valide sur le papier mais injuste dans son déroulé, un joueur subissant systématiquement les noirs pendant que son adversaire du jour enchaîne les blancs.
Le départage : trois métriques, pas une seule
À score égal en fin de tournoi, le classement final ne peut pas s'arrêter au score brut. Trois départages, appliqués dans l'ordre, tranchent la plupart des égalités :
| Départage | Calcul | Ce qu'il récompense |
|---|---|---|
| Buchholz | Somme des scores finaux de tous les adversaires rencontrés | Avoir affronté un plateau difficile |
| Sonneborn-Berger | Somme des scores des adversaires battus, plus la moitié des scores des adversaires contre qui on a fait nul | Battre des adversaires forts, pas juste accumuler des points contre des adversaires faibles |
| Elo moyen des adversaires | Moyenne simple des classements affrontés | Une mesure plus directe, moins sensible aux performances ponctuelles des adversaires |
Le Buchholz et le Sonneborn-Berger répondent à des questions différentes : le premier récompense la difficulté du parcours quel qu'en soit le résultat, le second récompense spécifiquement les victoires contre des adversaires qui ont bien performé. Un joueur avec un parcours très difficile mais peu de victoires peut avoir un bon Buchholz et un faible Sonneborn-Berger ; c'est pour ça qu'un classement final robuste applique les deux dans un ordre défini, jamais un seul isolément.
Pourquoi l'ordre du classement doit être déterministe
Une fois score et départages appliqués, il reste toujours une probabilité non nulle d'égalité parfaite sur tous les critères. Le classement final doit malgré tout produire un ordre stable et reproductible, pas dépendant de l'ordre d'insertion en base de données ou d'un tri instable. C'est un détail d'implémentation qui semble mineur, mais qui devient un vrai problème le jour où deux exécutions du même calcul, sur les mêmes données, produisent un classement différent : dans un tournoi homologué, ce genre d'incohérence n'est pas acceptable, même pour départager une position qui n'a de toute façon aucun impact sur le podium.