예제 #1
0
    def calc_elim_match_points_2015(cls, district_points, matches,
                                    POINTS_MULTIPLIER):
        from helpers.match_helper import MatchHelper  # circular import issue

        # count number of matches played per team per comp level
        num_played = defaultdict(lambda: defaultdict(int))
        for level in ['qf', 'sf']:
            for match in matches[level]:
                if not match.has_been_played:
                    continue
                for color in ['red', 'blue']:
                    for team in match.alliances[color]['teams']:
                        num_played[level][team] += 1

        # qf and sf points
        advancement = MatchHelper.generatePlayoffAdvancement2015(matches)
        for last_level, level in [('qf', 'sf'), ('sf', 'f')]:
            for (teams, _, _) in advancement[last_level]:
                teams = ['frc{}'.format(t) for t in teams]
                done = False
                for match in matches[level]:
                    for color in ['red', 'blue']:
                        if set(teams).intersection(
                                set(match.alliances[color]['teams'])) != set():
                            for team in teams:
                                points = DistrictPointValues.QF_WIN.get(
                                    match.year,
                                    DistrictPointValues.QF_WIN_DEFAULT
                                ) if last_level == 'qf' else DistrictPointValues.SF_WIN.get(
                                    match.year,
                                    DistrictPointValues.SF_WIN_DEFAULT)
                                district_points['points'][team][
                                    'elim_points'] += int(
                                        math.ceil(points *
                                                  num_played[last_level][team])
                                    ) * POINTS_MULTIPLIER
                            done = True
                            break
                        if done:
                            break
                    if done:
                        break

        # final points
        num_wins = {'red': 0, 'blue': 0}
        team_matches_played = {'red': [], 'blue': []}
        for match in matches['f']:
            if not match.has_been_played or match.winning_alliance == '':
                continue

            num_wins[match.winning_alliance] += 1
            for team in match.alliances[match.winning_alliance]['teams']:
                team_matches_played[match.winning_alliance].append(team)

            if num_wins[match.winning_alliance] >= 2:
                points = DistrictPointValues.F_WIN.get(
                    match.year, DistrictPointValues.F_WIN_DEFAULT)
                for team in team_matches_played[match.winning_alliance]:
                    district_points['points'][team][
                        'elim_points'] += points * POINTS_MULTIPLIER
    def calc_elim_match_points_2015(cls, district_points, matches, POINTS_MULTIPLIER):
        from helpers.match_helper import MatchHelper  # circular import issue

        # count number of matches played per team per comp level
        num_played = defaultdict(lambda: defaultdict(int))
        for level in ["qf", "sf"]:
            for match in matches[level]:
                if not match.has_been_played:
                    continue
                for color in ["red", "blue"]:
                    for team in match.alliances[color]["teams"]:
                        num_played[level][team] += 1

        # qf and sf points
        advancement = MatchHelper.generatePlayoffAdvancement2015(matches)
        for last_level, level in [("qf", "sf"), ("sf", "f")]:
            for (teams, _, _) in advancement[last_level]:
                teams = ["frc{}".format(t) for t in teams]
                done = False
                for match in matches[level]:
                    for color in ["red", "blue"]:
                        if set(teams).intersection(set(match.alliances[color]["teams"])) != set():
                            for team in teams:
                                points = (
                                    DistrictPointValues.QF_WIN.get(match.year, DistrictPointValues.QF_WIN_DEFAULT)
                                    if last_level == "qf"
                                    else DistrictPointValues.SF_WIN.get(match.year, DistrictPointValues.SF_WIN_DEFAULT)
                                )
                                district_points["points"][team]["elim_points"] += (
                                    int(np.ceil(points * num_played[last_level][team])) * POINTS_MULTIPLIER
                                )
                            done = True
                            break
                        if done:
                            break
                    if done:
                        break

        # final points
        num_wins = {"red": 0, "blue": 0}
        team_matches_played = {"red": [], "blue": []}
        for match in matches["f"]:
            if not match.has_been_played or match.winning_alliance == "":
                continue

            num_wins[match.winning_alliance] += 1
            for team in match.alliances[match.winning_alliance]["teams"]:
                team_matches_played[match.winning_alliance].append(team)

            if num_wins[match.winning_alliance] >= 2:
                points = DistrictPointValues.F_WIN.get(match.year, DistrictPointValues.F_WIN_DEFAULT)
                for team in team_matches_played[match.winning_alliance]:
                    district_points["points"][team]["elim_points"] += points * POINTS_MULTIPLIER
