3
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 ?

ToErotimatiko
  • 179
  • 2
  • 3
  • 14

1 Answers1

3

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.)

Eli Harold
  • 2,280
  • 1
  • 3
  • 22
  • Oh !! Now, I see. I would have NOT thought of it that way, it makes total sense. I just realized that I haven't encountered the "While True" (while true what? was my first thought) statement, I just have to look up and learn about it ! Infinite loop ! – ToErotimatiko Mar 04 '22 at 18:42
  • @ToErotimatiko I made an update to the code to fix a slight error. If you previously copied the code, copy the new version instead. – Eli Harold Mar 04 '22 at 19:34
  • Thank you ! I was just testing different lists and lengths to check, believe it or not, I added the same thing ! thank you again! – ToErotimatiko Mar 04 '22 at 20:32
  • @ToErotimatiko Of course, glad I could help! It should work with any even number of teams, I would have to test and debug to make sure it worked properly for uneven numbers of teams. (You may would have to add a `bye` functionality. – Eli Harold Mar 04 '22 at 21:07
  • Hello @Eli Harold. I just realized that there are indeed repeated pairs in the above solution. For example I see Granada - Atletico Bilbao and Barcelona - Real in both week 0 and week 2 – ToErotimatiko Mar 14 '22 at 21:16
  • @ToErotimatiko Thank you for letting me know, I found a small bug in the code, I updated it and it should now work. – Eli Harold Mar 15 '22 at 12:08
  • You are welcome ! I just reviewed these examples and realized it ! I don't really understand why the ''[match for w in range(week) for match in matchUps[f'Week {w}']]" . Is it also checking through all contents of this week, that's it ? – ToErotimatiko Mar 15 '22 at 18:32
  • I just saw also the comment about double round robin. I think this goes more in detail, because in 2 RR the matches should be ''fairly" distributed in the first half and the second half, meaning two teams can't compete both their games in the first or second half but rather split. @Eli Harold – ToErotimatiko Mar 15 '22 at 19:51
  • 1
    @ToErotimatiko I had to change that line because it ONLY checked this week, but we wanted to check all weeks so I had to change it to include those. And yes, you would have to add logic to make sure the halves were split, just adding the `*2` would give all the pairs, but not split correctly. – Eli Harold Mar 15 '22 at 20:19