I'm trying to make a bracket generator similar to the Swiss style, but drawing games in batches of 2 rounds unlike Swiss which requires the results of the most recent round to generate the next round of games.
I decided to try using some kind of rating system (Glicko, elo, whatever...) for the seeding - every player starts with the default rating (so initial matches are random), and then matches are drawn such that the sum of squares of rating differences is minimal and after each batch of matches, the ratings are updated with the results. However, I must also prevent 2 players from playing more than once (especially in the same round).
I thought about representing each round as a graph - all of the "possible" matches would be the edges and each vertex would be a player, so the possible matches would be the complete graph of n vertices (then I can set repeat matchups from previous rounds to have a very high "distance" so they never get picked). The problem then becomes finding the right subgraph such that each vertex is connected exactly twice and the sum of squares of distances is minimized.
This sounds a bit similar to the traveling salesman problem but the matches can be completely "disjoint" - if we have:
1 vs 2
2 vs 3
3 vs 1
4 vs 5
5 vs 6
6 vs 4
when we represent this as a graph, the two groups of 3 are disconnected.
I haven't been able to come up with an efficient algorithm for this, nor find an analogous problem that has been solved.
I implemented a Swiss-like tournament pairing algorithm using
networkx.min_weight_matching.The logic of the pairing is in methods
tournament.dist, which defines the "penalty" of pairing together two players who don't have the same number of wins; andtournament.get_next_round.SOS (sum of opponents' numbers of wins) and SOSOS (sum of opponents' sos) are used as tie-breakers.
I did not implement a method to remove players for a round or to add a bye-player in case the number of players is odd.
Output: