Home > python, wxpython > Python: creazione calendario Fantalega

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)
Categorie:python, wxpython Tag: ,
I commenti sono chiusi.