예제 #3
0
    def calc_elim_match_points_2015(cls, district_points, matches, POINTS_MULTIPLIER):
        from helpers.match_helper import MatchHelper  # circular import issue

        # count number of matches played per team per comp level
        num_played = defaultdict(lambda: defaultdict(int))
        for level in ['qf', 'sf']:
            for match in matches[level]:
                if not match.has_been_played:
                    continue
                for color in ['red', 'blue']:
                    for team in match.alliances[color]['teams']:
                        num_played[level][team] += 1

        # qf and sf points
        advancement = MatchHelper.generatePlayoffAdvancement2015(matches)
        for last_level, level in [('qf', 'sf'), ('sf', 'f')]:
            for (teams, _, _) in advancement[last_level]:
                teams = ['frc{}'.format(t) for t in teams]
                done = False
                for match in matches[level]:
                    for color in ['red', 'blue']:
                        if set(teams).intersection(set(match.alliances[color]['teams'])) != set():
                            for team in teams:
                                points = DistrictPointValues.QF_WIN.get(match.year, DistrictPointValues.QF_WIN_DEFAULT) if last_level == 'qf' else DistrictPointValues.SF_WIN.get(match.year, DistrictPointValues.SF_WIN_DEFAULT)
                                district_points['points'][team]['elim_points'] += int(
                                    math.ceil(points * num_played[last_level][team])) * POINTS_MULTIPLIER
                            done = True
                            break
                        if done:
                            break
                    if done:
                        break

        # final points
        num_wins = {'red': 0, 'blue': 0}
        team_matches_played = {'red': [], 'blue': []}
        for match in matches['f']:
            if not match.has_been_played or match.winning_alliance == '':
                continue

            num_wins[match.winning_alliance] += 1
            for team in match.alliances[match.winning_alliance]['teams']:
                team_matches_played[match.winning_alliance].append(team)

            if num_wins[match.winning_alliance] >= 2:
                points = DistrictPointValues.F_WIN.get(match.year, DistrictPointValues.F_WIN_DEFAULT)
                for team in team_matches_played[match.winning_alliance]:
                    district_points['points'][team]['elim_points'] += points * POINTS_MULTIPLIER
    def _render(self, event_key):
        event = EventQuery(event_key).fetch()

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()
        event.prep_details()
        medias_future = media_query.EventTeamsPreferredMediasQuery(event_key).fetch_async()
        district_future = DistrictQuery(event.district_key.id()).fetch_async() if event.district_key else None
        event_medias_future = media_query.EventMediasQuery(event_key).fetch_async()
        status_sitevar_future = Sitevar.get_by_id_async('apistatus.down_events')

        event_divisions_future = None
        event_codivisions_future = None
        parent_event_future = None
        if event.divisions:
            event_divisions_future = ndb.get_multi_async(event.divisions)
        elif event.parent_event:
            parent_event_future = event.parent_event.get_async()
            event_codivisions_future = EventDivisionsQuery(event.parent_event.id()).fetch_async()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches, event)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        # Organize medias by team
        image_medias = MediaHelper.get_images([media for media in medias_future.get_result()])
        team_medias = defaultdict(list)
        for image_media in image_medias:
            for reference in image_media.references:
                team_medias[reference].append(image_media)
        team_and_medias = []
        for team in teams:
            team_and_medias.append((team, team_medias.get(team.key, [])))

        num_teams = len(team_and_medias)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = team_and_medias[:middle_value], team_and_medias[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event, event.alliance_selections)

        playoff_advancement = None
        playoff_template = None
        double_elim_matches = None
        if EventHelper.is_2015_playoff(event_key):
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(matches, event.alliance_selections)
            playoff_template = 'playoff_table'
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.ROUND_ROBIN_6_TEAM:
            playoff_advancement = MatchHelper.generatePlayoffAdvancementRoundRobin(matches, event.year, event.alliance_selections)
            playoff_template = 'playoff_round_robin_6_team'
            comp_levels = bracket_table.keys()
            for comp_level in comp_levels:
                if comp_level != 'f':
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.BO3_FINALS or event.playoff_type == PlayoffType.BO5_FINALS:
            comp_levels = bracket_table.keys()
            for comp_level in comp_levels:
                if comp_level != 'f':
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.DOUBLE_ELIM_8_TEAM:
            double_elim_matches = MatchHelper.organizeDoubleElimMatches(matches)

        district_points_sorted = None
        if event.district_key and event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        event_insights = event.details.insights if event.details else None
        event_insights_template = None
        if event_insights:
            event_insights_template = 'event_partials/event_insights_{}.html'.format(event.year)

        district = district_future.get_result() if district_future else None
        event_divisions = None
        if event_divisions_future:
            event_divisions = [e.get_result() for e in event_divisions_future]
        elif event_codivisions_future:
            event_divisions = event_codivisions_future.get_result()

        medias_by_slugname = MediaHelper.group_by_slugname([media for media in event_medias_future.get_result()])
        has_time_predictions = matches_upcoming and any(match.predicted_time for match in matches_upcoming)

        status_sitevar = status_sitevar_future.get_result()

        self.template_values.update({
            "event": event,
            "event_down": status_sitevar and event_key in status_sitevar.contents,
            "district_name": district.display_name if district else None,
            "district_abbrev": district.abbreviation if district else None,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            'has_time_predictions': has_time_predictions,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "playoff_template": playoff_template,
            "district_points_sorted": district_points_sorted,
            "event_insights_qual": event_insights['qual'] if event_insights else None,
            "event_insights_playoff": event_insights['playoff'] if event_insights else None,
            "event_insights_template": event_insights_template,
            "medias_by_slugname": medias_by_slugname,
            "event_divisions": event_divisions,
            'parent_event': parent_event_future.get_result() if parent_event_future else None,
            'double_elim_matches': double_elim_matches,
            'double_elim_playoff_types': PlayoffType.DOUBLE_ELIM_TYPES,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)
    def parse(self, response):
        matches = response['Schedule']

        event_key = '{}{}'.format(self.year, self.event_short)
        event = Event.get_by_id(event_key)
        if event.timezone_id:
            event_tz = pytz.timezone(event.timezone_id)
        else:
            logging.warning("Event {} has no timezone! Match times may be wrong.".format(event_key))
            event_tz = None

        parsed_matches = []
        is_octofinals = len(matches) > 0 and 'Octofinal' in matches[0]['description']
        for match in matches:
            if 'tournamentLevel' in match:  # 2016+
                level = match['tournamentLevel']
            else:  # 2015
                level = match['level']
            comp_level = get_comp_level(self.year, level, match['matchNumber'], is_octofinals)
            set_number, match_number = get_set_match_number(self.year, comp_level, match['matchNumber'], is_octofinals)

            red_teams = []
            blue_teams = []
            team_key_names = []
            null_team = False
            for team in match['Teams']:
                if team['teamNumber'] is None:
                    null_team = True
                team_key = 'frc{}'.format(team['teamNumber'])
                team_key_names.append(team_key)
                if 'Red' in team['station']:
                    red_teams.append(team_key)
                elif 'Blue' in team['station']:
                    blue_teams.append(team_key)
            if null_team and match['scoreRedFinal'] is None and match['scoreBlueFinal'] is None:
                continue

            alliances = {
                'red': {
                    'teams': red_teams,
                    'score': match['scoreRedFinal']
                },
                'blue': {
                    'teams': blue_teams,
                    'score': match['scoreBlueFinal']
                }
            }

            if not match['startTime']:  # no startTime means it's an unneeded rubber match
                continue

            time = datetime.datetime.strptime(match['startTime'].split('.')[0], TIME_PATTERN)
            actual_time_raw = match['actualStartTime'] if 'actualStartTime' in match else None
            actual_time = None
            if event_tz is not None:
                time = time - event_tz.utcoffset(time)

            if actual_time_raw is not None:
                actual_time = datetime.datetime.strptime(actual_time_raw.split('.')[0], TIME_PATTERN)
                if event_tz is not None:
                    actual_time = actual_time - event_tz.utcoffset(actual_time)

            parsed_matches.append(Match(
                id=Match.renderKeyName(
                    event_key,
                    comp_level,
                    set_number,
                    match_number),
                event=event.key,
                year=event.year,
                set_number=set_number,
                match_number=match_number,
                comp_level=comp_level,
                team_key_names=team_key_names,
                time=time,
                actual_time=actual_time,
                alliances_json=json.dumps(alliances),
            ))

        if self.year == 2015:
            # Fix null teams in elims (due to FMS API failure, some info not complete)
            # Should only happen for sf and f matches
            organized_matches = MatchHelper.organizeMatches(parsed_matches)
            for level in ['sf', 'f']:
                playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(organized_matches)
                if playoff_advancement[LAST_LEVEL[level]] != []:
                    for match in organized_matches[level]:
                        if 'frcNone' in match.team_key_names:
                            if level == 'sf':
                                red_seed, blue_seed = QF_SF_MAP[match.match_number]
                            else:
                                red_seed = 0
                                blue_seed = 1
                            red_teams = ['frc{}'.format(t) for t in playoff_advancement[LAST_LEVEL[level]][red_seed][0]]
                            blue_teams = ['frc{}'.format(t) for t in playoff_advancement[LAST_LEVEL[level]][blue_seed][0]]

                            alliances = match.alliances
                            alliances['red']['teams'] = red_teams
                            alliances['blue']['teams'] = blue_teams
                            match.alliances_json = json.dumps(alliances)
                            match.team_key_names = red_teams + blue_teams

            fixed_matches = []
            for key, matches in organized_matches.items():
                if key != 'num':
                    for match in matches:
                        if 'frcNone' not in match.team_key_names:
                            fixed_matches.append(match)
            parsed_matches = fixed_matches

        return parsed_matches
    def parse(self, response):
        matches = response['Schedule']

        event_key = '{}{}'.format(self.year, self.event_short)
        event = Event.get_by_id(event_key)
        if event.timezone_id:
            event_tz = pytz.timezone(event.timezone_id)
        else:
            logging.warning(
                "Event {} has no timezone! Match times may be wrong.".format(
                    event_key))
            event_tz = None

        parsed_matches = []
        remapped_matches = {}  # If a key changes due to a tiebreaker
        for match in matches:
            if 'tournamentLevel' in match:  # 2016+
                level = match['tournamentLevel']
            else:  # 2015
                level = match['level']
            comp_level = PlayoffType.get_comp_level(event.playoff_type, level,
                                                    match['matchNumber'])
            set_number, match_number = PlayoffType.get_set_match_number(
                event.playoff_type, comp_level, match['matchNumber'])

            red_teams = []
            blue_teams = []
            red_surrogates = []
            blue_surrogates = []
            team_key_names = []
            null_team = False
            sorted_teams = sorted(
                match['Teams'], key=lambda team: team['station']
            )  # Sort by station to ensure correct ordering. Kind of hacky.
            for team in sorted_teams:
                if team['teamNumber'] is None:
                    null_team = True
                team_key = 'frc{}'.format(team['teamNumber'])
                team_key_names.append(team_key)
                if 'Red' in team['station']:
                    red_teams.append(team_key)
                    if team['surrogate']:
                        red_surrogates.append(team_key)
                elif 'Blue' in team['station']:
                    blue_teams.append(team_key)
                    if team['surrogate']:
                        blue_surrogates.append(team_key)

            if null_team and match['scoreRedFinal'] is None and match[
                    'scoreBlueFinal'] is None:
                continue

            alliances = {
                'red': {
                    'teams': red_teams,
                    'surrogates': red_surrogates,
                    'score': match['scoreRedFinal']
                },
                'blue': {
                    'teams': blue_teams,
                    'surrogates': blue_surrogates,
                    'score': match['scoreBlueFinal']
                },
            }

            if not match[
                    'startTime']:  # no startTime means it's an unneeded rubber match
                continue

            time = datetime.datetime.strptime(match['startTime'].split('.')[0],
                                              TIME_PATTERN)
            if event_tz is not None:
                time = time - event_tz.utcoffset(time)

            actual_time_raw = match[
                'actualStartTime'] if 'actualStartTime' in match else None
            actual_time = None
            if actual_time_raw is not None:
                actual_time = datetime.datetime.strptime(
                    actual_time_raw.split('.')[0], TIME_PATTERN)
                if event_tz is not None:
                    actual_time = actual_time - event_tz.utcoffset(actual_time)

            post_result_time_raw = match.get('postResultTime')
            post_result_time = None
            if post_result_time_raw is not None:
                post_result_time = datetime.datetime.strptime(
                    post_result_time_raw.split('.')[0], TIME_PATTERN)
                if event_tz is not None:
                    post_result_time = post_result_time - event_tz.utcoffset(
                        post_result_time)

            key_name = Match.renderKeyName(event_key, comp_level, set_number,
                                           match_number)

            # Check for tiebreaker matches
            existing_match = Match.get_by_id(key_name)
            # Follow chain of existing matches
            while existing_match is not None and existing_match.tiebreak_match_key is not None:
                logging.info("Following Match {} to {}".format(
                    existing_match.key.id(),
                    existing_match.tiebreak_match_key.id()))
                existing_match = existing_match.tiebreak_match_key.get()
            # Check if last existing match needs to be tiebroken
            if existing_match and existing_match.comp_level != 'qm' and \
                    existing_match.has_been_played and \
                    existing_match.winning_alliance == '' and \
                    existing_match.actual_time != actual_time and \
                    not self.is_blank_match(existing_match):
                logging.warning("Match {} is tied!".format(
                    existing_match.key.id()))

                # TODO: Only query within set if set_number ever gets indexed
                match_count = 0
                for match_key in Match.query(
                        Match.event == event.key,
                        Match.comp_level == comp_level).fetch(keys_only=True):
                    _, match_key = match_key.id().split('_')
                    if match_key.startswith('{}{}'.format(
                            comp_level, set_number)):
                        match_count += 1

                # Sanity check: Tiebreakers must be played after at least 3 matches, or 6 for finals
                if match_count < 3 or (match_count < 6 and comp_level == 'f'):
                    logging.warning(
                        "Match supposedly tied, but existing count is {}! Skipping match."
                        .format(match_count))
                    continue

                match_number = match_count + 1
                new_key_name = Match.renderKeyName(event_key, comp_level,
                                                   set_number, match_number)
                remapped_matches[key_name] = new_key_name
                key_name = new_key_name

                # Point existing match to new tiebreaker match
                existing_match.tiebreak_match_key = ndb.Key(Match, key_name)
                parsed_matches.append(existing_match)

                logging.warning("Creating new match: {}".format(key_name))
            elif existing_match:
                remapped_matches[key_name] = existing_match.key.id()
                key_name = existing_match.key.id()
                match_number = existing_match.match_number

            parsed_matches.append(
                Match(
                    id=key_name,
                    event=event.key,
                    year=event.year,
                    set_number=set_number,
                    match_number=match_number,
                    comp_level=comp_level,
                    team_key_names=team_key_names,
                    time=time,
                    actual_time=actual_time,
                    post_result_time=post_result_time,
                    alliances_json=json.dumps(alliances),
                ))

        if self.year == 2015:
            # Fix null teams in elims (due to FMS API failure, some info not complete)
            # Should only happen for sf and f matches
            organized_matches = MatchHelper.organizeMatches(parsed_matches)
            for level in ['sf', 'f']:
                playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(
                    organized_matches)
                if playoff_advancement[LAST_LEVEL[level]] != []:
                    for match in organized_matches[level]:
                        if 'frcNone' in match.team_key_names:
                            if level == 'sf':
                                red_seed, blue_seed = QF_SF_MAP[
                                    match.match_number]
                            else:
                                red_seed = 0
                                blue_seed = 1
                            red_teams = [
                                'frc{}'.format(t) for t in playoff_advancement[
                                    LAST_LEVEL[level]][red_seed][0]
                            ]
                            blue_teams = [
                                'frc{}'.format(t) for t in playoff_advancement[
                                    LAST_LEVEL[level]][blue_seed][0]
                            ]

                            alliances = match.alliances
                            alliances['red']['teams'] = red_teams
                            alliances['blue']['teams'] = blue_teams
                            match.alliances_json = json.dumps(alliances)
                            match.team_key_names = red_teams + blue_teams

            fixed_matches = []
            for key, matches in organized_matches.items():
                if key != 'num':
                    for match in matches:
                        if 'frcNone' not in match.team_key_names:
                            fixed_matches.append(match)
            parsed_matches = fixed_matches

        return parsed_matches, remapped_matches
예제 #7
0
    def parse(self, response):
        """
        This currently only works for the 2015 game, where elims matches are all part of one set.
        """
        matches = response['Schedule']

        event_key = '{}{}'.format(self.year, self.event_short)
        event = Event.get_by_id(event_key)
        if event.timezone_id:
            event_tz = pytz.timezone(event.timezone_id)
        else:
            logging.warning(
                "Event {} has no timezone! Match times may be wrong.").format(
                    event_key)
            event_tz = None

        set_number = 1
        parsed_matches = []
        for match in matches:
            comp_level = self._get_comp_level(match['level'],
                                              match['matchNumber'])
            match_number = self._get_match_number(comp_level,
                                                  match['matchNumber'])

            red_teams = []
            blue_teams = []
            team_key_names = []
            null_team = False
            for team in match['Teams']:
                if team['teamNumber'] is None:
                    null_team = True
                team_key = 'frc{}'.format(team['teamNumber'])
                team_key_names.append(team_key)
                if 'Red' in team['station']:
                    red_teams.append(team_key)
                elif 'Blue' in team['station']:
                    blue_teams.append(team_key)
            if null_team and match['scoreRedFinal'] is None and match[
                    'scoreBlueFinal'] is None:
                continue

            alliances = {
                'red': {
                    'teams': red_teams,
                    'score': match['scoreRedFinal']
                },
                'blue': {
                    'teams': blue_teams,
                    'score': match['scoreBlueFinal']
                }
            }

            score_breakdown = {
                'red': {
                    'auto': match['scoreRedAuto'],
                    'foul': match['scoreRedFoul']
                },
                'blue': {
                    'auto': match['scoreBlueAuto'],
                    'foul': match['scoreBlueFoul']
                }
            }

            time = datetime.datetime.strptime(match['startTime'],
                                              "%Y-%m-%dT%H:%M:%S")
            if event_tz is not None:
                time = time - event_tz.utcoffset(time)

            parsed_matches.append(
                Match(
                    id=Match.renderKeyName(event_key, comp_level, set_number,
                                           match_number),
                    event=event.key,
                    game=
                    "frc_unknown",  # TODO: deprecate in favor of a 'year' property
                    set_number=set_number,
                    match_number=match_number,
                    comp_level=comp_level,
                    team_key_names=team_key_names,
                    time=time,
                    alliances_json=json.dumps(alliances),
                    score_breakdown_json=json.dumps(score_breakdown)))

        # Fix null teams in elims (due to FMS API failure, some info not complete)
        # Should only happen for sf and f matches
        organized_matches = MatchHelper.organizeMatches(parsed_matches)
        for level in ['sf', 'f']:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(
                organized_matches)
            if playoff_advancement[LAST_LEVEL[level]] != []:
                for match in organized_matches[level]:
                    if 'frcNone' in match.team_key_names:
                        if level == 'sf':
                            red_seed, blue_seed = QF_SF_MAP[match.match_number]
                        else:
                            red_seed = 0
                            blue_seed = 1
                        red_teams = [
                            'frc{}'.format(t) for t in playoff_advancement[
                                LAST_LEVEL[level]][red_seed][0]
                        ]
                        blue_teams = [
                            'frc{}'.format(t) for t in playoff_advancement[
                                LAST_LEVEL[level]][blue_seed][0]
                        ]

                        alliances = match.alliances
                        alliances['red']['teams'] = red_teams
                        alliances['blue']['teams'] = blue_teams
                        match.alliances_json = json.dumps(alliances)
                        match.team_key_names = red_teams + blue_teams

        fixed_matches = []
        for key, matches in organized_matches.items():
            if key != 'num':
                for match in matches:
                    if 'frcNone' not in match.team_key_names:
                        fixed_matches.append(match)

        return fixed_matches
    def parse(self, response):
        matches = response["Schedule"]

        event_key = "{}{}".format(self.year, self.event_short)
        event = Event.get_by_id(event_key)
        if event.timezone_id:
            event_tz = pytz.timezone(event.timezone_id)
        else:
            logging.warning("Event {} has no timezone! Match times may be wrong.".format(event_key))
            event_tz = None

        parsed_matches = []
        is_octofinals = len(matches) > 0 and "Octofinal" in matches[0]["description"]
        for match in matches:
            if "tournamentLevel" in match:  # 2016+
                level = match["tournamentLevel"]
            else:  # 2015
                level = match["level"]
            comp_level = get_comp_level(self.year, level, match["matchNumber"], is_octofinals)
            set_number, match_number = get_set_match_number(self.year, comp_level, match["matchNumber"], is_octofinals)

            red_teams = []
            blue_teams = []
            team_key_names = []
            null_team = False
            sorted_teams = sorted(
                match["Teams"], key=lambda team: team["station"]
            )  # Sort by station to ensure correct ordering. Kind of hacky.
            for team in sorted_teams:
                if team["teamNumber"] is None:
                    null_team = True
                team_key = "frc{}".format(team["teamNumber"])
                team_key_names.append(team_key)
                if "Red" in team["station"]:
                    red_teams.append(team_key)
                elif "Blue" in team["station"]:
                    blue_teams.append(team_key)
            if null_team and match["scoreRedFinal"] is None and match["scoreBlueFinal"] is None:
                continue

            alliances = {
                "red": {"teams": red_teams, "score": match["scoreRedFinal"]},
                "blue": {"teams": blue_teams, "score": match["scoreBlueFinal"]},
            }

            if not match["startTime"]:  # no startTime means it's an unneeded rubber match
                continue

            time = datetime.datetime.strptime(match["startTime"].split(".")[0], TIME_PATTERN)
            actual_time_raw = match["actualStartTime"] if "actualStartTime" in match else None
            actual_time = None
            if event_tz is not None:
                time = time - event_tz.utcoffset(time)

            if actual_time_raw is not None:
                actual_time = datetime.datetime.strptime(actual_time_raw.split(".")[0], TIME_PATTERN)
                if event_tz is not None:
                    actual_time = actual_time - event_tz.utcoffset(actual_time)

            parsed_matches.append(
                Match(
                    id=Match.renderKeyName(event_key, comp_level, set_number, match_number),
                    event=event.key,
                    year=event.year,
                    set_number=set_number,
                    match_number=match_number,
                    comp_level=comp_level,
                    team_key_names=team_key_names,
                    time=time,
                    actual_time=actual_time,
                    alliances_json=json.dumps(alliances),
                )
            )

        if self.year == 2015:
            # Fix null teams in elims (due to FMS API failure, some info not complete)
            # Should only happen for sf and f matches
            organized_matches = MatchHelper.organizeMatches(parsed_matches)
            for level in ["sf", "f"]:
                playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(organized_matches)
                if playoff_advancement[LAST_LEVEL[level]] != []:
                    for match in organized_matches[level]:
                        if "frcNone" in match.team_key_names:
                            if level == "sf":
                                red_seed, blue_seed = QF_SF_MAP[match.match_number]
                            else:
                                red_seed = 0
                                blue_seed = 1
                            red_teams = ["frc{}".format(t) for t in playoff_advancement[LAST_LEVEL[level]][red_seed][0]]
                            blue_teams = [
                                "frc{}".format(t) for t in playoff_advancement[LAST_LEVEL[level]][blue_seed][0]
                            ]

                            alliances = match.alliances
                            alliances["red"]["teams"] = red_teams
                            alliances["blue"]["teams"] = blue_teams
                            match.alliances_json = json.dumps(alliances)
                            match.team_key_names = red_teams + blue_teams

            fixed_matches = []
            for key, matches in organized_matches.items():
                if key != "num":
                    for match in matches:
                        if "frcNone" not in match.team_key_names:
                            fixed_matches.append(match)
            parsed_matches = fixed_matches

        return parsed_matches
    def parse(self, response):
        matches = response['Schedule']

        event_key = '{}{}'.format(self.year, self.event_short)
        event = Event.get_by_id(event_key)
        if event.timezone_id:
            event_tz = pytz.timezone(event.timezone_id)
        else:
            logging.warning("Event {} has no timezone! Match times may be wrong.".format(event_key))
            event_tz = None

        parsed_matches = []
        remapped_matches = {}  # If a key changes due to a tiebreaker
        is_octofinals = len(matches) > 0 and 'Octofinal' in matches[0]['description']
        for match in matches:
            if 'tournamentLevel' in match:  # 2016+
                level = match['tournamentLevel']
            else:  # 2015
                level = match['level']
            comp_level = get_comp_level(self.year, level, match['matchNumber'], is_octofinals)
            set_number, match_number = get_set_match_number(self.year, comp_level, match['matchNumber'], is_octofinals)

            red_teams = []
            blue_teams = []
            red_surrogates = []
            blue_surrogates = []
            team_key_names = []
            null_team = False
            sorted_teams = sorted(match['Teams'], key=lambda team: team['station'])  # Sort by station to ensure correct ordering. Kind of hacky.
            for team in sorted_teams:
                if team['teamNumber'] is None:
                    null_team = True
                team_key = 'frc{}'.format(team['teamNumber'])
                team_key_names.append(team_key)
                if 'Red' in team['station']:
                    red_teams.append(team_key)
                    if team['surrogate']:
                        red_surrogates.append(team_key)
                elif 'Blue' in team['station']:
                    blue_teams.append(team_key)
                    if team['surrogate']:
                        blue_surrogates.append(team_key)

            if null_team and match['scoreRedFinal'] is None and match['scoreBlueFinal'] is None:
                continue

            alliances = {
                'red': {
                    'teams': red_teams,
                    'surrogates': red_surrogates,
                    'score': match['scoreRedFinal']
                },
                'blue': {
                    'teams': blue_teams,
                    'surrogates': blue_surrogates,
                    'score': match['scoreBlueFinal']
                },
            }

            if not match['startTime']:  # no startTime means it's an unneeded rubber match
                continue

            time = datetime.datetime.strptime(match['startTime'].split('.')[0], TIME_PATTERN)
            if event_tz is not None:
                time = time - event_tz.utcoffset(time)

            actual_time_raw = match['actualStartTime'] if 'actualStartTime' in match else None
            actual_time = None
            if actual_time_raw is not None:
                actual_time = datetime.datetime.strptime(actual_time_raw.split('.')[0], TIME_PATTERN)
                if event_tz is not None:
                    actual_time = actual_time - event_tz.utcoffset(actual_time)

            post_result_time_raw = match.get('postResultTime')
            post_result_time = None
            if post_result_time_raw is not None:
                post_result_time = datetime.datetime.strptime(post_result_time_raw.split('.')[0], TIME_PATTERN)
                if event_tz is not None:
                    post_result_time = post_result_time - event_tz.utcoffset(post_result_time)

            key_name = Match.renderKeyName(
                event_key,
                comp_level,
                set_number,
                match_number)

            # Check for tiebreaker matches
            existing_match = Match.get_by_id(key_name)
            # Follow chain of existing matches
            while existing_match is not None and existing_match.tiebreak_match_key is not None:
                logging.info("Following Match {} to {}".format(existing_match.key.id(), existing_match.tiebreak_match_key.id()))
                existing_match = existing_match.tiebreak_match_key.get()
            # Check if last existing match needs to be tiebroken
            if existing_match and existing_match.comp_level != 'qm' and \
                    existing_match.has_been_played and \
                    existing_match.winning_alliance == '' and \
                    existing_match.actual_time != actual_time and \
                    not self.is_blank_match(existing_match):
                logging.warning("Match {} is tied!".format(existing_match.key.id()))

                # TODO: Only query within set if set_number ever gets indexed
                match_count = 0
                for match_key in Match.query(Match.event==event.key, Match.comp_level==comp_level).fetch(keys_only=True):
                    _, match_key = match_key.id().split('_')
                    if match_key.startswith('{}{}'.format(comp_level, set_number)):
                        match_count += 1

                # Sanity check: Tiebreakers must be played after at least 3 matches, or 6 for finals
                if match_count < 3 or (match_count < 6 and comp_level == 'f'):
                    logging.warning("Match supposedly tied, but existing count is {}! Skipping match.".format(match_count))
                    continue

                match_number = match_count + 1
                new_key_name = Match.renderKeyName(
                    event_key,
                    comp_level,
                    set_number,
                    match_number)
                remapped_matches[key_name] = new_key_name
                key_name = new_key_name

                # Point existing match to new tiebreaker match
                existing_match.tiebreak_match_key = ndb.Key(Match, key_name)
                parsed_matches.append(existing_match)

                logging.warning("Creating new match: {}".format(key_name))
            elif existing_match:
                remapped_matches[key_name] = existing_match.key.id()
                key_name = existing_match.key.id()
                match_number = existing_match.match_number

            parsed_matches.append(Match(
                id=key_name,
                event=event.key,
                year=event.year,
                set_number=set_number,
                match_number=match_number,
                comp_level=comp_level,
                team_key_names=team_key_names,
                time=time,
                actual_time=actual_time,
                post_result_time=post_result_time,
                alliances_json=json.dumps(alliances),
            ))

        if self.year == 2015:
            # Fix null teams in elims (due to FMS API failure, some info not complete)
            # Should only happen for sf and f matches
            organized_matches = MatchHelper.organizeMatches(parsed_matches)
            for level in ['sf', 'f']:
                playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(organized_matches)
                if playoff_advancement[LAST_LEVEL[level]] != []:
                    for match in organized_matches[level]:
                        if 'frcNone' in match.team_key_names:
                            if level == 'sf':
                                red_seed, blue_seed = QF_SF_MAP[match.match_number]
                            else:
                                red_seed = 0
                                blue_seed = 1
                            red_teams = ['frc{}'.format(t) for t in playoff_advancement[LAST_LEVEL[level]][red_seed][0]]
                            blue_teams = ['frc{}'.format(t) for t in playoff_advancement[LAST_LEVEL[level]][blue_seed][0]]

                            alliances = match.alliances
                            alliances['red']['teams'] = red_teams
                            alliances['blue']['teams'] = blue_teams
                            match.alliances_json = json.dumps(alliances)
                            match.team_key_names = red_teams + blue_teams

            fixed_matches = []
            for key, matches in organized_matches.items():
                if key != 'num':
                    for match in matches:
                        if 'frcNone' not in match.team_key_names:
                            fixed_matches.append(match)
            parsed_matches = fixed_matches

        return parsed_matches, remapped_matches
예제 #10
0
    def parse(self, response):
        matches = response['Schedule']

        event_key = '{}{}'.format(self.year, self.event_short)
        event = Event.get_by_id(event_key)
        if event.timezone_id:
            event_tz = pytz.timezone(event.timezone_id)
        else:
            logging.warning("Event {} has no timezone! Match times may be wrong.".format(event_key))
            event_tz = None

        parsed_matches = []
        for match in matches:
            if 'tournamentLevel' in match:  # 2016+
                level = match['tournamentLevel']
            else:  # 2015
                level = match['level']
            comp_level = get_comp_level(self.year, level, match['matchNumber'])
            set_number, match_number = get_set_match_number(self.year, comp_level, match['matchNumber'])

            red_teams = []
            blue_teams = []
            team_key_names = []
            null_team = False
            for team in match['Teams']:
                if team['teamNumber'] is None:
                    null_team = True
                team_key = 'frc{}'.format(team['teamNumber'])
                team_key_names.append(team_key)
                if 'Red' in team['station']:
                    red_teams.append(team_key)
                elif 'Blue' in team['station']:
                    blue_teams.append(team_key)
            if null_team and match['scoreRedFinal'] is None and match['scoreBlueFinal'] is None:
                continue

            alliances = {
                'red': {
                    'teams': red_teams,
                    'score': match['scoreRedFinal']
                },
                'blue': {
                    'teams': blue_teams,
                    'score': match['scoreBlueFinal']
                }
            }

            if not match['startTime']:  # no startTime means it's an unneeded rubber match
                continue

            time = datetime.datetime.strptime(match['startTime'].split('.')[0], TIME_PATTERN)
            actual_time_raw = match['actualStartTime'] if 'actualStartTime' in match else None
            actual_time = None
            if event_tz is not None:
                time = time - event_tz.utcoffset(time)

            if actual_time_raw is not None:
                actual_time = datetime.datetime.strptime(actual_time_raw.split('.')[0], TIME_PATTERN)
                if event_tz is not None:
                    actual_time = actual_time - event_tz.utcoffset(actual_time)

            parsed_matches.append(Match(
                id=Match.renderKeyName(
                    event_key,
                    comp_level,
                    set_number,
                    match_number),
                event=event.key,
                year=event.year,
                set_number=set_number,
                match_number=match_number,
                comp_level=comp_level,
                team_key_names=team_key_names,
                time=time,
                actual_time=actual_time,
                alliances_json=json.dumps(alliances),
            ))

        if self.year == 2015:
            # Fix null teams in elims (due to FMS API failure, some info not complete)
            # Should only happen for sf and f matches
            organized_matches = MatchHelper.organizeMatches(parsed_matches)
            for level in ['sf', 'f']:
                playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(organized_matches)
                if playoff_advancement[LAST_LEVEL[level]] != []:
                    for match in organized_matches[level]:
                        if 'frcNone' in match.team_key_names:
                            if level == 'sf':
                                red_seed, blue_seed = QF_SF_MAP[match.match_number]
                            else:
                                red_seed = 0
                                blue_seed = 1
                            red_teams = ['frc{}'.format(t) for t in playoff_advancement[LAST_LEVEL[level]][red_seed][0]]
                            blue_teams = ['frc{}'.format(t) for t in playoff_advancement[LAST_LEVEL[level]][blue_seed][0]]

                            alliances = match.alliances
                            alliances['red']['teams'] = red_teams
                            alliances['blue']['teams'] = blue_teams
                            match.alliances_json = json.dumps(alliances)
                            match.team_key_names = red_teams + blue_teams

            fixed_matches = []
            for key, matches in organized_matches.items():
                if key != 'num':
                    for match in matches:
                        if 'frcNone' not in match.team_key_names:
                            fixed_matches.append(match)
            parsed_matches = fixed_matches

        return parsed_matches
예제 #11
0
    def calc_rank_based_match_points(cls, event, district_points, match_futures, POINTS_MULTIPLIER):
        """
        Calculates match district points based on team ranking
        This algorithm was introduced for the 2015 season and also used for 2016
        See: http://www.firstinspires.org/node/7616 and also
        http://www.firstinspires.org/robotics/frc/blog/Admin-Manual-Section-7-and-the-FIRST-STRONGHOLD-Logo
        """
        from helpers.match_helper import MatchHelper  # circular import issue

        # qual match points are calculated by rank
        if event.rankings and len(event.rankings) > 1:
            rankings = event.rankings[1:]  # skip title row
            num_teams = len(rankings)
            alpha = 1.07
            for row in rankings:
                rank = int(row[0])
                team = 'frc{}'.format(row[1])
                qual_points = int(np.ceil(cls.inverf(float(num_teams - 2 * rank + 2) / (alpha * num_teams)) * (
                10.0 / cls.inverf(1.0 / alpha)) + 12))
                district_points['points'][team]['qual_points'] = qual_points * POINTS_MULTIPLIER
        else:
            logging.warning("Event {} has no rankings for qual_points calculations!".format(event.key.id()))

        matches = MatchHelper.organizeMatches([mf.get_result() for mf in match_futures])

        # qual match calculations. only used for tiebreaking
        for match in matches['qm']:
            for color in ['red', 'blue']:
                for team in match.alliances[color]['teams']:
                    score = match.alliances[color]['score']
                    district_points['tiebreakers'][team]['highest_qual_scores'] = heapq.nlargest(3, district_points[
                        'tiebreakers'][team]['highest_qual_scores'] + [score])

        # elim match point calculations
        # count number of matches played per team per comp level
        num_played = defaultdict(lambda: defaultdict(int))
        for level in ['qf', 'sf']:
            for match in matches[level]:
                if not match.has_been_played:
                    continue
                for color in ['red', 'blue']:
                    for team in match.alliances[color]['teams']:
                        num_played[level][team] += 1

        # qf and sf points
        advancement = MatchHelper.generatePlayoffAdvancement2015(matches)
        for last_level, level in [('qf', 'sf'), ('sf', 'f')]:
            for (teams, _, _) in advancement[last_level]:
                teams = ['frc{}'.format(t) for t in teams]
                done = False
                for match in matches[level]:
                    for color in ['red', 'blue']:
                        if set(teams).intersection(set(match.alliances[color]['teams'])) != set():
                            for team in teams:
                                points = DistrictPointValues.QF_WIN.get(event.year, DistrictPointValues.QF_WIN_DEFAULT) if last_level == 'qf' else DistrictPointValues.SF_WIN.get(event.year, DistrictPointValues.SF_WIN_DEFAULT)
                                district_points['points'][team]['elim_points'] += int(
                                    np.ceil(points * num_played[last_level][team])) * POINTS_MULTIPLIER
                            done = True
                            break
                        if done:
                            break
                    if done:
                        break

        # final points
        num_wins = {'red': 0, 'blue': 0}
        team_matches_played = {'red': [], 'blue': []}
        for match in matches['f']:
            if not match.has_been_played or match.winning_alliance == '':
                continue

            num_wins[match.winning_alliance] += 1
            for team in match.alliances[match.winning_alliance]['teams']:
                team_matches_played[match.winning_alliance].append(team)

            if num_wins[match.winning_alliance] >= 2:
                points = DistrictPointValues.F_WIN.get(event.year, DistrictPointValues.F_WIN_DEFAULT)
                for team in team_matches_played[match.winning_alliance]:
                    district_points['points'][team]['elim_points'] += points * POINTS_MULTIPLIER
    def parse(self, response):
        """
        This currently only works for the 2015 game, where elims matches are all part of one set.
        """
        matches = response["Schedule"]

        event_key = "{}{}".format(self.year, self.event_short)
        event = Event.get_by_id(event_key)
        if event.timezone_id:
            event_tz = pytz.timezone(event.timezone_id)
        else:
            logging.warning("Event {} has no timezone! Match times may be wrong.".format(event_key))
            event_tz = None

        set_number = 1
        parsed_matches = []
        for match in matches:
            comp_level = get_comp_level(match["level"], match["matchNumber"])
            match_number = get_match_number(comp_level, match["matchNumber"])

            red_teams = []
            blue_teams = []
            team_key_names = []
            null_team = False
            for team in match["Teams"]:
                if team["teamNumber"] is None:
                    null_team = True
                team_key = "frc{}".format(team["teamNumber"])
                team_key_names.append(team_key)
                if "Red" in team["station"]:
                    red_teams.append(team_key)
                elif "Blue" in team["station"]:
                    blue_teams.append(team_key)
            if null_team and match["scoreRedFinal"] is None and match["scoreBlueFinal"] is None:
                continue

            alliances = {
                "red": {"teams": red_teams, "score": match["scoreRedFinal"]},
                "blue": {"teams": blue_teams, "score": match["scoreBlueFinal"]},
            }

            score_breakdown = {
                "red": {"auto_points": match["scoreRedAuto"], "foul_points": match["scoreRedFoul"]},
                "blue": {"auto_points": match["scoreBlueAuto"], "foul_points": match["scoreBlueFoul"]},
            }

            time = datetime.datetime.strptime(match["startTime"], "%Y-%m-%dT%H:%M:%S")
            if event_tz is not None:
                time = time - event_tz.utcoffset(time)

            parsed_matches.append(
                Match(
                    id=Match.renderKeyName(event_key, comp_level, set_number, match_number),
                    event=event.key,
                    year=event.year,
                    set_number=set_number,
                    match_number=match_number,
                    comp_level=comp_level,
                    team_key_names=team_key_names,
                    time=time,
                    alliances_json=json.dumps(alliances),
                    score_breakdown_json=json.dumps(score_breakdown),
                )
            )

        # Fix null teams in elims (due to FMS API failure, some info not complete)
        # Should only happen for sf and f matches
        organized_matches = MatchHelper.organizeMatches(parsed_matches)
        for level in ["sf", "f"]:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(organized_matches)
            if playoff_advancement[LAST_LEVEL[level]] != []:
                for match in organized_matches[level]:
                    if "frcNone" in match.team_key_names:
                        if level == "sf":
                            red_seed, blue_seed = QF_SF_MAP[match.match_number]
                        else:
                            red_seed = 0
                            blue_seed = 1
                        red_teams = ["frc{}".format(t) for t in playoff_advancement[LAST_LEVEL[level]][red_seed][0]]
                        blue_teams = ["frc{}".format(t) for t in playoff_advancement[LAST_LEVEL[level]][blue_seed][0]]

                        alliances = match.alliances
                        alliances["red"]["teams"] = red_teams
                        alliances["blue"]["teams"] = blue_teams
                        match.alliances_json = json.dumps(alliances)
                        match.team_key_names = red_teams + blue_teams

        fixed_matches = []
        for key, matches in organized_matches.items():
            if key != "num":
                for match in matches:
                    if "frcNone" not in match.team_key_names:
                        fixed_matches.append(match)

        return fixed_matches
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()
        medias_future = media_query.EventTeamsPreferredMediasQuery(event_key).fetch_async()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        # Organize medias by team
        image_medias = MediaHelper.get_images([media for media in medias_future.get_result()])
        team_medias = defaultdict(list)
        for image_media in image_medias:
            for reference in image_media.references:
                team_medias[reference].append(image_media)
        team_and_medias = []
        for team in teams:
            team_and_medias.append((team, team_medias.get(team.key, [])))

        num_teams = len(team_and_medias)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = team_and_medias[:middle_value], team_and_medias[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event.alliance_selections)
        is_2015_playoff = EventHelper.is_2015_playoff(event_key)
        if is_2015_playoff:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(matches, event.alliance_selections)
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        else:
            playoff_advancement = None

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        event_insights = EventInsightsHelper.calculate_event_insights(cleaned_matches, event.year)
        event_insights_template = None
        if event_insights:
            event_insights_template = 'event_partials/event_insights_{}.html'.format(event.year)

        # rankings processing for ranking score per match
        full_rankings = event.rankings
        rankings_enhanced = event.rankings_enhanced
        if rankings_enhanced is not None:
            rp_index = RankingIndexes.CUMULATIVE_RANKING_SCORE[event.year]
            matches_index = RankingIndexes.MATCHES_PLAYED[event.year]
            ranking_criterion_name = full_rankings[0][rp_index]
            full_rankings[0].append(ranking_criterion_name + "/Match*")

            for row in full_rankings[1:]:
                team = row[1]
                if rankings_enhanced["ranking_score_per_match"] is not None:
                    rp_per_match = rankings_enhanced['ranking_score_per_match'][team]
                    row.append(rp_per_match)
                if rankings_enhanced["match_offset"] is not None:
                    match_offset = rankings_enhanced["match_offset"][team]
                    if match_offset != 0:
                        row[matches_index] = "{} ({})".format(row[matches_index], match_offset)

        self.template_values.update({
            "event": event,
            "district_name": DistrictType.type_names.get(event.event_district_enum, None),
            "district_abbrev": DistrictType.type_abbrevs.get(event.event_district_enum, None),
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "district_points_sorted": district_points_sorted,
            "is_2015_playoff": is_2015_playoff,
            "event_insights_qual": event_insights['qual'] if event_insights else None,
            "event_insights_playoff": event_insights['playoff'] if event_insights else None,
            "event_insights_template": event_insights_template,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)
예제 #14
0
    def _render(self, event_key):
        event = EventQuery(event_key).fetch()

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()
        event.prep_details()
        medias_future = media_query.EventTeamsPreferredMediasQuery(event_key).fetch_async()
        district_future = DistrictQuery(event.district_key.id()).fetch_async() if event.district_key else None
        event_medias_future = media_query.EventMediasQuery(event_key).fetch_async()
        status_sitevar_future = Sitevar.get_by_id_async('apistatus.down_events')

        event_divisions_future = None
        event_codivisions_future = None
        parent_event_future = None
        if event.divisions:
            event_divisions_future = ndb.get_multi_async(event.divisions)
        elif event.parent_event:
            parent_event_future = event.parent_event.get_async()
            event_codivisions_future = EventDivisionsQuery(event.parent_event.id()).fetch_async()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches, event)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        # Organize medias by team
        image_medias = MediaHelper.get_images([media for media in medias_future.get_result()])
        team_medias = defaultdict(list)
        for image_media in image_medias:
            for reference in image_media.references:
                team_medias[reference].append(image_media)
        team_and_medias = []
        for team in teams:
            team_and_medias.append((team, team_medias.get(team.key, [])))

        num_teams = len(team_and_medias)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = team_and_medias[:middle_value], team_and_medias[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event, event.alliance_selections)

        playoff_advancement = None
        playoff_template = None
        double_elim_matches = None
        if EventHelper.is_2015_playoff(event_key):
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(matches, event.alliance_selections)
            playoff_template = 'playoff_table'
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.ROUND_ROBIN_6_TEAM:
            playoff_advancement = MatchHelper.generatePlayoffAdvancementRoundRobin(matches, event.year, event.alliance_selections)
            playoff_template = 'playoff_round_robin_6_team'
            comp_levels = bracket_table.keys()
            for comp_level in comp_levels:
                if comp_level != 'f':
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.BO3_FINALS or event.playoff_type == PlayoffType.BO5_FINALS:
            comp_levels = bracket_table.keys()
            for comp_level in comp_levels:
                if comp_level != 'f':
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.DOUBLE_ELIM_8_TEAM:
            double_elim_matches = MatchHelper.organizeDoubleElimMatches(matches)

        district_points_sorted = None
        if event.district_key and event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        event_insights = event.details.insights if event.details else None
        event_insights_template = None
        if event_insights:
            event_insights_template = 'event_partials/event_insights_{}.html'.format(event.year)

        district = district_future.get_result() if district_future else None
        event_divisions = None
        if event_divisions_future:
            event_divisions = [e.get_result() for e in event_divisions_future]
        elif event_codivisions_future:
            event_divisions = event_codivisions_future.get_result()

        medias_by_slugname = MediaHelper.group_by_slugname([media for media in event_medias_future.get_result()])
        has_time_predictions = matches_upcoming and any(match.predicted_time for match in matches_upcoming)

        status_sitevar = status_sitevar_future.get_result()

        self.template_values.update({
            "event": event,
            "event_down": status_sitevar and event_key in status_sitevar.contents,
            "district_name": district.display_name if district else None,
            "district_abbrev": district.abbreviation if district else None,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            'has_time_predictions': has_time_predictions,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "playoff_template": playoff_template,
            "district_points_sorted": district_points_sorted,
            "event_insights_qual": event_insights['qual'] if event_insights else None,
            "event_insights_playoff": event_insights['playoff'] if event_insights else None,
            "event_insights_template": event_insights_template,
            "medias_by_slugname": medias_by_slugname,
            "event_divisions": event_divisions,
            'parent_event': parent_event_future.get_result() if parent_event_future else None,
            'double_elim_matches': double_elim_matches,
            'double_elim_playoff_types': PlayoffType.DOUBLE_ELIM_TYPES,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)
    def parse(self, response):
        """
        This currently only works for the 2015 game, where elims matches are all part of one set.
        """
        matches = response['Schedule']

        event_key = '{}{}'.format(self.year, self.event_short)
        event = Event.get_by_id(event_key)
        if event.timezone_id:
            event_tz = pytz.timezone(event.timezone_id)
        else:
            logging.warning("Event {} has no timezone! Match times may be wrong.".format(event_key))
            event_tz = None

        set_number = 1
        parsed_matches = []
        for match in matches:
            comp_level = self._get_comp_level(match['level'], match['matchNumber'])
            match_number = self._get_match_number(comp_level, match['matchNumber'])

            red_teams = []
            blue_teams = []
            team_key_names = []
            null_team = False
            for team in match['Teams']:
                if team['teamNumber'] is None:
                    null_team = True
                team_key = 'frc{}'.format(team['teamNumber'])
                team_key_names.append(team_key)
                if 'Red' in team['station']:
                    red_teams.append(team_key)
                elif 'Blue' in team['station']:
                    blue_teams.append(team_key)
            if null_team and match['scoreRedFinal'] is None and match['scoreBlueFinal'] is None:
                continue

            alliances = {
                'red': {
                    'teams': red_teams,
                    'score': match['scoreRedFinal']
                },
                'blue': {
                    'teams': blue_teams,
                    'score': match['scoreBlueFinal']
                }
            }

            score_breakdown = {
                'red': {
                    'auto': match['scoreRedAuto'],
                    'foul': match['scoreRedFoul']
                },
                'blue': {
                    'auto': match['scoreBlueAuto'],
                    'foul': match['scoreBlueFoul']
                }
            }

            time = datetime.datetime.strptime(match['startTime'], "%Y-%m-%dT%H:%M:%S")
            if event_tz is not None:
                time = time - event_tz.utcoffset(time)

            parsed_matches.append(Match(
                id=Match.renderKeyName(
                    event_key,
                    comp_level,
                    set_number,
                    match_number),
                event=event.key,
                year=event.year,
                set_number=set_number,
                match_number=match_number,
                comp_level=comp_level,
                team_key_names=team_key_names,
                time=time,
                alliances_json=json.dumps(alliances),
                score_breakdown_json=json.dumps(score_breakdown)
            ))

        # Fix null teams in elims (due to FMS API failure, some info not complete)
        # Should only happen for sf and f matches
        organized_matches = MatchHelper.organizeMatches(parsed_matches)
        for level in ['sf', 'f']:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(organized_matches)
            if playoff_advancement[LAST_LEVEL[level]] != []:
                for match in organized_matches[level]:
                    if 'frcNone' in match.team_key_names:
                        if level == 'sf':
                            red_seed, blue_seed = QF_SF_MAP[match.match_number]
                        else:
                            red_seed = 0
                            blue_seed = 1
                        red_teams = ['frc{}'.format(t) for t in playoff_advancement[LAST_LEVEL[level]][red_seed][0]]
                        blue_teams = ['frc{}'.format(t) for t in playoff_advancement[LAST_LEVEL[level]][blue_seed][0]]

                        alliances = match.alliances
                        alliances['red']['teams'] = red_teams
                        alliances['blue']['teams'] = blue_teams
                        match.alliances_json = json.dumps(alliances)
                        match.team_key_names = red_teams + blue_teams

        fixed_matches = []
        for key, matches in organized_matches.items():
            if key != 'num':
                for match in matches:
                    if 'frcNone' not in match.team_key_names:
                        fixed_matches.append(match)

        return fixed_matches
예제 #16
0
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()
        medias_future = media_query.EventTeamsPreferredMediasQuery(
            event_key).fetch_async()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        # Organize medias by team
        image_medias = MediaHelper.get_images(
            [media for media in medias_future.get_result()])
        team_medias = defaultdict(list)
        for image_media in image_medias:
            for reference in image_media.references:
                team_medias[reference].append(image_media)
        team_and_medias = []
        for team in teams:
            team_and_medias.append((team, team_medias.get(team.key, [])))

        num_teams = len(team_and_medias)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = team_and_medias[:middle_value], team_and_medias[
            middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()
                ] if (event.matchstats is not None
                      and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches,
                                                    event.alliance_selections)
        is_2015_playoff = EventHelper.is_2015_playoff(event_key)
        if is_2015_playoff:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(
                matches, event.alliance_selections)
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        else:
            playoff_advancement = None

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(
                event.district_points['points'].items(),
                key=lambda (team, points): -points['total'])

        event_insights = EventInsightsHelper.calculate_event_insights(
            cleaned_matches, event.year)
        event_insights_template = None
        if event_insights:
            event_insights_template = 'event_partials/event_insights_{}.html'.format(
                event.year)

        self.template_values.update({
            "event":
            event,
            "district_name":
            DistrictType.type_names.get(event.event_district_enum, None),
            "district_abbrev":
            DistrictType.type_abbrevs.get(event.event_district_enum, None),
            "matches":
            matches,
            "matches_recent":
            matches_recent,
            "matches_upcoming":
            matches_upcoming,
            "awards":
            awards,
            "teams_a":
            teams_a,
            "teams_b":
            teams_b,
            "num_teams":
            num_teams,
            "oprs":
            oprs,
            "bracket_table":
            bracket_table,
            "playoff_advancement":
            playoff_advancement,
            "district_points_sorted":
            district_points_sorted,
            "is_2015_playoff":
            is_2015_playoff,
            "event_insights_qual":
            event_insights['qual'] if event_insights else None,
            "event_insights_playoff":
            event_insights['playoff'] if event_insights else None,
            "event_insights_template":
            event_insights_template,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)
예제 #17
0
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        num_teams = len(teams)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = teams[:middle_value], teams[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event.alliance_selections)
        is_2015_playoff = EventHelper.is_2015_playoff(event_key)
        if is_2015_playoff:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(matches, event.alliance_selections)
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        else:
            playoff_advancement = None

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        self.template_values.update({
            "event": event,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "district_points_sorted": district_points_sorted,
            "is_2015_playoff": is_2015_playoff,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        path = os.path.join(os.path.dirname(__file__), '../templates/event_details.html')
        return template.render(path, self.template_values)
    def _render(self, event_key):
        event = EventQuery(event_key).fetch()

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()
        event.prep_details()
        medias_future = media_query.EventTeamsPreferredMediasQuery(event_key).fetch_async()
        district_future = DistrictQuery(event.district_key.id()).fetch_async() if event.district_key else None
        event_medias_future = media_query.EventMediasQuery(event_key).fetch_async()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        # Organize medias by team
        image_medias = MediaHelper.get_images([media for media in medias_future.get_result()])
        team_medias = defaultdict(list)
        for image_media in image_medias:
            for reference in image_media.references:
                team_medias[reference].append(image_media)
        team_and_medias = []
        for team in teams:
            team_and_medias.append((team, team_medias.get(team.key, [])))

        num_teams = len(team_and_medias)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = team_and_medias[:middle_value], team_and_medias[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event.alliance_selections)
        is_2015_playoff = EventHelper.is_2015_playoff(event_key)
        if is_2015_playoff:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(matches, event.alliance_selections)
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        else:
            playoff_advancement = None

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        event_insights = event.details.insights if event.details else None
        event_insights_template = None
        if event_insights:
            event_insights_template = 'event_partials/event_insights_{}.html'.format(event.year)

        district = district_future.get_result() if district_future else None

        medias_by_slugname = MediaHelper.group_by_slugname([media for media in event_medias_future.get_result()])

        self.template_values.update({
            "event": event,
            "district_name": district.display_name if district else None,
            "district_abbrev": district.abbreviation if district else None,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "district_points_sorted": district_points_sorted,
            "is_2015_playoff": is_2015_playoff,
            "event_insights_qual": event_insights['qual'] if event_insights else None,
            "event_insights_playoff": event_insights['playoff'] if event_insights else None,
            "event_insights_template": event_insights_template,
            "medias_by_slugname": medias_by_slugname,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)
예제 #19
0
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()

        awards = AwardHelper.organizeAwards(event.awards)
        if event.within_a_day:
            cleaned_matches = event.matches
        else:
            cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        num_teams = len(teams)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = teams[:middle_value], teams[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()
                ] if (event.matchstats is not None
                      and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches,
                                                    event.alliance_selections)
        if event.year == 2015:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(
                matches, event.alliance_selections)
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        else:
            playoff_advancement = None

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(
                event.district_points['points'].items(),
                key=lambda (team, points): -points['total'])

        self.template_values.update({
            "event":
            event,
            "matches":
            matches,
            "matches_recent":
            matches_recent,
            "matches_upcoming":
            matches_upcoming,
            "awards":
            awards,
            "teams_a":
            teams_a,
            "teams_b":
            teams_b,
            "num_teams":
            num_teams,
            "oprs":
            oprs,
            "bracket_table":
            bracket_table,
            "playoff_advancement":
            playoff_advancement,
            "district_points_sorted":
            district_points_sorted,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        path = os.path.join(os.path.dirname(__file__),
                            '../templates/event_details.html')
        return template.render(path, self.template_values)
예제 #20
0
    def calculate_event_points(cls, event):
        match_key_futures = Match.query(Match.event == event.key).fetch_async(None, keys_only=True)
        award_key_futures = Award.query(Award.event == event.key).fetch_async(None, keys_only=True)

        match_futures = ndb.get_multi_async(match_key_futures.get_result())
        award_futures = ndb.get_multi_async(award_key_futures.get_result())

        POINTS_MULTIPLIER = 3 if event.event_type_enum == EventType.DISTRICT_CMP else 1

        district_points = {
            'points': defaultdict(lambda: {
                'qual_points': 0,
                'elim_points': 0,
                'alliance_points': 0,
                'award_points': 0,
                'total': 0,
            }),
            'tiebreakers': defaultdict(lambda: {  # for tiebreaker stats that can't be calculated with 'points'
                'qual_wins': 0,
                'highest_qual_scores': [],
            }),
        }

        # match points
        if event.year == 2015:
            from helpers.match_helper import MatchHelper  # circular import issue

            # qual match points are calculated by rank
            if event.rankings and len(event.rankings) > 1:
                rankings = event.rankings[1:]  # skip title row
                num_teams = len(rankings)
                alpha = 1.07
                for row in rankings:
                    rank = int(row[0])
                    team = 'frc{}'.format(row[1])
                    qual_points = int(np.ceil(cls.inverf(float(num_teams - 2 * rank + 2) / (alpha * num_teams)) * (10.0 / cls.inverf(1.0 / alpha)) + 12))
                    district_points['points'][team]['qual_points'] = qual_points * POINTS_MULTIPLIER
            else:
                logging.warning("Event {} has no rankings for qual_points calculations!".format(event.key.id()))

            matches = MatchHelper.organizeMatches([mf.get_result() for mf in match_futures])

            # qual match calculations. only used for tiebreaking
            for match in matches['qm']:
                for color in ['red', 'blue']:
                    for team in match.alliances[color]['teams']:
                        score = match.alliances[color]['score']
                        district_points['tiebreakers'][team]['highest_qual_scores'] = heapq.nlargest(3, district_points['tiebreakers'][team]['highest_qual_scores'] + [score])

            # elim match point calculations
            # count number of matches played per team per comp level
            num_played = defaultdict(lambda: defaultdict(int))
            for level in ['qf', 'sf']:
                for match in matches[level]:
                    if not match.has_been_played:
                        continue
                    for color in ['red', 'blue']:
                        for team in match.alliances[color]['teams']:
                            num_played[level][team] += 1

            # qf and sf points
            advancement = MatchHelper.generatePlayoffAdvancement2015(matches)
            for last_level, level in [('qf', 'sf'), ('sf', 'f')]:
                for (teams, _, _) in advancement[last_level]:
                    teams = ['frc{}'.format(t) for t in teams]
                    done = False
                    for match in matches[level]:
                        for color in ['red', 'blue']:
                            if set(teams).intersection(set(match.alliances[color]['teams'])) != set():
                                for team in teams:
                                    points = 5.0 if last_level == 'qf' else 3.3
                                    district_points['points'][team]['elim_points'] += int(np.ceil(points * num_played[last_level][team])) * POINTS_MULTIPLIER
                                done = True
                                break
                            if done:
                                break
                        if done:
                            break

            # final points
            num_wins = {'red': 0, 'blue': 0}
            team_matches_played = {'red': [], 'blue': []}
            for match in matches['f']:
                if not match.has_been_played or match.winning_alliance == '':
                    continue

                num_wins[match.winning_alliance] += 1
                for team in match.alliances[match.winning_alliance]['teams']:
                    team_matches_played[match.winning_alliance].append(team)

                if num_wins[match.winning_alliance] >= 2:
                    for team in team_matches_played[match.winning_alliance]:
                        district_points['points'][team]['elim_points'] += 5 * POINTS_MULTIPLIER

        else:
            elim_num_wins = defaultdict(lambda: defaultdict(int))
            elim_alliances = defaultdict(lambda: defaultdict(list))
            for match_future in match_futures:
                match = match_future.get_result()
                if not match.has_been_played:
                    continue

                if match.comp_level == 'qm':
                    if match.winning_alliance == '':
                        for team in match.team_key_names:
                            district_points['points'][team]['qual_points'] += 1 * POINTS_MULTIPLIER
                    else:
                        for team in match.alliances[match.winning_alliance]['teams']:
                            district_points['points'][team]['qual_points'] += 2 * POINTS_MULTIPLIER
                            district_points['tiebreakers'][team]['qual_wins'] += 1

                    for color in ['red', 'blue']:
                        for team in match.alliances[color]['teams']:
                            score = match.alliances[color]['score']
                            district_points['tiebreakers'][team]['highest_qual_scores'] = heapq.nlargest(3, district_points['tiebreakers'][team]['highest_qual_scores'] + [score])
                else:
                    if match.winning_alliance == '':
                        continue

                    match_set_key = '{}_{}{}'.format(match.event.id(), match.comp_level, match.set_number)
                    elim_num_wins[match_set_key][match.winning_alliance] += 1
                    elim_alliances[match_set_key][match.winning_alliance] += match.alliances[match.winning_alliance]['teams']

                    if elim_num_wins[match_set_key][match.winning_alliance] >= 2:
                        for team in elim_alliances[match_set_key][match.winning_alliance]:
                            district_points['points'][team]['elim_points'] += 5* POINTS_MULTIPLIER

        # alliance points
        if event.alliance_selections:
            selection_points = EventHelper.alliance_selections_to_points(event.alliance_selections)
            for team, points in selection_points.items():
                district_points['points'][team]['alliance_points'] += points * POINTS_MULTIPLIER
        else:
            logging.warning("Event {} has no alliance selection district_points!".format(event.key.id()))

        # award points
        for award_future in award_futures:
            award = award_future.get_result()
            if award.award_type_enum not in AwardType.NON_JUDGED_NON_TEAM_AWARDS:
                if award.award_type_enum == AwardType.CHAIRMANS:
                    point_value = 10
                elif award.award_type_enum in {AwardType.ENGINEERING_INSPIRATION, AwardType.ROOKIE_ALL_STAR}:
                    point_value = 8
                else:
                    point_value = 5
                for team in award.team_list:
                    district_points['points'][team.id()]['award_points'] += point_value * POINTS_MULTIPLIER

        for team, point_breakdown in district_points['points'].items():
            for p in point_breakdown.values():
                district_points['points'][team]['total'] += p

        return district_points