class PointsControllerTestCase(TestCase): def setUp(self): self.og = Mock() self.oo = Mock() self.cg = Mock() self.co = Mock() self.points_controller = PointsController() self.results_controller = Mock() debate = Mock(OG=self.og, OO=self.oo, CG=self.cg, CO=self.co) result = Mock(debate=debate, og=0, oo=1, cg=2, co=3, ogsp1 = 60, ogsp2 = 65, oosp1 = 70, oosp2 = 75, cgsp1 = 80, cgsp2 = 85, cosp1 = 90, cosp2 = 95) self.results_controller.result_for_team.return_value = result self.points_controller.results_controller = self.results_controller def testGetTeamPoints(self): self.assertEqual(0, self.points_controller.team_points_for_team(self.og, 1), "Did not get correct team score for OG") self.assertEqual(1, self.points_controller.team_points_for_team(self.oo, 1), "Did not get correct team score for OO") self.assertEqual(2, self.points_controller.team_points_for_team(self.cg, 1), "Did not get correct team score for CG") self.assertEqual(3, self.points_controller.team_points_for_team(self.co, 1), "Did not get correct team score for CO") def testGetTeamPointsCallsResultController(self): self.points_controller.team_points_for_team(self.og, 1) self.results_controller.result_for_team.assert_called_once_with(self.og, 1) def testGetTotalPointsCallsCorrectNumberOfRounds(self): self.points_controller.total_points_for_team(self.og, 3) calls = [call(self.og, 1), call(self.og, 2), call(self.og, 3)] self.results_controller.result_for_team.assert_has_calls(calls, any_order=True) def testGetSpeakerPointsReturnsCorrectNumberOfPoints(self): speaks = self.points_controller.speaker_points_for_team(self.og, 1) self.assertEqual(2, len(speaks), "Should only return two speaker points per team") def testSpeakerPointsCorrectForOG(self): speaks = self.points_controller.speaker_points_for_team(self.og, 1) self.assertEqual(speaks[0], 60) self.assertEqual(speaks[1], 65) def testSpeakerPointsCorrectForOO(self): speaks = self.points_controller.speaker_points_for_team(self.oo, 1) self.assertEqual(speaks[0], 70) self.assertEqual(speaks[1], 75) def testSpeakerPointsCorrectForCG(self): speaks = self.points_controller.speaker_points_for_team(self.cg, 1) self.assertEqual(speaks[0], 80) self.assertEqual(speaks[1], 85) def testSpeakerPointsCorrectForCO(self): speaks = self.points_controller.speaker_points_for_team(self.co, 1) self.assertEqual(speaks[0], 90) self.assertEqual(speaks[1], 95)
def total_team_points(self): from results.controllers.PointsController import PointsController controller = PointsController() from draw.models import Tournament return controller.total_points_for_team(self, Tournament.instance().round_with_results)
class DrawController: resultsController = None pointsController = None def __init__(self): self.resultsController = ResultsController() self.pointsController = PointsController() def draw_next_round(self): tournament = Tournament.instance() next_round = tournament.round + 1 pools = self.create_pools(Team.objects.all(), tournament.round) pools = self.remove_empty(pools) pools = self.shuffle_pools(pools) pools = self.balance_pools(pools) debates = self.draw_from_pools(next_round, pools) tournament.round = next_round tournament.save() mapper = VenueMapper() mapper.map_venues(next_round) return debates def create_pools(self, teams, max_round): if not self.resultsController.results_entered_for_round(Tournament.instance().round): raise TournamentStateException("All results for current round must be entered to draw") pools = self.create_blank_pools(max_round) for team in teams: points = self.pointsController.total_points_for_team(team, 1) pools[points].append(team) return pools @staticmethod def create_blank_pools(max_round): pools = {} if max_round == 0: return pools for points in range(0, 4 + ((max_round - 1) * 3)): pools.update({points: []}) return pools @staticmethod def remove_empty(pools): keys = pools.keys() for key in keys: pool = pools[key] if len(pool) < 1: pools.pop(key) return pools @staticmethod def next_viable_pool(current, pools): for i in range(current + 1, len(pools.values())): next_pool = pools.values()[i] if len(next_pool) != 0: return next_pool raise ValueError("No viable pool") @staticmethod def shuffle_pools(pools): for pool in pools.values(): random.shuffle(pool) return pools def balance_pools(self, pools): flattened_pools = [item for sublist in pools.values() for item in sublist] if len(flattened_pools) % 4 != 0: raise ValueError("Number of teams must be divisible by 4") made_swap = True while made_swap: made_swap = False for i in range(0, len(pools.values())): pool = pools.values()[i] if (len(pool) % 4 != 0) and pool != pools.values()[-1]: teams_needed = 4 - (len(pool) % 4) for t in range(0, teams_needed): source_pool = self.next_viable_pool(i, pools) pool.append(source_pool.pop(0)) made_swap = True return pools def draw_from_pools(self, round, pools): debates = [] for pool in pools.values(): if len(pool) % 4 != 0: raise ValueError("Number of teams must be divisible by four") num_debates = len(pool) / 4 for i in range(0, num_debates): debate = Debate(round=round) debate.OG = pool[(i * 4)] debate.OO = pool[(i * 4) + 1] debate.CG = pool[(i * 4) + 2] debate.CO = pool[(i * 4) + 3] debate.full_clean() debate.save() debates.append(debate) return debates