Implement a round robin tournament without playing twice with the same partner

44 Views Asked by At

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)

0

There are 0 best solutions below