def _test_match_generation(self, teams, multiplier=1):
     """Test even-numbered round-robin match generation (actual code)."""
     meetings = multiplier * 2
     scheduler = RoundRobinScheduler(teams, meetings=meetings)
     expected = list(itertools.permutations(scheduler.teams, 2)) * multiplier
     matches = scheduler.generate_matches()
     self.assertCountEqual(expected, matches,
                           ('Incorrect matches generated for even-numbered '
                            'round-robin schedule with {} meetings for '
                            '{} teams.').format(meetings, teams))
 def _test_match_generation(self, teams, multiplier=1):
     """Test even-numbered round-robin match generation (actual code)."""
     meetings = multiplier * 2
     scheduler = RoundRobinScheduler(teams, meetings=meetings)
     expected = list(itertools.permutations(scheduler.teams,
                                            2)) * multiplier
     matches = scheduler.generate_matches()
     self.assertCountEqual(expected, matches,
                           ('Incorrect matches generated for even-numbered '
                            'round-robin schedule with {} meetings for '
                            '{} teams.').format(meetings, teams))
    def _test_match_generation(self, teams, evens=0, known_home_teams=None):
        """Test odd-numbered round-robin match generation."""
        meetings = 2 * evens + 1
        team_list = list(range(1, teams + 1))
        scheduler = RoundRobinScheduler(teams, meetings=meetings)
        self.assertSequenceEqual(scheduler.home_teams, (),
                                 'Default home teams not returned.')
        matches = scheduler.generate_matches(home_teams=known_home_teams)
        if known_home_teams:
            self.assertSequenceEqual(known_home_teams, scheduler.home_teams,
                                     'Home teams not stored.')

        homes = [match[0] for match in matches]
        aways = [match[1] for match in matches]
        home_teams = 0
        away_teams = 0
        odd_teams = teams % 2 == 1
        if odd_teams:
            teams += 1
            team_list.append(None)

        more_matches = evens * (teams - 1) + int(teams / 2)
        less_matches = more_matches - 1

        home_match_counts = collections.Counter(homes)
        away_match_counts = collections.Counter(aways)
        for team in team_list:
            home_count = home_match_counts[team]
            away_count = away_match_counts[team]
            self.assertTrue(
                (home_count == more_matches or home_count == less_matches),
                'Team has an illegal number of home matches.')
            self.assertTrue(
                (away_count == more_matches or away_count == less_matches),
                'Team has an illegal number of away matches.')
            if home_count == more_matches:
                if known_home_teams:
                    self.assertIn(team, known_home_teams,
                                  'Home team designation violated.')
                self.assertEqual(away_count, less_matches,
                                 'Wrong number of away matches.')
                home_teams += 1
            else:
                if known_home_teams:
                    self.assertNotIn(team, known_home_teams,
                                     'Away team designation violated.')
                self.assertEqual(away_count, more_matches,
                                 'Wrong number of away matches.')
                away_teams += 1

        self.assertEqual(home_teams, away_teams,
                         'Home and away team counts not balanced.')
    def _test_match_generation(self, teams, evens=0, known_home_teams=None):
        """Test odd-numbered round-robin match generation."""
        meetings = 2 * evens + 1
        team_list = list(range(1, teams + 1))
        scheduler = RoundRobinScheduler(teams, meetings=meetings)
        self.assertSequenceEqual(scheduler.home_teams, (),
                                 'Default home teams not returned.')
        matches = scheduler.generate_matches(home_teams=known_home_teams)
        if known_home_teams:
            self.assertSequenceEqual(known_home_teams, scheduler.home_teams,
                                     'Home teams not stored.')

        homes = [match[0] for match in matches]
        aways = [match[1] for match in matches]
        home_teams = 0
        away_teams = 0
        odd_teams = teams % 2 == 1
        if odd_teams:
            teams += 1
            team_list.append(None)

        more_matches = evens * (teams - 1) + int(teams / 2)
        less_matches = more_matches - 1

        home_match_counts = collections.Counter(homes)
        away_match_counts = collections.Counter(aways)
        for team in team_list:
            home_count = home_match_counts[team]
            away_count = away_match_counts[team]
            self.assertTrue((home_count == more_matches or
                             home_count == less_matches),
                            'Team has an illegal number of home matches.')
            self.assertTrue((away_count == more_matches or
                             away_count == less_matches),
                            'Team has an illegal number of away matches.')
            if home_count == more_matches:
                if known_home_teams:
                    self.assertIn(team, known_home_teams,
                                  'Home team designation violated.')
                self.assertEqual(away_count, less_matches,
                                 'Wrong number of away matches.')
                home_teams += 1
            else:
                if known_home_teams:
                    self.assertNotIn(team, known_home_teams,
                                     'Away team designation violated.')
                self.assertEqual(away_count, more_matches,
                                 'Wrong number of away matches.')
                away_teams += 1

        self.assertEqual(home_teams, away_teams,
                         'Home and away team counts not balanced.')
    def _test_matrix_generation(self, meetings, teams,
                                known_home_teams=None):
        """Test odd-numbered round-robin matrix generation."""
        scheduler = RoundRobinScheduler(teams, meetings=meetings)
        self.assertSequenceEqual(scheduler.home_teams, (),
                                 'Default home teams not returned.')
        matrix = scheduler.generate_matrix(home_teams=known_home_teams)
        if known_home_teams:
            self.assertSequenceEqual(known_home_teams, scheduler.home_teams,
                                     'Home teams not stored.')
        home_teams = 0
        away_teams = 0
        odd_teams = teams % 2 == 1
        if odd_teams:
            teams += 1

        for x in range(teams):
            self.assertIsNone(matrix[x][x], 'Match against self not None.')
            opponents = matrix[x]
            home_count = opponents.count(True)
            away_count = opponents.count(False)
            if home_count > away_count:
                home_teams += 1
                if known_home_teams:
                    self.assertIn(scheduler.teams[x], known_home_teams,
                                  'Home team designation violated.')
                self.assertEqual(home_count, away_count + 1,
                                 'Team has too many home opponents.')
                if odd_teams and x != teams - 1:
                    self.assertTrue(opponents[-1],
                                    'Home excess not balanced by bye round.')
            else:
                away_teams += 1
                if known_home_teams:
                    self.assertNotIn(scheduler.teams[x], known_home_teams,
                                     'Away team designation violated.')
                self.assertEqual(away_count, home_count + 1,
                                 'Team has too many away opponents.')
                if odd_teams and x != teams - 1:
                    self.assertFalse(opponents[-1],
                                     'Away excess not balanced by bye round.')

        self.assertEqual(home_teams, away_teams,
                         'Home and away team counts not balanced.')
    def _test_matrix_generation(self, meetings, teams, known_home_teams=None):
        """Test odd-numbered round-robin matrix generation."""
        scheduler = RoundRobinScheduler(teams, meetings=meetings)
        self.assertSequenceEqual(scheduler.home_teams, (),
                                 'Default home teams not returned.')
        matrix = scheduler.generate_matrix(home_teams=known_home_teams)
        if known_home_teams:
            self.assertSequenceEqual(known_home_teams, scheduler.home_teams,
                                     'Home teams not stored.')
        home_teams = 0
        away_teams = 0
        odd_teams = teams % 2 == 1
        if odd_teams:
            teams += 1

        for x in range(teams):
            self.assertIsNone(matrix[x][x], 'Match against self not None.')
            opponents = matrix[x]
            home_count = opponents.count(True)
            away_count = opponents.count(False)
            if home_count > away_count:
                home_teams += 1
                if known_home_teams:
                    self.assertIn(scheduler.teams[x], known_home_teams,
                                  'Home team designation violated.')
                self.assertEqual(home_count, away_count + 1,
                                 'Team has too many home opponents.')
                if odd_teams and x != teams - 1:
                    self.assertTrue(opponents[-1],
                                    'Home excess not balanced by bye round.')
            else:
                away_teams += 1
                if known_home_teams:
                    self.assertNotIn(scheduler.teams[x], known_home_teams,
                                     'Away team designation violated.')
                self.assertEqual(away_count, home_count + 1,
                                 'Team has too many away opponents.')
                if odd_teams and x != teams - 1:
                    self.assertFalse(opponents[-1],
                                     'Away excess not balanced by bye round.')

        self.assertEqual(home_teams, away_teams,
                         'Home and away team counts not balanced.')
 def test_wrappers(self):
     """Test that named RoundRobinScheduler wrappers are equivalent."""
     wrappers = [
         SingleRoundRobinScheduler, DoubleRoundRobinScheduler,
         TripleRoundRobinScheduler, QuadrupleRoundRobinScheduler
     ]
     for i in range(4):
         meetings = i + 1
         wrapper = wrappers[i]
         direct_scheduler = RoundRobinScheduler(4, meetings=meetings)
         wrapped_scheduler = wrapper(4)
         self.assertTrue(
             issubclass(wrapped_scheduler.__class__,
                        direct_scheduler.__class__),
             'Wrapper class is not a subclass of base class.')
         self.assertEqual(
             direct_scheduler.find_unique_match,
             wrapped_scheduler.find_unique_match,
             'find_unique_match different in base and wrapper.')
         self.assertEqual(direct_scheduler.matches_share_opponents,
                          wrapped_scheduler.matches_share_opponents,
                          ('matches_share_opponents different in base and '
                           'wrapper.'))
         self.assertEqual(
             direct_scheduler.generate_matches.__func__,
             wrapped_scheduler.generate_matches.__func__,
             'generate_matches different in base and wrapper.')
         self.assertEqual(direct_scheduler.generate_matrix.__func__,
                          wrapped_scheduler.generate_matrix.__func__,
                          'generate_matrix different in base and wrapper.')
         self.assertEqual(direct_scheduler.generate_round.__func__,
                          wrapped_scheduler.generate_round.__func__,
                          'generate_round different in base and wrapper.')
         self.assertEqual(
             direct_scheduler.generate_schedule.__func__,
             wrapped_scheduler.generate_schedule.__func__,
             'generate_schedule different in base and wrapper.')
 def test_schedule_generation(self):
     """Test sextuple round-robin schedule generation."""
     scheduler = RoundRobinScheduler(6, meetings=6)
     # Failed attempt
     random.seed(35)
     self.assertRaises(ScheduleGenerationFailed,
                       scheduler.generate_schedule,
                       try_once=True)
     # Successful attempt
     random.seed(1)
     if PY2:
         expected_schedule = [[(6, 4), (3, 1), (2, 5)],
                              [(3, 1), (6, 5), (4, 2)],
                              [(6, 1), (2, 3), (5, 4)],
                              [(5, 1), (2, 6), (3, 4)],
                              [(1, 6), (2, 5), (3, 4)],
                              [(5, 6), (4, 3), (2, 1)],
                              [(2, 6), (3, 5), (4, 1)],
                              [(3, 1), (2, 5), (4, 6)],
                              [(1, 4), (3, 5), (6, 2)],
                              [(1, 2), (5, 4), (6, 3)],
                              [(5, 2), (6, 4), (1, 3)],
                              [(1, 3), (4, 2), (6, 5)],
                              [(5, 3), (2, 6), (4, 1)],
                              [(5, 1), (4, 6), (3, 2)],
                              [(3, 2), (1, 6), (4, 5)],
                              [(1, 3), (4, 6), (5, 2)],
                              [(3, 6), (4, 5), (2, 1)],
                              [(2, 3), (4, 5), (1, 6)],
                              [(1, 2), (5, 3), (6, 4)],
                              [(4, 1), (3, 2), (6, 5)],
                              [(1, 4), (6, 3), (5, 2)],
                              [(1, 5), (3, 6), (4, 2)],
                              [(5, 1), (2, 4), (6, 3)],
                              [(1, 2), (3, 6), (5, 4)],
                              [(5, 6), (1, 4), (2, 3)],
                              [(5, 3), (6, 1), (2, 4)],
                              [(4, 3), (1, 5), (6, 2)],
                              [(2, 1), (3, 4), (5, 6)],
                              [(6, 1), (2, 4), (3, 5)],
                              [(1, 5), (6, 2), (4, 3)]]
     elif PY3:
         expected_schedule = [[(6, 4), (2, 3), (5, 1)],
                              [(4, 5), (1, 2), (3, 6)],
                              [(3, 4), (1, 2), (6, 5)],
                              [(2, 6), (5, 3), (4, 1)],
                              [(6, 3), (1, 5), (2, 4)],
                              [(5, 6), (3, 2), (1, 4)],
                              [(6, 1), (4, 2), (5, 3)],
                              [(1, 3), (6, 4), (5, 2)],
                              [(5, 1), (3, 4), (6, 2)],
                              [(4, 1), (5, 6), (3, 2)],
                              [(4, 5), (6, 1), (2, 3)],
                              [(2, 1), (5, 4), (3, 6)],
                              [(6, 2), (4, 5), (3, 1)],
                              [(1, 5), (2, 4), (3, 6)],
                              [(2, 6), (1, 5), (4, 3)],
                              [(4, 6), (2, 1), (5, 3)],
                              [(3, 1), (2, 5), (6, 4)],
                              [(1, 6), (4, 2), (3, 5)],
                              [(6, 1), (2, 3), (5, 4)],
                              [(1, 4), (6, 2), (3, 5)],
                              [(5, 2), (1, 4), (6, 3)],
                              [(5, 6), (2, 4), (3, 1)],
                              [(3, 4), (6, 5), (1, 2)],
                              [(2, 5), (4, 1), (6, 3)],
                              [(4, 3), (5, 1), (2, 6)],
                              [(2, 5), (4, 6), (1, 3)],
                              [(1, 3), (5, 2), (4, 6)],
                              [(1, 6), (5, 4), (3, 2)],
                              [(2, 1), (4, 3), (6, 5)],
                              [(3, 5), (1, 6), (4, 2)]]
     schedule = scheduler.generate_schedule(try_once=True)
     self.assertListEqual(expected_schedule, schedule,
                          ('Wrong schedule created for '
                           'sextuple round-robin competition'))
 def test_schedule_generation(self):
     """Test sextuple round-robin schedule generation."""
     scheduler = RoundRobinScheduler(6, meetings=6)
     # Failed attempt
     random.seed(35)
     self.assertRaises(ScheduleGenerationFailed,
                       scheduler.generate_schedule, try_once=True)
     # Successful attempt
     random.seed(1)
     if PY2:
         expected_schedule = [
             [(6, 4), (3, 1), (2, 5)],
             [(3, 1), (6, 5), (4, 2)],
             [(6, 1), (2, 3), (5, 4)],
             [(5, 1), (2, 6), (3, 4)],
             [(1, 6), (2, 5), (3, 4)],
             [(5, 6), (4, 3), (2, 1)],
             [(2, 6), (3, 5), (4, 1)],
             [(3, 1), (2, 5), (4, 6)],
             [(1, 4), (3, 5), (6, 2)],
             [(1, 2), (5, 4), (6, 3)],
             [(5, 2), (6, 4), (1, 3)],
             [(1, 3), (4, 2), (6, 5)],
             [(5, 3), (2, 6), (4, 1)],
             [(5, 1), (4, 6), (3, 2)],
             [(3, 2), (1, 6), (4, 5)],
             [(1, 3), (4, 6), (5, 2)],
             [(3, 6), (4, 5), (2, 1)],
             [(2, 3), (4, 5), (1, 6)],
             [(1, 2), (5, 3), (6, 4)],
             [(4, 1), (3, 2), (6, 5)],
             [(1, 4), (6, 3), (5, 2)],
             [(1, 5), (3, 6), (4, 2)],
             [(5, 1), (2, 4), (6, 3)],
             [(1, 2), (3, 6), (5, 4)],
             [(5, 6), (1, 4), (2, 3)],
             [(5, 3), (6, 1), (2, 4)],
             [(4, 3), (1, 5), (6, 2)],
             [(2, 1), (3, 4), (5, 6)],
             [(6, 1), (2, 4), (3, 5)],
             [(1, 5), (6, 2), (4, 3)]
         ]
     elif PY3:
         expected_schedule = [
             [(6, 4), (2, 3), (5, 1)],
             [(4, 5), (1, 2), (3, 6)],
             [(3, 4), (1, 2), (6, 5)],
             [(2, 6), (5, 3), (4, 1)],
             [(6, 3), (1, 5), (2, 4)],
             [(5, 6), (3, 2), (1, 4)],
             [(6, 1), (4, 2), (5, 3)],
             [(1, 3), (6, 4), (5, 2)],
             [(5, 1), (3, 4), (6, 2)],
             [(4, 1), (5, 6), (3, 2)],
             [(4, 5), (6, 1), (2, 3)],
             [(2, 1), (5, 4), (3, 6)],
             [(6, 2), (4, 5), (3, 1)],
             [(1, 5), (2, 4), (3, 6)],
             [(2, 6), (1, 5), (4, 3)],
             [(4, 6), (2, 1), (5, 3)],
             [(3, 1), (2, 5), (6, 4)],
             [(1, 6), (4, 2), (3, 5)],
             [(6, 1), (2, 3), (5, 4)],
             [(1, 4), (6, 2), (3, 5)],
             [(5, 2), (1, 4), (6, 3)],
             [(5, 6), (2, 4), (3, 1)],
             [(3, 4), (6, 5), (1, 2)],
             [(2, 5), (4, 1), (6, 3)],
             [(4, 3), (5, 1), (2, 6)],
             [(2, 5), (4, 6), (1, 3)],
             [(1, 3), (5, 2), (4, 6)],
             [(1, 6), (5, 4), (3, 2)],
             [(2, 1), (4, 3), (6, 5)],
             [(3, 5), (1, 6), (4, 2)]
         ]
     schedule = scheduler.generate_schedule(try_once=True)
     self.assertListEqual(expected_schedule, schedule,
                          ('Wrong schedule created for '
                           'sextuple round-robin competition'))