Hey, the more the merrier as far as I'm concerned
Here's a snippet of what I put together actually nearly 12 months ago, checking the time stamp of the file. I've made a few small changes just now, but I haven't tested anything yet, so there may be typos/errors if you try run the below currently (just working out of notepad at the moment...)
The part that was frustrating me was the 'get_valid_game_days' method. There's nothing in the code below for this, but I spent an hour or so playing around on the python command line trying to solve this - basically, need to take a date range, and calculate all the valid game days within this range, grouped by week. The timedate library has some cool functionality that should make this possible, but I'll be darned if I could crack it - this was that "math-level" stuff I mentioned above that I struggle with.
For example, if Friday and Saturday were the only valid days, and the date range was for 4 weeks starting this week, the output of this method should be:
[[16/12/2016, 17/12/2016], [23/12/2016, 24/12/2016], [30/12/2016, 31/12/2016], [6/1/2017, 7/1/2017]]
As a rule I generally work with all dates as ordinal numbers - datetime objects have a .toordinal() method. I just trust it more, especially when writing to databases.
Code:
class ScheduleGen:
def __init__(self, current_year=2016, season_start_month=9, season_start_day=30, season_end_month=3, season_end_day=28):
self.current_year = current_year
self.season_start_month = season_start_month
def create_round_robin_schedule(self, team_ids=None, play_each_team=3, valid_days={'monday': False, 'tuesday': False, 'wednesday': False, 'thursday': False,
'friday': True, 'saturday': True,
'sunday': True}):
matchups = self.generate_round_robin_matchups(teams=team_ids, play_each_team=play_each_team)
valid_game_days = self.get_valid_game_days(valid_game_days=valid_days)
def get_valid_game_days(self, valid_game_days):
'''
Parameters:
:valid_game_days: (dict) A dictionary of each day of the week and a True/False value.
Returns:
A list of all possible game days, in ordinal format.
'''
# This is where I had trouble. What is needed here is to use the current_year/season_start_month/season_start_day,
# the current_year+1/season_end_month/season_end_date, and the valid_game_days dictionary to compile a list of
# all available dates, grouped in weeks (to ensure teams don't always play multiple games in the same week),
# with the dates stored as ordinals (whole numbers - a feature of the timedate module), similar to this:
# valid_dates = [[734228, 734229],[734235, 734236],[734241. 734242]] etc.
pass
@staticmethod
def generate_round_robin_matchups(teams=None, play_each_team=1):
'''
Note: Bulk of this code taken from: https://gist.github.com/Makistos/7192777
Parameters:
:teams: (list) league team IDs.
:play_each_team: (int) how many times all teams play each other.
Returns:
A list of all valid matchups.
'''
matchups = []
if len(teams) % 2 == 1:
#teams = teams + ['BYE']
teams.append(False)
for i in range((len(teams) - 1) * play_each_team):
mid = round(len(teams) / 2)
l1 = teams[:mid]
l2 = teams[mid:]
l2.reverse()
# Switch sides after each round
if(i % 2 == 1):
matchups = matchups + [ zip(l1, l2) ]
else:
matchups = matchups + [ zip(l2, l1) ]
teams.insert(1, teams.pop())
return matchups