Creating a Round- Robin tournament, alternative solution?

Question:

teams = ["Atletico","Barcelona","Real Madrid", "Sevilla", "Atletic Bilbao ", "Granada", "Mallorca","Valencia"]

We have a group of teams where we want to create a tourname. Could be any tournament, any number of teams (not odd).

I want want to create a round-roubin tournament, where basically, all teams play with all the other teams .

I have created one kind-of solution:

weeks=[]
def schedule(teams):
    teams = list(teams)
    n = len(teams)
    for a in range(n - 1):
        b = zip(teams[:n // 2], reversed(teams[n // 2:]))
        weeks.append(list(b))
        teams.insert(1, teams.pop())
    print(weeks)
    return weeks

schedule(teams)

This solution though is not optimal since I’m taking into considerate home and away status. 1) One group of teams is always home and another group is always away and 2) It is not randomized.

I would like a solution where in each week the pairs are randomly matched but they pairs have not played before. How could I keep tracking of which matches have been scheduled already ?

Asked By: ToErotimatiko

||

Answers:

I was just going to point you toward the solution, but I got tired of trying to explain in the comments so:

Here is a solution:

import random

teams = ["Atletico", "Barcelona", "Real Madrid", "Sevilla", "Atletic Bilbao ", "Granada", "Mallorca", "Valencia"]
pairs = [(i, j) for i in teams for j in teams if i != j]
random.shuffle(pairs)

numWeeks = len(teams) - 1
numPairs = len(teams)//2
matchUps = {}
for week in range(numWeeks):
    matchUps[f'Week {week}'] = []
    for _ in range(numPairs):
        for pair in pairs:
            if pair[0] not in [team for match in matchUps[f'Week {week}'] for team in match]:
                if pair[1] not in [team for match in matchUps[f'Week {week}'] for team in match]:
                    if pair not in [match for w in range(week) for match in matchUps[f'Week {w}']] and (pair[1], pair[0]) not in [match for w in range(week) for match in matchUps[f'Week {w}']]:
                        break
        matchUps[f'Week {week}'].append(pair)

print(matchUps)

Output:

{'Week 0': [('Granada', 'Sevilla'), 
            ('Mallorca', 'Barcelona'), 
            ('Real Madrid', 'Atletic Bilbao '), 
            ('Atletico', 'Valencia')], 
 'Week 1': [('Atletic Bilbao ', 'Sevilla'), 
            ('Granada', 'Atletico'), 
            ('Mallorca', 'Valencia'), 
            ('Real Madrid', 'Barcelona')], 
 'Week 2': [('Sevilla', 'Mallorca'), 
            ('Atletic Bilbao ', 'Barcelona'), 
            ('Valencia', 'Granada'), 
            ('Atletico', 'Real Madrid')], 
 'Week 3': [('Sevilla', 'Valencia'), 
            ('Atletico', 'Barcelona'), 
            ('Granada', 'Real Madrid'), 
            ('Mallorca', 'Atletic Bilbao ')], 
 'Week 4': [('Sevilla', 'Real Madrid'), 
            ('Atletico', 'Mallorca'), 
            ('Granada', 'Barcelona'), 
            ('Atletic Bilbao ', 'Valencia')], 
 'Week 5': [('Granada', 'Mallorca'), 
            ('Sevilla', 'Barcelona'), 
            ('Valencia', 'Real Madrid'), 
            ('Atletico', 'Atletic Bilbao ')], 
 'Week 6': [('Sevilla', 'Atletico'), 
            ('Barcelona', 'Valencia'), 
            ('Real Madrid', 'Mallorca'), 
            ('Atletic Bilbao ', 'Granada')]}

This gets the pairs as shown in the comments:

teams = ["Atletico", "Barcelona", "Real Madrid", "Sevilla", "Atletic Bilbao ", "Granada", "Mallorca", "Valencia"]
pairs = [(i, j) for i in teams for j in teams if i != j]

Then it randomizes:

random.shuffle(pairs)

Then gets the needed number of weeks and the needed and the number of pairs for each week:

numWeeks = len(teams) - 1
numPairs = len(teams)//2

Then it loops over the weeks (creating a new week each time):

for week in range(numWeeks):
    matchUps[f'Week {week}'] = []

Then it loops over each needed pair:

for _ in range(numPairs):

For each pair requirement it loops through the no-duplicate list to find an unused pair:

        for pair in pairs:
            if pair[0] not in [team for match in matchUps[f'Week {week}'] for team in match]:
                if pair[1] not in [team for match in matchUps[f'Week {week}'] for team in match]:
                    if pair not in [match for w in range(week) for match in matchUps[f'Week {w}']] and (pair[1], pair[0]) not in [match for w in range(week) for match in matchUps[f'Week {w}']]:
                        break

Once it finds a pair that can be used it places it in the week:

matchUps[f'Week {week}'].append(pair)

NOTE: This gives random home/away assignments, but you could change:

numWeeks = len(teams) - 1

to:

numWeeks = (len(teams) - 1)*2

And that would give a double round-robin where each team was home once and each team was away once. (To do this you would need to make a few minor logic changes.)

Answered By: Eli Harold