Esempio n. 1
0
def build_5_matches(places):
    return [
        {
            'A':
            Match(0,
                  'Quarter 1 (#0)',
                  'A',
                  places[0],
                  datetime(2014, 4, 27, 14, 30),
                  datetime(2014, 4, 27, 14, 35),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(1,
                  'Quarter 2 (#1)',
                  'A',
                  places[1],
                  datetime(2014, 4, 27, 14, 35),
                  datetime(2014, 4, 27, 14, 40),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(2,
                  'Semi 1 (#2)',
                  'A',
                  places[2],
                  datetime(2014, 4, 27, 14, 45),
                  datetime(2014, 4, 27, 14, 50),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(3,
                  'Semi 2 (#3)',
                  'A',
                  places[3],
                  datetime(2014, 4, 27, 14, 50),
                  datetime(2014, 4, 27, 14, 55),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(4,
                  'Final (#4)',
                  'A',
                  places[4],
                  datetime(2014, 4, 27, 15, 0),
                  datetime(2014, 4, 27, 15, 5),
                  MatchType.knockout,
                  use_resolved_ranking=False)
        },
    ]
Esempio n. 2
0
def test_knockout_match_winners_tie():
    knockout_positions = {
        ('A', 2): OrderedDict([
            ('JKL', 1),
            ('GHI', 2),
            ('DEF', 3),
            ('ABC', 4),
        ])
    }
    # Deliberately out of order as some python implementations
    # use the creation order of the tuples as a fallback sort comparison
    positions = {
        'ABC': 1,
        'DEF': 4,
        'GHI': 3,
        'JKL': 2,
    }
    scheduler = get_scheduler(knockout_positions = knockout_positions, \
                                positions = positions)

    game = Match(2, 'Match 2', 'A', [], None, None, None, False)
    winners = scheduler.get_winners(game)

    assert set(winners) == set(['GHI', 'JKL']), \
            "Should used the league positions to resolve the tie"
    def _add_match(self, match_info, rounds_remaining, round_num):
        new_matches = {}

        arena = match_info['arena']
        start_time = match_info['start_time']
        end_time = start_time + self.schedule.match_duration
        num = len(self.schedule.matches)

        teams = []
        for team_ref in match_info['teams']:
            teams.append(self.get_team(team_ref))

        if len(teams) < 4:
            "Fill empty zones with None"
            teams += [None] * (4 - len(teams))

        display_name = self.get_match_display_name(rounds_remaining, round_num,
                                                   num)
        is_final = rounds_remaining == 0
        match = Match(num,
                      display_name,
                      arena,
                      teams,
                      start_time,
                      end_time,
                      MatchType.knockout,
                      use_resolved_ranking=not is_final)
        self.knockout_rounds[-1].append(match)

        new_matches[match_info['arena']] = match

        self.schedule.matches.append(new_matches)
        self.period.matches.append(new_matches)
Esempio n. 4
0
def make_schedule():
    settings = {'match_periods': {'league': [], 'knockout': []},
                'match_slot_lengths': {'pre': 90,
                                       'match': 180,
                                       'post': 30,
                                       'total': 300},
                'staging': {'opens': 300,
                            'closes': 120,
                            'duration': 180,
                            'signal_shepherds': {'Blue': 241,
                                                 'Green': 181},
                            'signal_teams': 240},
                'league': { 'extra_spacing': [], },
                'delays': []}
    teams = defaultdict(lambda: Team(None, None, False, None))
    schedule = MatchSchedule(settings, {}, teams, 4)

    finals = Match(num=0, display_name='Match 0',
                   arena='A',
                   teams=['AAA', 'BBB', 'CCC', 'DDD'],
                   start_time=datetime.datetime(2014, 4, 25, 12, 0),
                   end_time=datetime.datetime(2014, 4, 25, 12, 5),
                   type=MatchType.knockout, use_resolved_ranking=False)
    schedule.knockout_rounds = [[finals]]
    schedule.matches.append({'A':finals})

    return schedule
Esempio n. 5
0
def test_first_round_before_league_end():
    positions = OrderedDict()
    positions['ABC'] = 1
    positions['CDE'] = 2
    positions['EFG'] = 3
    positions['GHI'] = 4

    # Fake a couple of league matches that won't have been scored
    matches = [
        {
            'A': Match(0, 'Match 0', 'A', [], None, None, MatchType.league,
                       False)
        },
        {
            'A': Match(1, 'Match 1', 'A', [], None, None, MatchType.league,
                       False)
        },
    ]
    scheduler = get_scheduler(matches, positions=positions)

    def seeder(*args):
        assert args[0] == 4, "Wrong number of teams"
        return [[0, 1, 2, 3]]

    # Mock the random (even thought it's not really random)
    scheduler.R = mock.Mock()
    # Mock the seeder to make it less interesting
    with mock.patch(
            'sr.comp.knockout.first_round_seeding') as first_round_seeding:
        first_round_seeding.side_effect = seeder
        scheduler.add_knockouts()

    knockout_rounds = scheduler.knockout_rounds

    assert len(knockout_rounds) == 1, "Should be finals only"
    finals = knockout_rounds[0]

    assert len(finals) == 1, "Should be one final"
    final = finals[0]
    final_teams = final.teams

    # No scores yet -- should just list as ???
    expected_teams = [UNKNOWABLE_TEAM] * 4

    assert expected_teams == final_teams, "Should not show teams until league complete"
Esempio n. 6
0
    def _build_matchlist(self, yamldata):
        """Build the match list."""
        self.matches = []
        if yamldata is None:
            self.n_planned_league_matches = 0
            return

        match_numbers = sorted(yamldata.keys())
        self.n_planned_league_matches = len(match_numbers)

        if tuple(match_numbers) != tuple(range(len(match_numbers))):
            raise Exception("Matches are not a complete 0-N range")

        # Effectively just the .values(), except that it's ordered by number
        raw_matches = [yamldata[m] for m in match_numbers]

        match_n = 0

        for period in self.match_periods:
            # Fill this period with matches

            clock = MatchPeriodClock(period, self.delays)

            # No extra spacing for matches at the start of a period

            # Fill this match period with matches
            for start in clock.iterslots(self.match_duration):
                try:
                    arenas = raw_matches.pop(0)
                except IndexError:
                    # no more matches left
                    break

                m = {}

                end_time = start + self.match_duration
                for arena_name, teams in arenas.items():
                    teams = self.remove_drop_outs(teams, match_n)
                    display_name = 'Match {n}'.format(n=match_n)
                    match = Match(match_n,
                                  display_name,
                                  arena_name,
                                  teams,
                                  start,
                                  end_time,
                                  MatchType.league,
                                  use_resolved_ranking=False)
                    m[arena_name] = match

                period.matches.append(m)
                self.matches.append(m)

                match_n += 1

                extra_spacing = self._spacing.get(match_n)
                if extra_spacing:
                    clock.advance_time(extra_spacing)
Esempio n. 7
0
def build_match(num,
                arena,
                teams=None,
                start_time=None,
                end_time=None,
                type_=None,
                use_resolved_ranking=False):
    return Match(num, 'Match {n}'.format(n=num), arena, teams, start_time,
                 end_time, type_, use_resolved_ranking)
    def _add_round_of_matches(self, matches, arenas, rounds_remaining):
        """
        Add a whole round of matches.

        :param list matches: A list of lists of teams for each match.
        """

        self.knockout_rounds += [[]]

        round_num = 0
        while len(matches):
            # Deliberately not using iterslots since we need to ensure
            # that the time advances even after we've run out of matches
            start_time = self.clock.current_time
            end_time = start_time + self.schedule.match_duration

            new_matches = {}
            for arena in arenas:
                teams = matches.pop(0)

                if len(teams) < 4:
                    "Fill empty zones with None"
                    teams += [None] * (4 - len(teams))

                # Randomise the zones
                self.R.shuffle(teams)

                num = len(self.schedule.matches)
                display_name = self.get_match_display_name(
                    rounds_remaining, round_num, num)

                match = Match(
                    num,
                    display_name,
                    arena,
                    teams,
                    start_time,
                    end_time,
                    MatchType.knockout,
                    # Just the finals don't use the resolved ranking
                    use_resolved_ranking=rounds_remaining != 0)

                self.knockout_rounds[-1].append(match)
                new_matches[arena] = match

                if len(matches) == 0:
                    break

            self.clock.advance_time(self.schedule.match_duration)
            self.schedule.matches.append(new_matches)
            self.period.matches.append(new_matches)

            round_num += 1
Esempio n. 9
0
def test_knockout_match_winners_irrelevant_tie_1():
    knockout_positions = {
        ('A', 2): OrderedDict([
            ('JKL', 1),
            ('GHI', 2),
            ('ABC', 3),
            ('DEF', 3),
        ])
    }
    scheduler = get_scheduler(knockout_positions=knockout_positions)

    game = Match(2, 'Match 2', 'A', [], None, None, None, False)
    winners = scheduler.get_winners(game)

    assert set(winners) == set(['GHI', 'JKL'])
Esempio n. 10
0
    def add_tiebreaker(self, scores, time):
        """
        Add a tie breaker to the league if required. Also set a ``tiebreaker``
        attribute if necessary.

        :param scores: The scores.
        :param time: The time.
        """

        finals_info = self.knockout_rounds[-1][0]
        finals_key = (finals_info.arena, finals_info.num)
        try:
            finals_positions = scores.knockout.game_positions[finals_key]
        except KeyError:
            return
        winners = finals_positions.get(1)
        if not winners:
            raise AssertionError('The only winning move is not to play.')
        if len(winners) > 1:  # Act surprised!
            # Start with the winning teams in the same order as in the finals
            tiebreaker_teams = [
                team if team in winners else None for team in finals_info.teams
            ]
            # Use a static permutation
            permutation = [3, 2, 0, 1]
            tiebreaker_teams = [
                tiebreaker_teams[permutation[n]] for n in permutation
            ]
            # Inject new match
            end_time = time + self.match_duration
            num = self.n_matches()
            arena = finals_info.arena
            match = Match(num=num,
                          display_name="Tiebreaker (#{0})".format(num),
                          arena=arena,
                          teams=tiebreaker_teams,
                          type=MatchType.tiebreaker,
                          start_time=time,
                          end_time=end_time,
                          use_resolved_ranking=False)
            slot = {arena: match}
            self.matches.append(slot)
            match_period = MatchPeriod(time, end_time, end_time, 'Tiebreaker',
                                       [slot], MatchType.tiebreaker)
            self.match_periods.append(match_period)

            self.tiebreaker = match
Esempio n. 11
0
def build_match(
    num: int = 0,
    arena: str = 'main',
    teams: Sequence[Optional[TLA]] = (),
    start_time: datetime.datetime = _DEFAULT_START_TIME,
    end_time: datetime.datetime = _DEFAULT_END_TIME,
    type_: MatchType = MatchType.league,
    use_resolved_ranking: bool = False,
) -> Match:
    return Match(
        MatchNumber(num),
        "Match {n}".format(n=num),
        ArenaName(arena),
        list(teams),
        start_time,
        end_time,
        type_,
        use_resolved_ranking,
    )
Esempio n. 12
0
def test_get_staging_times():
    start = datetime(2014, 3, 26, 13, 0, 0)
    match = Match(0, None, 'A', [], start, None, None, None)

    matches = load_basic_data()

    staging_times = matches.get_staging_times(match)

    expected = {
        'opens': datetime(2014, 3, 26, 12, 56, 30),
        'closes': datetime(2014, 3, 26, 12, 59, 30),
        'duration': timedelta(seconds=180),
        'signal_shepherds': {
            'Blue': datetime(2014, 3, 26, 12, 57, 29),
            'Green': datetime(2014, 3, 26, 12, 58, 29),
        },
        'signal_teams': datetime(2014, 3, 26, 12, 57, 30),
    }

    assert expected == staging_times, "Wrong staging times for given match"
Esempio n. 13
0
def test_tiebreaker():
    schedule = make_schedule()
    scores = make_finals_score({'AAA': 1, 'BBB': 1, 'CCC': 1, 'DDD': 0})

    schedule.add_tiebreaker(scores, datetime.datetime(2014, 4, 25, 13, 0))

    assert schedule.tiebreaker

    start_time = datetime.datetime(2014, 4, 25, 13, 0)
    end_time = datetime.datetime(2014, 4, 25, 13, 5)

    tiebreaker_match = {
        'A':
        Match(num=1,
              display_name='Tiebreaker (#1)',
              arena='A',
              teams=['BBB', 'AAA', None, 'CCC'],
              start_time=start_time,
              end_time=end_time,
              type=MatchType.tiebreaker,
              use_resolved_ranking=False)
    }

    eq_(schedule.matches[-1], tiebreaker_match)

    last_period = schedule.match_periods[-1]
    last_period_matches = last_period.matches

    assert last_period_matches == [tiebreaker_match
                                   ], "Wrong matches in last period"

    last_period_matches.pop()  # simplify the next comparison

    expected_period = MatchPeriod(start_time, end_time, end_time, 'Tiebreaker',
                                  [], MatchType.tiebreaker)

    assert last_period == expected_period, "Wrong last period"
Esempio n. 14
0
def test_two_teams_before():
    league_matches = [{
        'A':
        Match(0,
              'Match 0',
              'A', [],
              datetime(2014, 4, 27, 12, 30),
              datetime(2014, 4, 27, 12, 35),
              MatchType.league,
              use_resolved_ranking=False)
    }]

    expected = [
        {
            'A':
            Match(1,
                  'Quarter 1 (#1)',
                  'A', [UNKNOWABLE_TEAM] * 2,
                  datetime(2014, 4, 27, 14, 30),
                  datetime(2014, 4, 27, 14, 35),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(2,
                  'Quarter 2 (#2)',
                  'A', [UNKNOWABLE_TEAM] * 2,
                  datetime(2014, 4, 27, 14, 35),
                  datetime(2014, 4, 27, 14, 40),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(3,
                  'Semi 1 (#3)',
                  'A', [UNKNOWABLE_TEAM] * 2,
                  datetime(2014, 4, 27, 14, 45),
                  datetime(2014, 4, 27, 14, 50),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(4,
                  'Semi 2 (#4)',
                  'A', [UNKNOWABLE_TEAM] * 2,
                  datetime(2014, 4, 27, 14, 50),
                  datetime(2014, 4, 27, 14, 55),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(5,
                  'Final (#5)',
                  'A', [UNKNOWABLE_TEAM] * 2,
                  datetime(2014, 4, 27, 15, 0),
                  datetime(2014, 4, 27, 15, 5),
                  MatchType.knockout,
                  use_resolved_ranking=False)
        },
    ]

    assertMatches(
        expected,
        matches_config=get_two_team_config(),
        matches=league_matches,
    )
def test_before():
    league_matches = [{
        'A':
        Match(0,
              'Match 0',
              'A', [],
              datetime(2014, 4, 27, 12, 30),
              datetime(2014, 4, 27, 12, 35),
              MatchType.league,
              use_resolved_ranking=False)
    }]

    scheduler = get_scheduler(matches=league_matches)
    scheduler.add_knockouts()

    period = scheduler.period

    expected = [
        {
            'A':
            Match(1,
                  'Quarter 1 (#1)',
                  'A', [UNKNOWABLE_TEAM] * 4,
                  datetime(2014, 4, 27, 14, 30),
                  datetime(2014, 4, 27, 14, 35),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(2,
                  'Quarter 2 (#2)',
                  'A', [UNKNOWABLE_TEAM] * 4,
                  datetime(2014, 4, 27, 14, 35),
                  datetime(2014, 4, 27, 14, 40),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(3,
                  'Semi 1 (#3)',
                  'A', [UNKNOWABLE_TEAM] * 4,
                  datetime(2014, 4, 27, 14, 45),
                  datetime(2014, 4, 27, 14, 50),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(4,
                  'Semi 2 (#4)',
                  'A', [UNKNOWABLE_TEAM] * 4,
                  datetime(2014, 4, 27, 14, 50),
                  datetime(2014, 4, 27, 14, 55),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(5,
                  'Final (#5)',
                  'A', [UNKNOWABLE_TEAM] * 4,
                  datetime(2014, 4, 27, 15, 0),
                  datetime(2014, 4, 27, 15, 5),
                  MatchType.knockout,
                  use_resolved_ranking=False)
        },
    ]

    for i in range(len(expected)):
        e = expected[i]
        a = period.matches[i]

        assert e == a, "Match {0} in the knockouts".format(i)
Esempio n. 16
0
def test_knockout_match_winners_empty():
    scheduler = get_scheduler()
    game = Match(2, 'Match 2', 'A', [], None, None, None, False)
    winners = scheduler.get_winners(game)
    assert winners == [UNKNOWABLE_TEAM] * 2
def helper(places, knockout_positions=None):
    scheduler = get_scheduler(knockout_positions=knockout_positions)
    scheduler.add_knockouts()

    period = scheduler.period

    expected = [
        {
            'A':
            Match(0,
                  'Quarter 1 (#0)',
                  'A',
                  places[0],
                  datetime(2014, 4, 27, 14, 30),
                  datetime(2014, 4, 27, 14, 35),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(1,
                  'Quarter 2 (#1)',
                  'A',
                  places[1],
                  datetime(2014, 4, 27, 14, 35),
                  datetime(2014, 4, 27, 14, 40),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(2,
                  'Semi 1 (#2)',
                  'A',
                  places[2],
                  datetime(2014, 4, 27, 14, 45),
                  datetime(2014, 4, 27, 14, 50),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(3,
                  'Semi 2 (#3)',
                  'A',
                  places[3],
                  datetime(2014, 4, 27, 14, 50),
                  datetime(2014, 4, 27, 14, 55),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(4,
                  'Final (#4)',
                  'A',
                  places[4],
                  datetime(2014, 4, 27, 15, 0),
                  datetime(2014, 4, 27, 15, 5),
                  MatchType.knockout,
                  use_resolved_ranking=False)
        },
    ]

    for i in range(len(expected)):
        e = expected[i]
        a = period.matches[i]

        assert e == a, "Match {0} in the knockouts".format(i)
Esempio n. 18
0
def test_four_teams_before():
    # Add an unscored league match so that we don't appear to have played them all
    league_matches = [{
        'A':
        Match(0,
              'Match 0',
              'A', [],
              datetime(2014, 4, 27, 12, 30),
              datetime(2014, 4, 27, 12, 35),
              MatchType.league,
              use_resolved_ranking=False)
    }]

    expected = [
        {
            'A':
            Match(1,
                  'Quarter 1 (#1)',
                  'A', [UNKNOWABLE_TEAM] * 4,
                  datetime(2014, 4, 27, 14, 30),
                  datetime(2014, 4, 27, 14, 35),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(2,
                  'Quarter 2 (#2)',
                  'A', [UNKNOWABLE_TEAM] * 4,
                  datetime(2014, 4, 27, 14, 35),
                  datetime(2014, 4, 27, 14, 40),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(3,
                  'Semi 1 (#3)',
                  'A', [UNKNOWABLE_TEAM] * 4,
                  datetime(2014, 4, 27, 14, 45),
                  datetime(2014, 4, 27, 14, 50),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(4,
                  'Semi 2 (#4)',
                  'A', [UNKNOWABLE_TEAM] * 4,
                  datetime(2014, 4, 27, 14, 50),
                  datetime(2014, 4, 27, 14, 55),
                  MatchType.knockout,
                  use_resolved_ranking=True)
        },
        {
            'A':
            Match(5,
                  'Final (#5)',
                  'A', [UNKNOWABLE_TEAM] * 4,
                  datetime(2014, 4, 27, 15, 0),
                  datetime(2014, 4, 27, 15, 5),
                  MatchType.knockout,
                  use_resolved_ranking=False)
        },
    ]

    assertMatches(
        expected,
        matches_config=get_four_team_config(),
        matches=league_matches,
    )
Esempio n. 19
0
from dateutil.tz import tzutc
from collections import OrderedDict

from sr.comp.winners import Award, compute_awards
from sr.comp.match_period import Match, MatchType
from sr.comp.teams import Team
from sr.comp.scores import TeamScore
from sr.comp.ranker import calc_positions, calc_ranked_points

from nose.tools import eq_
import mock

FINAL_INFO = Match(num=1,
                   display_name='Match 1',
                   arena='A',
                   teams=['AAA', 'BBB', 'CCC', 'DDD'],
                   start_time=datetime(2014, 4, 26, 16, 30, tzinfo=tzutc()),
                   end_time=datetime(2014, 4, 26, 16, 35, tzinfo=tzutc()),
                   type=MatchType.knockout,
                   use_resolved_ranking=False)

TIEBREAKER_INFO = Match(num=2,
                        display_name='Tiebreaker (#2)',
                        arena='A',
                        teams=['AAA', 'BBB'],
                        start_time=datetime(2014,
                                            4,
                                            26,
                                            16,
                                            30,
                                            tzinfo=tzutc()),
                        end_time=datetime(2014, 4, 26, 16, 35, tzinfo=tzutc()),