Python: creazione calendario Fantalega
28 Aprile 2010
Il modulo che regola la creazione del calendario secondo il metodo del cingolo a scorrimento è:
# calendar.py class Calendar(object): def __init__(self, teams, rounds=2): self.teams = teams self.max_rounds = rounds self.team1_home = True self.team2_home = True self.matrix = [] self.first_round_calendar = [] self.season = [] def generate_matrix(self): """ generate_matrix() -> list create a matrix to fill with teams First init matrix with all None fields. The matrix first row is a copy of input iterable (i.e. teams). The matrix second row is the reversed one except the last iterable value that is excluded. """ # init matrix self.matrix = [[None]*len(self.teams) for team in self.teams] # first matrix row with all teams (header) i.e. [1, 2, 3, 4] self.matrix[0] = self.teams # reversed header without the last team i.e. [3, 2, 1, None] row2 = self.teams[:][:-1] row2.reverse() self.matrix[1][0:(len(self.teams) - 1)] = row2[0:(len(self.teams) - 1)] def matrix_rotation(self): """ matrix_rotation() -> list This is the first step of matrix composition. if the first row is [3, 2, 1, None], the second one will be the last value except None of the first row at postion 1 and then the other values rotated: [1, 3, 2, None] The last row will be [2, 1, 3, None] """ i = 1 while i < len(self.teams): k = 1 for item in self.matrix[i]: try: self.matrix[i + 1][k] = item self.matrix[i + 1][0] = self.matrix[i + 1][( len(self.teams) - 1)] self.matrix[i + 1][(len(self.teams) - 1)] = None k += 1 except IndexError: break i += 1 def matrix_substitution(self): """ matrix_substitution() -> list This is the second step of matrix composition. If the matrix header and a matrix row for the same index, have the same value the row index moves his value in place of 'None' and gets the excluded value of the previous matrix generation (4): [1, 2, 3, 4] [3, 2, 1, None] --> 2 has same index of header [3, 4, 1, 2] 4 take place of 2 and 2 substitutes None """ row_m = 1 while row_m < len(self.teams): for item_a in self.matrix[0]: for item_b in self.matrix[row_m]: if self.matrix[0].index(item_a) == \ self.matrix[row_m].index(item_b): # when a value has the same index than header if item_a == item_b: # the value is substituted by the excluded one (e.g. 4) self.matrix[row_m][self.matrix[row_m].index(item_b)] = \ self.teams[-1] self.matrix[row_m][(len(self.teams) - 1)] = item_b row_m += 1 def match_composition(self): """ match_composition() -> list Match composition: third step coupling the first team of header with the matrix first-row team with same index. The second team of header is coupled with the second team of the matrix first row. We get teams only if the team are not chosen yet, to avoid duplicated match if header team or n-row one is duplicate, we pass to the other column I.e. At day 1 we couple header team with same index first-row team, at day 2 we couple header team with same index second-row team and so on. """ cal = [] day = 1 while day < len(self.teams): first_round = [] for team1 in self.matrix[0]: index = self.matrix[0].index(team1) team2 = self.matrix[day][index] if team2 not in first_round or team1 not in first_round: if self.team1_home is True: first_round.append(team1) first_round.append(team2) cal.append((day, team1, team2)) self.team1_home = False self.team2_home = True else: first_round.append(team2) first_round.append(team1) cal.append((day, team2, team1)) self.team1_home = True self.team2_home = False day += 1 return cal def generate_2nd_round(self): """ generate_2nd_round() -> list Create the second round for half calendar Tuples have "day, team_a, team_b" format """ return [(int(n) + len(self.teams) - 1, team2, team1) for n, team1, team2 in self.first_round_calendar] def build_season(self): """ build_season() -> list generate a match calendar iterable. Tuples have "day, team_a, team_b" format """ n_round = 1 self.generate_matrix() self.matrix_rotation() self.matrix_substitution() self.first_round_calendar = self.match_composition() while n_round < self.max_rounds: second_round = self.generate_2nd_round() self.season = self.first_round_calendar + second_round n_round += 1 return self.season
Una piccola interfaccia per l’inserimento delle squadre:
# main.py import wx from random import shuffle from calendar import Calendar def get_teams(): app = wx.App() app.MainLoop() teams = [] dlg = wx.TextEntryDialog(None, "number of teams?", 'INFO', '') if dlg.ShowModal() == wx.ID_OK: try: nteams = int(dlg.GetValue()) except ValueError: print "ERROR: Need a number!" else: # exit if number of teams is < 2 if nteams < 2: print "ERROR: number of teams must be >= 2" else: team_no = 1 while team_no <= nteams: dlgt = wx.TextEntryDialog(None, "team name n. %d?" % (team_no), 'INFO', '') if dlgt.ShowModal() == wx.ID_OK: name = dlgt.GetValue() if name in teams: print "ERROR: team <%s> already exists" % name dlgt.SetValue('') else: teams.append(name) dlgt.SetValue('') team_no += 1 # Add fake team if number of teams is odd if nteams % 2 != 0: teams.append('Fake Team') return teams if __name__ == '__main__': teams = get_teams() # shuffle(teams) if teams: cal = Calendar(teams=teams) season = cal.build_season() for match in season: print match else: print "WARNING: no teams saved"
Un piccolo abbozzo di tests:
import unittest from calendar import Calendar class CalendarInitTestCase(unittest.TestCase): def setUp(self): self.teams = ['Inter', 'Milan', 'Juve', 'Napoli'] self.cal = Calendar(self.teams) def tearDown(self): self.teams = [] def test_default_rounds(self): self.assertEqual(self.cal.max_rounds, 2) def test_default_teams(self): self.assertEqual(self.cal.teams, self.teams) class CalendarMatrixTestCase(unittest.TestCase): def setUp(self): self.teams = ['Inter', 'Milan', 'Juve', 'Napoli'] self.cal = Calendar(self.teams) self.cal.generate_matrix() def tearDown(self): self.cal.teams = [] self.cal.matrix = [] def test_matrix_header(self): self.assertEqual(self.cal.matrix[0], self.teams) def test_matrix_first_row_before_rotation(self): self.assertEqual(self.cal.matrix[1], ['Juve', 'Milan', 'Inter', None]) def test_matrix_second_row_before_rotation(self): self.assertEqual(self.cal.matrix[2], [None, None, None, None]) def test_matrix_third_row_before_rotation(self): self.assertEqual(self.cal.matrix[3], [None, None, None, None]) def test_matrix_second_row_after_rotation(self): self.cal.matrix_rotation() self.assertEqual(self.cal.matrix[2], ['Inter', 'Juve', 'Milan', None]) def test_matrix_third_row_after_rotation(self): self.cal.matrix_rotation() self.assertEqual(self.cal.matrix[3], ['Milan', 'Inter', 'Juve', None]) def test_matrix_first_row_after_substitution(self): self.cal.matrix_rotation() self.cal.matrix_substitution() self.assertEqual(self.cal.matrix[1], ['Juve', 'Napoli', 'Inter', 'Milan']) def test_matrix_second_row_after_substitution(self): self.cal.matrix_rotation() self.cal.matrix_substitution() self.assertEqual(self.cal.matrix[2], ['Napoli', 'Juve', 'Milan', 'Inter']) def test_matrix_third_row_after_substitution(self): self.cal.matrix_rotation() self.cal.matrix_substitution() self.assertEqual(self.cal.matrix[3], ['Milan', 'Inter', 'Napoli', 'Juve']) class CalendarSeasonTestCase(unittest.TestCase): def setUp(self): self.teams = ['Inter', 'Milan', 'Juve', 'Napoli'] self.cal = Calendar(self.teams) self.cal.generate_matrix() self.cal.matrix_rotation() self.cal.matrix_substitution() self.season = [(1, 'Inter', 'Juve'), (1, 'Napoli', 'Milan'), (2, 'Inter', 'Napoli'), (2, 'Juve', 'Milan'), (3, 'Inter', 'Milan'), (3, 'Napoli', 'Juve'), (4, u'Juve', u'Inter'), (4, u'Milan', u'Napoli'), (5, u'Napoli', u'Inter'), (5, u'Milan', u'Juve'), (6, u'Milan', u'Inter'), (6, u'Juve', u'Napoli')] def tearDown(self): self.cal.teams = [] self.cal.matrix = [] def test_1st_round_season(self): self.cal.build_season() self.assertEqual(self.cal.first_round_calendar, self.season[:len(self.season)/2]) def test_complete_season(self): self.cal.build_season() self.assertEqual(self.cal.season, self.season) if __name__ == '__main__': suite1 = unittest.TestLoader().loadTestsFromTestCase(CalendarInitTestCase) suite2 = unittest.TestLoader().loadTestsFromTestCase(CalendarMatrixTestCase) suite3 = unittest.TestLoader().loadTestsFromTestCase(CalendarSeasonTestCase) alltests = unittest.TestSuite([suite1, suite2, suite3]) unittest.TextTestRunner(verbosity=2).run(alltests)
Commenti recenti