I want to organize a badminton tournament in double teams, where no one plays twice with the same partner, using python. I created a graph using nx.Graph and implemented a function to get the list of unplayed partners for each round (each player keeps track of already played partners). But unfortunately, after a few rounds, the algorithm doesn't achieve to find unplayed and available partners (because unplayed partners are already picked in another team). This is my first step, so let's say I have an even number of players.
With that context, how to implement a team matcher which uses a rotation of partners in such a way that everyone plays at each round, and everyone has a different partner ?
Here is my draft of matcher class:
import itertools
import networkx as nx
class Player:
def __init__(self, name: str):
self.name = name
self.previous_partners = set()
self.score = 0.0
def __str__(self):
return self.name
class Team:
def __init__(self, players: list):
if len(players) != 2:
raise ValueError('A team must contain exactly two players')
self.players = players
def __str__(self):
return ' / '.join([str(player) for player in self.players])
class RoundRobinMatcher:
@staticmethod
def _create_graph(players: list[Player]) -> nx.Graph:
graph = nx.Graph()
for player in players:
graph.add_node(player, score=player.score)
for opponent in player.previous_partners:
graph.add_edge(player, opponent)
return graph
@staticmethod
def _find_unplayed_pairs(graph: nx.Graph) -> list[tuple[Player, Player]]:
unplayed_pairs = []
for pair in itertools.combinations(graph.nodes, 2):
if not graph.has_edge(*pair):
unplayed_pairs.append(pair)
return unplayed_pairs
def match(self, players: list[Player]) -> list[Team]:
graph = self._create_graph(players)
unplayed_pairs = self._find_unplayed_pairs(graph)
teams = []
for pair in unplayed_pairs:
for team in teams:
if pair[0] in team.players or pair[1] in team.players:
break
else:
teams.append(Team(pair))
return teams
if __name__ == '__main__':
players = [Player('a'), Player('b'), Player('c'), Player('d'), Player('e'), Player('f'), Player('g'), Player('h')]
matcher = RoundRobinMatcher()
teams = matcher.match(players)
for team in teams:
print(team)