Mike
Mike

Reputation: 7831

Python Balanced sports schedule generation

I have the following code sample

import itertools
import random
set_size = 2
schedule = set()
teams = range(10)
for comb in itertools.product(teams, repeat=set_size):
    comb = sorted(list(comb))
    if len(set(comb)) == set_size:
        schedule.add(tuple(comb))

schedule = list(schedule)
random.shuffle(schedule)

home = {}
for game in schedule:
    if home.has_key(game[0]):
        home[game[0]] += 1
    else:
        home[game[0]] = 1


print home

It generates a valid schedule but the issue is some of the teams are very lopsided for home games.

For example a print out of home is

{0: 5, 1: 3, 2: 5, 3: 5, 4: 5, 5: 5, 6: 5, 7: 5, 8: 4, 9: 3}

The key is the team and the value is the number of home games. If I have 10 teams in a league I expect some teams to get 5 home and others to get only 4 but some get 5 while others are getting only 3

Upvotes: 0

Views: 965

Answers (2)

Krzysztof Rosiński
Krzysztof Rosiński

Reputation: 1478

Another example:

import random

data = range(10)
home_games = len(data)/2
home = {}
schedule = []
for d in data:
    home[d] = 0

random.shuffle(data)

for i in range(len(data)):
    for j in range(1,len(data)-i):
        if j < home_games:
            schedule.append((data[i], data[j+i]))
            home[data[i]]+=1
        else:
            schedule.append((data[i+j], data[i]))
            home[data[j+i]]+=1

print home

And the output:

{0: 5, 1: 5, 2: 4, 3: 4, 4: 4, 5: 5, 6: 5, 7: 5, 8: 4, 9: 4}

You can use random.shuffle on the schedule to change the pair order

Upvotes: 1

MattH
MattH

Reputation: 38247

This is a start:

from itertools import combinations

def balance(teams):
  home_count = dict.fromkeys(teams,0)
  max_homes = len(teams)//2
  matches = []
  for a,b in combinations(teams,2):
    if home_count[a] >= max_homes:
      matches.append((b,a))
      home_count[b] += 1
    else:
      matches.append((a,b))
      home_count[a] += 1
  return matches

def home_games(matches):
  counts = {}
  for (a,b) in matches:
    counts[a] = counts.get(a,0) + 1
  return counts

Then

>>> matches = balance(range(10))
>>> home_games(matches)
{0: 5, 1: 5, 2: 5, 3: 5, 4: 5, 5: 4, 6: 4, 7: 4, 8: 4, 9: 4}

You should shuffle the team order passed to balance as the last few teams will always have fewer home matches.

You may also need to distribute the matches so that any one team doesn't play too soon after it's last match, but that will depend on how many games are held concurrently. And is worthy of another SO question.

Upvotes: 1

Related Questions