def deleteInvalidMatches(self, match_list): """ A match is invalid iff it is an elim match where the match number is 3 and the same alliance won in match numbers 1 and 2 of the same set. """ matches_by_key = {} for match in match_list: matches_by_key[match.key_name] = match return_list = [] for match in match_list: if match.comp_level in Match.ELIM_LEVELS and match.match_number == 3 and ( not match.has_been_played): match_1 = matches_by_key.get( Match.renderKeyName(match.event.id(), match.comp_level, match.set_number, 1)) match_2 = matches_by_key.get( Match.renderKeyName(match.event.id(), match.comp_level, match.set_number, 2)) if match_1 is not None and match_2 is not None and\ match_1.has_been_played and match_2.has_been_played and\ match_1.winning_alliance == match_2.winning_alliance: try: MatchManipulator.delete(match) logging.warning("Deleting invalid match: %s" % match.key_name) except: logging.warning( "Tried to delete invalid match, but failed: %s" % match.key_name) continue return_list.append(match) return return_list
def deleteInvalidMatches(self, match_list): """ A match is invalid iff it is an elim match where the match number is 3 and the same alliance won in match numbers 1 and 2 of the same set. """ matches_by_key = {} for match in match_list: matches_by_key[match.key_name] = match return_list = [] for match in match_list: if match.comp_level in Match.ELIM_LEVELS and match.match_number == 3 and (not match.has_been_played): match_1 = matches_by_key.get( Match.renderKeyName(match.event.id(), match.comp_level, match.set_number, 1) ) match_2 = matches_by_key.get( Match.renderKeyName(match.event.id(), match.comp_level, match.set_number, 2) ) if ( match_1 != None and match_2 != None and match_1.has_been_played and match_2.has_been_played and match_1.winning_alliance == match_2.winning_alliance ): try: match.key.delete() logging.warning("Deleting invalid match: %s" % match.key_name) except: logging.warning("Tried to delete invalid match, but failed: %s" % match.key_name) continue return_list.append(match) return return_list
def post(self): self._require_admin() event_key = self.request.get('event_key') matches_csv = self.request.get('matches_csv') matches = OffseasonMatchesParser.parse(matches_csv) event = Event.get_by_id(event_key) matches = [Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None) ) for match in matches] new_matches = MatchManipulator.createOrUpdate(matches) try: last_matches = MatchHelper.recentMatches(new_matches, 1) upcoming_matches = MatchHelper.upcomingMatches(new_matches, 8) except: logging.warning("Computing last/upcoming matches for Firebase failed!") try: FirebasePusher.updateEvent(event, last_matches, upcoming_matches) except: logging.warning("Enqueuing Firebase push failed!") self.redirect('/admin/event/{}'.format(event_key))
def parse(self, response): matches = response["MatchScores"] match_details_by_key = {} is_octofinals = len(matches) > 0 and matches[len(matches) - 1]["matchNumber"] > 21 for match in matches: comp_level = get_comp_level(self.year, match["matchLevel"], match["matchNumber"], is_octofinals) set_number, match_number = get_set_match_number(self.year, comp_level, match["matchNumber"], is_octofinals) breakdown = {"red": {}, "blue": {}} if "coopertition" in match: breakdown["coopertition"] = match["coopertition"] if "coopertitionPoints" in match: breakdown["coopertition_points"] = match["coopertitionPoints"] for alliance in match["Alliances"]: color = alliance["alliance"].lower() for key, value in alliance.items(): if key != "alliance": breakdown[color][key] = value match_details_by_key[ Match.renderKeyName("{}{}".format(self.year, self.event_short), comp_level, set_number, match_number) ] = breakdown return match_details_by_key
def post(self): self._require_admin() event_key = self.request.get('event_key') matches_csv = self.request.get('matches_csv') matches, _ = OffseasonMatchesParser.parse(matches_csv) event = Event.get_by_id(event_key) matches = [Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None) ) for match in matches] MatchManipulator.createOrUpdate(matches) self.redirect('/admin/event/{}'.format(event_key))
def parse(self, response): """ This currently only works for the 2015 game. """ matches = response['MatchScores'] match_details_by_key = {} set_number = 1 for match in matches: comp_level = get_comp_level(match['matchLevel'], match['matchNumber']) match_number = get_match_number(comp_level, match['matchNumber']) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] for alliance in match['Alliances']: color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][camel_to_snake(key)] = value match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
def get(self, year): year_event_keys = Event.query(Event.year == int(year)).fetch(1000, keys_only=True) final_match_keys = [] for event_key in year_event_keys: final_match_keys.extend(Match.query(Match.event == event_key, Match.comp_level == 'f').fetch(100, keys_only=True)) match_keys_to_repair = [] for match_key in final_match_keys: key_name = match_key.id() if '_f0m' in key_name: match_keys_to_repair.append(match_key) deleted_keys = [] matches_to_repair = ndb.get_multi(match_keys_to_repair) for match in matches_to_repair: deleted_keys.append(match.key) event = ndb.get_multi([match.event])[0] match.set_number = 1 match.key = ndb.Key(Match, Match.renderKeyName( event.key.id(), match.comp_level, match.set_number, match.match_number)) MatchManipulator.createOrUpdate(matches_to_repair) MatchManipulator.delete_keys(deleted_keys) template_values = {'deleted_keys': deleted_keys, 'new_matches': matches_to_repair} path = os.path.join(os.path.dirname(__file__), '../templates/math/final_matches_repair_do.html') self.response.out.write(template.render(path, template_values))
def post(self): self._require_admin() event_key = self.request.get('event_key') matches_csv = self.request.get('matches_csv') matches = OffseasonMatchesParser.parse(matches_csv) event = Event.get_by_id(event_key) matches = [ Match(id=Match.renderKeyName(event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None)) for match in matches ] try: FirebasePusher.updated_event(event.key_name) except: logging.warning("Enqueuing Firebase push failed!") self.redirect('/admin/event/{}'.format(event_key))
def _process_request(self, request, event_key): event = Event.get_by_id(event_key) year = int(event_key[:4]) matches = [] needs_time = [] for match in JSONMatchesParser.parse(request.body, year): match = Match( id=Match.renderKeyName(event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None), score_breakdown_json=match.get("score_breakdown_json", None), time_string=match.get("time_string", None), time=match.get("time", None), ) if (not match.time or match.time == "") and match.time_string: # We can calculate the real time from the time string needs_time.append(match) matches.append(match) if needs_time: try: logging.debug("Calculating time!") MatchHelper.add_match_times(event, needs_time) except Exception, e: logging.error("Failed to calculate match times")
def parse(self, response): matches = response['MatchScores'] event_key = '{}{}'.format(self.year, self.event_short) event = Event.get_by_id(event_key) match_details_by_key = {} for match in matches: comp_level = PlayoffType.get_comp_level(event.playoff_type, match['matchLevel'], match['matchNumber']) set_number, match_number = PlayoffType.get_set_match_number( event.playoff_type, comp_level, match['matchNumber']) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] for alliance in match['Alliances']: color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][key] = value match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
def post(self): self._require_admin() event_key = self.request.get('event_key') matches_csv = self.request.get('matches_csv') matches = OffseasonMatchesParser.parse(matches_csv) event = Event.get_by_id(event_key) matches = [Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None) ) for match in matches] try: FirebasePusher.updated_event(event.key_name) except: logging.warning("Enqueuing Firebase push failed!") self.redirect('/admin/event/{}'.format(event_key))
def parse(self, response): matches = response['MatchScores'] match_details_by_key = {} for match in matches: comp_level = get_comp_level(self.year, match['matchLevel'], match['matchNumber']) set_number, match_number = get_set_match_number(self.year, comp_level, match['matchNumber']) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] for alliance in match['Alliances']: color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][key] = value match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
def parse(self, response): matches = response['MatchScores'] match_details_by_key = {} is_octofinals = len(matches) > 0 and matches[len(matches) - 1]['matchNumber'] > 23 # Hacky; this should be 24. Banking on the fact that 3 tiebreakers is rare for match in matches: comp_level = get_comp_level(self.year, match['matchLevel'], match['matchNumber'], is_octofinals) set_number, match_number = get_set_match_number(self.year, comp_level, match['matchNumber'], is_octofinals) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] for alliance in match['Alliances']: color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][key] = value match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
def parse(self, response): """ This currently only works for the 2015 game. """ matches = response["MatchScores"] match_details_by_key = {} set_number = 1 for match in matches: comp_level = get_comp_level(match["matchLevel"], match["matchNumber"]) match_number = get_match_number(comp_level, match["matchNumber"]) breakdown = {"red": {}, "blue": {}} if "coopertition" in match: breakdown["coopertition"] = match["coopertition"] if "coopertitionPoints" in match: breakdown["coopertition_points"] = match["coopertitionPoints"] for alliance in match["Alliances"]: color = alliance["alliance"].lower() for key, value in alliance.items(): if key != "alliance": breakdown[color][camel_to_snake(key)] = value match_details_by_key[ Match.renderKeyName("{}{}".format(self.year, self.event_short), comp_level, set_number, match_number) ] = breakdown return match_details_by_key
def setupMatches(csv): with open(csv, 'r') as f: event = Event( id = "2013test", event_short = "test", year = 2013 ) parsed_matches = OffseasonMatchesParser.parse(f.read()) matches = [Match( id = Match.renderKeyName( event, match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event = event.key, game = Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number = match.get("set_number", 0), match_number = match.get("match_number", 0), comp_level = match.get("comp_level", None), team_key_names = match.get("team_key_names", None), alliances_json = match.get("alliances_json", None) ) for match in parsed_matches] return matches
def _process_request(self, request, event_key): event = Event.get_by_id(event_key) year = int(event_key[:4]) matches = [] for match in JSONMatchesParser.parse(request.body, year): match = Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None), score_breakdown_json=match.get("score_breakdown_json", None), time_string=match.get("time_string", None), time=match.get("time", None), ) if (not match.time or match.time == "") and match.time_string: # We can calculate the real time from the time string logging.debug("Calculating time!") MatchHelper.add_match_times(event, [match]) matches.append(match) MatchManipulator.createOrUpdate(matches) self.response.out.write(json.dumps({'Success': "Matches successfully updated"}))
def post(self): self._require_admin() event_key = self.request.get('event_key') matches_csv = self.request.get('matches_csv') matches, _ = OffseasonMatchesParser.parse(matches_csv) event = Event.get_by_id(event_key) matches = [Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None) ) for match in matches] MatchManipulator.createOrUpdate(matches) self.redirect('/admin/event/{}'.format(event_key))
def get(self, year): year_event_keys = Event.query(Event.year == int(year)).fetch(1000, keys_only=True) final_match_keys = [] for event_key in year_event_keys: final_match_keys.extend(Match.query(Match.event == event_key, Match.comp_level == 'f').fetch(100, keys_only=True)) match_keys_to_repair = [] for match_key in final_match_keys: key_name = match_key.id() if '_f0m' in key_name: match_keys_to_repair.append(match_key) deleted_keys = [] matches_to_repair = ndb.get_multi(match_keys_to_repair) for match in matches_to_repair: deleted_keys.append(match.key) event = ndb.get_multi([match.event])[0] match.set_number = 1 match.key = ndb.Key(Match, Match.renderKeyName( event.key.id(), match.comp_level, match.set_number, match.match_number)) MatchManipulator.createOrUpdate(matches_to_repair) MatchManipulator.delete_keys(deleted_keys) template_values = {'deleted_keys': deleted_keys, 'new_matches': matches_to_repair} path = os.path.join(os.path.dirname(__file__), '../templates/math/final_matches_repair_do.html') self.response.out.write(template.render(path, template_values))
def _process_request(self, request, event_key): matches = [] needs_time = [] for match in JSONMatchesParser.parse(request.body, self.event.year): match = Match( id=Match.renderKeyName( self.event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=self.event.key, year=self.event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None), score_breakdown_json=match.get("score_breakdown_json", None), time_string=match.get("time_string", None), time=match.get("time", None), ) if (not match.time or match.time == "") and match.time_string: # We can calculate the real time from the time string needs_time.append(match) matches.append(match) if needs_time: try: logging.debug("Calculating time!") MatchHelper.add_match_times(self.event, needs_time) except Exception, e: logging.error("Failed to calculate match times")
def parse(self, response): matches = response['MatchScores'] match_details_by_key = {} is_octofinals = len(matches) > 0 and matches[len(matches) - 1][ 'matchNumber'] > 23 # Hacky; this should be 24. Banking on the fact that 3 tiebreakers is rare for match in matches: comp_level = get_comp_level(self.year, match['matchLevel'], match['matchNumber'], is_octofinals) set_number, match_number = get_set_match_number( self.year, comp_level, match['matchNumber'], is_octofinals) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] for alliance in match['Alliances']: color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][key] = value match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
def getMatches(self, event): matches_url = self.YEAR_MATCH_RESULTS_URL_PATTERN.get( event.year, self.DEFAULT_MATCH_RESULTS_URL_PATTERN) % ( event.year, self.EVENT_SHORT_EXCEPTIONS.get(event.event_short, event.event_short)) match_dicts, _ = self.parse(matches_url, self.YEAR_MATCH_PARSER.get(event.year, self.DEFAULT_MATCH_PARSER)) if not match_dicts: # Matches have not been played, but qual match schedule may be out # If this is run when there are already matches in the DB, it will overwrite scores! # Check to make sure event has no existing matches if len(Match.query(Match.event == event.key).fetch(1, keys_only=True)) == 0: logging.warning("No matches found for {}. Trying to parse qual match schedule.".format(event.key.id())) qual_match_sched_url = self.MATCH_SCHEDULE_QUAL_URL_PATTERN % ( event.year, self.EVENT_SHORT_EXCEPTIONS.get(event.event_short, event.event_short)) match_dicts, _ = self.parse(qual_match_sched_url, self.MATCH_SCHEDULE_PARSER) for match_dict in match_dicts: alliances = json.loads(match_dict['alliances_json']) if (alliances['red']['score'] == -1 or alliances['blue']['score'] == -1 or match_dict['comp_level'] in Match.ELIM_LEVELS): break else: # Only qual matches have been played and they have all been played # If this is run when there are already elim matches in the DB, it will overwrite scores! # Check to make sure event has no existing elim matches if len(Match.query(Match.event == event.key, Match.comp_level.IN(Match.ELIM_LEVELS)).fetch(1, keys_only=True)) == 0: logging.warning("No elim matches found for {}. Trying to parse elim match schedule.".format(event.key.id())) elim_match_sched_url = self.MATCH_SCHEDULE_ELIMS_URL_PATTERN % ( event.year, self.EVENT_SHORT_EXCEPTIONS.get(event.event_short, event.event_short)) elim_match_dicts, _ = self.parse(elim_match_sched_url, self.MATCH_SCHEDULE_PARSER) match_dicts += elim_match_dicts matches = [Match( id=Match.renderKeyName( event.key.id(), match_dict.get("comp_level", None), match_dict.get("set_number", 0), match_dict.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match_dict.get("set_number", 0), match_number=match_dict.get("match_number", 0), comp_level=match_dict.get("comp_level", None), team_key_names=match_dict.get("team_key_names", None), time_string=match_dict.get("time_string", None), alliances_json=match_dict.get("alliances_json", None) ) for match_dict in match_dicts] MatchHelper.add_match_times(event, matches) return matches
def getMatches(self, event): matches_url = self.YEAR_MATCH_RESULTS_URL_PATTERN.get( event.year, self.DEFAULT_MATCH_RESULTS_URL_PATTERN) % ( event.year, self.EVENT_SHORT_EXCEPTIONS.get(event.event_short, event.event_short)) match_dicts, _ = self.parse(matches_url, self.YEAR_MATCH_PARSER.get(event.year, self.DEFAULT_MATCH_PARSER)) if not match_dicts: # Matches have not been played, but qual match schedule may be out # If this is run when there are already matches in the DB, it will overwrite scores! # Check to make sure event has no existing matches if len(Match.query(Match.event == event.key).fetch(1, keys_only=True)) == 0: logging.warning("No matches found for {}. Trying to parse qual match schedule.".format(event.key.id())) qual_match_sched_url = self.MATCH_SCHEDULE_QUAL_URL_PATTERN % ( event.year, self.EVENT_SHORT_EXCEPTIONS.get(event.event_short, event.event_short)) match_dicts, _ = self.parse(qual_match_sched_url, self.MATCH_SCHEDULE_PARSER) for match_dict in match_dicts: alliances = json.loads(match_dict['alliances_json']) if (alliances['red']['score'] == -1 or alliances['blue']['score'] == -1 or match_dict['comp_level'] in Match.ELIM_LEVELS): break else: # Only qual matches have been played and they have all been played # If this is run when there are already elim matches in the DB, it will overwrite scores! # Check to make sure event has no existing elim matches if len(Match.query(Match.event == event.key, Match.comp_level.IN(Match.ELIM_LEVELS)).fetch(1, keys_only=True)) == 0: logging.warning("No elim matches found for {}. Trying to parse elim match schedule.".format(event.key.id())) elim_match_sched_url = self.MATCH_SCHEDULE_ELIMS_URL_PATTERN % ( event.year, self.EVENT_SHORT_EXCEPTIONS.get(event.event_short, event.event_short)) elim_match_dicts, _ = self.parse(elim_match_sched_url, self.MATCH_SCHEDULE_PARSER) match_dicts += elim_match_dicts matches = [Match( id=Match.renderKeyName( event.key.id(), match_dict.get("comp_level", None), match_dict.get("set_number", 0), match_dict.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match_dict.get("set_number", 0), match_number=match_dict.get("match_number", 0), comp_level=match_dict.get("comp_level", None), team_key_names=match_dict.get("team_key_names", None), time_string=match_dict.get("time_string", None), alliances_json=match_dict.get("alliances_json", None) ) for match_dict in match_dicts] MatchHelper.add_match_times(event, matches) return matches
def matchDictToMatches(self, match_dicts): return [Match(id=Match.renderKeyName(self.event.key.id(), match_dict.get("comp_level", None), match_dict.get("set_number", 0), match_dict.get("match_number", 0)), event=self.event.key, year=self.event.year, set_number=match_dict.get("set_number", 0), match_number=match_dict.get("match_number", 0), comp_level=match_dict.get("comp_level", None), team_key_names=match_dict.get("team_key_names", None), time_string=match_dict.get("time_string", None), alliances_json=match_dict.get("alliances_json", None)) for match_dict in match_dicts]
def parse(self, response): matches = response['MatchScores'] event_key = '{}{}'.format(self.year, self.event_short) event = Event.get_by_id(event_key) match_details_by_key = {} for match in matches: comp_level = PlayoffType.get_comp_level(event.playoff_type, match['matchLevel'], match['matchNumber']) set_number, match_number = PlayoffType.get_set_match_number(event.playoff_type, comp_level, match['matchNumber']) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] game_data = None if self.year == 2018: # Switches should be the same, but parse individually in case FIRST change things right_switch_red = match['switchRightNearColor'] == 'Red' scale_red = match['scaleNearColor'] == 'Red' left_switch_red = match['switchLeftNearColor'] == 'Red' game_data = '{}{}{}'.format( 'L' if right_switch_red else 'R', 'L' if scale_red else 'R', 'L' if left_switch_red else 'R', ) for alliance in match.get('alliances', match.get('Alliances', [])): color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][key] = value if game_data is not None: breakdown[color]['tba_gameData'] = game_data match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
def set_up_matches(html, event): with open(html, 'r') as f: parsed_matches, _ = UsfirstMatchesParser.parse(f.read()) matches = [Match(id=Match.renderKeyName(event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None)) for match in parsed_matches] return matches
def setupMatches(self, csv): with open(csv, 'r') as f: parsed_matches, _ = OffseasonMatchesParser.parse(f.read()) matches = [Match(id=Match.renderKeyName(self.event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=self.event.key, year=self.event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None)) for match in parsed_matches] return matches
def getMatches(self, event, url): matches = self.parse(url, OffseasonMatchesParser) logging.info(matches) return [ Match(id=Match.renderKeyName(event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None)) for match in matches ]
def set_up_matches(html, event): with open(html, 'r') as f: parsed_matches, _ = UsfirstMatchesParser.parse(f.read()) matches = [ Match(id=Match.renderKeyName(event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None)) for match in parsed_matches ] return matches
def getMatches(self, event, url): matches = self.parse(url, OffseasonMatchesParser) logging.info(matches) return [Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None) ) for match in matches]
def match_dict_to_matches(self, match_dicts): return [ Match( id=Match.renderKeyName( self.event.key.id(), match_dict.get("comp_level", None), match_dict.get("set_number", 0), match_dict.get("match_number", 0), ), event=self.event.key, game=Match.FRC_GAMES_BY_YEAR.get(self.event.year, "frc_unknown"), set_number=match_dict.get("set_number", 0), match_number=match_dict.get("match_number", 0), comp_level=match_dict.get("comp_level", None), team_key_names=match_dict.get("team_key_names", None), time_string=match_dict.get("time_string", None), alliances_json=match_dict.get("alliances_json", None), ) for match_dict in match_dicts ]
def getMatches(self, event): url = self.MATCH_RESULTS_URL_PATTERN % (event.year, self.EVENT_SHORT_EXCEPTIONS.get(event.event_short, event.event_short)) matches, _ = self.parse(url, UsfirstMatchesParser) return [Match( id=Match.renderKeyName( event, match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), time_string=match.get("time_string", None), alliances_json=match.get("alliances_json", None) ) for match in matches]
def setupMatches(self, csv): with open(csv, "r") as f: parsed_matches = OffseasonMatchesParser.parse(f.read()) matches = [ Match( id=Match.renderKeyName( self.event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0), ), event=self.event.key, game=Match.FRC_GAMES_BY_YEAR.get(self.event.year, "frc_unknown"), set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None), ) for match in parsed_matches ] return matches
def _process_request(self, request, event_key): event = Event.get_by_id(event_key) year = int(event_key[:4]) matches = [Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None), score_breakdown_json=match.get("score_breakdown_json", None), time_string=match.get("time_string", None), time=match.get("time", None), ) for match in JSONMatchesParser.parse(request.body, year)] MatchManipulator.createOrUpdate(matches)
def _process_request(self, request, event_key): event = Event.get_by_id(event_key) year = int(event_key[:4]) matches = [ Match( id=Match.renderKeyName(event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None), score_breakdown_json=match.get("score_breakdown_json", None), time_string=match.get("time_string", None), time=match.get("time", None), ) for match in JSONMatchesParser.parse(request.body, year) ] MatchManipulator.createOrUpdate(matches)
def get(self, event_key): if tba_config.CONFIG["env"] == "prod": # disable in prod for now logging.error("Tried to restore {} from CSV in prod! No can do.".format(event_key)) return event = Event.get_by_id(event_key) # alliances result = urlfetch.fetch(self.ALLIANCES_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.ALLIANCES_URL.format(event.year, event_key, event_key))) else: data = result.content.replace('frc', '') alliance_selections = CSVAllianceSelectionsParser.parse(data) event_details = EventDetails( id=event_key, alliance_selections=alliance_selections ) EventDetailsManipulator.createOrUpdate(event_details) # awards result = urlfetch.fetch(self.AWARDS_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.AWARDS_URL.format(event.year, event_key, event_key))) else: # convert into expected input format data = StringIO.StringIO() writer = csv.writer(data, delimiter=',') for row in csv.reader(StringIO.StringIO(result.content), delimiter=','): writer.writerow([event.year, event.event_short, row[1], row[2].replace('frc', ''), row[3]]) awards = [] for award in CSVAwardsParser.parse(data.getvalue()): awards.append(Award( id=Award.render_key_name(event.key_name, award['award_type_enum']), name_str=award['name_str'], award_type_enum=award['award_type_enum'], year=event.year, event=event.key, event_type_enum=event.event_type_enum, team_list=[ndb.Key(Team, 'frc{}'.format(team_number)) for team_number in award['team_number_list']], recipient_json_list=award['recipient_json_list'] )) AwardManipulator.createOrUpdate(awards) # matches result = urlfetch.fetch(self.MATCHES_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.MATCHES_URL.format(event.year, event_key, event_key))) else: data = result.content.replace('frc', '').replace('{}_'.format(event_key), '') match_dicts, _ = OffseasonMatchesParser.parse(data) matches = [ Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None) ) for match in match_dicts] MatchManipulator.createOrUpdate(matches) # rankings result = urlfetch.fetch(self.RANKINGS_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.RANKINGS_URL.format(event.year, event_key, event_key))) else: # convert into expected input format rankings = list(csv.reader(StringIO.StringIO(result.content), delimiter=',')) event_details = EventDetails( id=event_key, rankings=rankings ) EventDetailsManipulator.createOrUpdate(event_details) self.response.out.write("Done restoring {}!".format(event_key))
def get(self, event_key): if tba_config.CONFIG["env"] == "prod": # disable in prod for now logging.error("Tried to restore {} from CSV in prod! No can do.".format(event_key)) return event = Event.get_by_id(event_key) # alliances result = urlfetch.fetch(self.ALLIANCES_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.ALLIANCES_URL.format(event.year, event_key, event_key))) else: data = result.content.replace('frc', '') alliance_selections = CSVAllianceSelectionsParser.parse(data) event_details = EventDetails( id=event_key, alliance_selections=alliance_selections ) EventDetailsManipulator.createOrUpdate(event_details) # awards result = urlfetch.fetch(self.AWARDS_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.AWARDS_URL.format(event.year, event_key, event_key))) else: # convert into expected input format data = StringIO.StringIO() writer = csv.writer(data, delimiter=',') for row in csv.reader(StringIO.StringIO(result.content), delimiter=','): writer.writerow([event.year, event.event_short, row[1], row[2].replace('frc', ''), row[3]]) awards = [] for award in CSVAwardsParser.parse(data.getvalue()): awards.append(Award( id=Award.render_key_name(event.key_name, award['award_type_enum']), name_str=award['name_str'], award_type_enum=award['award_type_enum'], year=event.year, event=event.key, event_type_enum=event.event_type_enum, team_list=[ndb.Key(Team, 'frc{}'.format(team_number)) for team_number in award['team_number_list']], recipient_json_list=award['recipient_json_list'] )) AwardManipulator.createOrUpdate(awards) # matches result = urlfetch.fetch(self.MATCHES_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.MATCHES_URL.format(event.year, event_key, event_key))) else: data = result.content.replace('frc', '').replace('{}_'.format(event_key), '') match_dicts, _ = OffseasonMatchesParser.parse(data) matches = [ Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None) ) for match in match_dicts] MatchManipulator.createOrUpdate(matches) # rankings result = urlfetch.fetch(self.RANKINGS_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.RANKINGS_URL.format(event.year, event_key, event_key))) else: # convert into expected input format rankings = list(csv.reader(StringIO.StringIO(result.content), delimiter=',')) event_details = EventDetails( id=event_key, rankings=rankings ) EventDetailsManipulator.createOrUpdate(event_details) self.response.out.write("Done restoring {}!".format(event_key))
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 = [] 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
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 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
def parse(self, response): matches = response['MatchScores'] event_key = '{}{}'.format(self.year, self.event_short) event = Event.get_by_id(event_key) match_details_by_key = {} for match in matches: comp_level = PlayoffType.get_comp_level(event.playoff_type, match['matchLevel'], match['matchNumber']) set_number, match_number = PlayoffType.get_set_match_number(event.playoff_type, comp_level, match['matchNumber']) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] game_data = None if self.year == 2018: # Switches should be the same, but parse individually in case FIRST change things right_switch_red = match['switchRightNearColor'] == 'Red' scale_red = match['scaleNearColor'] == 'Red' left_switch_red = match['switchLeftNearColor'] == 'Red' game_data = '{}{}{}'.format( 'L' if right_switch_red else 'R', 'L' if scale_red else 'R', 'L' if left_switch_red else 'R', ) for alliance in match.get('alliances', match.get('Alliances', [])): color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][key] = value if game_data is not None: breakdown[color]['tba_gameData'] = game_data if self.year == 2019: # Derive incorrect completedRocketFar and completedRocketNear returns from FIRST API for side1 in ['Near', 'Far']: completedRocket = True for side2 in ['Left', 'Right']: for level in ['low', 'mid', 'top']: if breakdown[color]['{}{}Rocket{}'.format(level, side2, side1)] != 'PanelAndCargo': completedRocket = False break if not completedRocket: break breakdown[color]['completedRocket{}'.format(side1)] = completedRocket match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
def _render(self, event_key): event = Event.get_by_id(event_key) if not event or event.year < 2016 or not event.details or not event.details.predictions: self.abort(404) event.get_matches_async() match_predictions = event.details.predictions.get('match_predictions', None) match_prediction_stats = event.details.predictions.get('match_prediction_stats', None) ranking_predictions = event.details.predictions.get('ranking_predictions', None) ranking_prediction_stats = event.details.predictions.get('ranking_prediction_stats', None) cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches, event) matches = MatchHelper.organizeMatches(cleaned_matches) # If no matches but there are match predictions, create fake matches # For cases where FIRST doesn't allow posting of match schedule fake_matches = False if match_predictions and (not matches['qm'] and match_predictions['qual']): fake_matches = True for i in xrange(len(match_predictions['qual'].keys())): match_number = i + 1 alliances = { 'red': { 'score': -1, 'teams': ['frc?', 'frc?', 'frc?'] }, 'blue': { 'score': -1, 'teams': ['frc?', 'frc?', 'frc?'] } } matches['qm'].append(Match( id=Match.renderKeyName( event_key, 'qm', 1, match_number), event=event.key, year=event.year, set_number=1, match_number=match_number, comp_level='qm', alliances_json=json.dumps(alliances), )) # Add actual scores to predictions distribution_info = {} for comp_level in Match.COMP_LEVELS: level = 'qual' if comp_level == 'qm' else 'playoff' for match in matches[comp_level]: distribution_info[match.key.id()] = { 'level': level, 'red_actual_score': match.alliances['red']['score'], 'blue_actual_score': match.alliances['blue']['score'], 'red_mean': match_predictions[level][match.key.id()]['red']['score'], 'blue_mean': match_predictions[level][match.key.id()]['blue']['score'], 'red_var': match_predictions[level][match.key.id()]['red']['score_var'], 'blue_var': match_predictions[level][match.key.id()]['blue']['score_var'], } last_played_match_num = None if ranking_prediction_stats: last_played_match_key = ranking_prediction_stats.get('last_played_match', None) if last_played_match_key: last_played_match_num = last_played_match_key.split('_qm')[1] self.template_values.update({ "event": event, "matches": matches, "fake_matches": fake_matches, "match_predictions": match_predictions, "distribution_info_json": json.dumps(distribution_info), "match_prediction_stats": match_prediction_stats, "ranking_predictions": ranking_predictions, "ranking_prediction_stats": ranking_prediction_stats, "last_played_match_num": last_played_match_num, }) if event.within_a_day: self._cache_expiration = self.SHORT_CACHE_EXPIRATION return jinja2_engine.render('event_insights.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
def _render(self, event_key): event = Event.get_by_id(event_key) if not event or event.year != 2016: self.abort(404) event.get_matches_async() match_predictions = event.details.predictions.get('match_predictions', None) match_prediction_stats = event.details.predictions.get('match_prediction_stats', None) ranking_predictions = event.details.predictions.get('ranking_predictions', None) ranking_prediction_stats = event.details.predictions.get('ranking_prediction_stats', None) cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches) matches = MatchHelper.organizeMatches(cleaned_matches) # If no matches but there are match predictions, create fake matches # For cases where FIRST doesn't allow posting of match schedule fake_matches = False if not matches['qm'] and match_predictions: fake_matches = True for i in xrange(len(match_predictions.keys())): match_number = i + 1 alliances = { 'red': { 'score': -1, 'teams': ['frc?', 'frc?', 'frc?'] }, 'blue': { 'score': -1, 'teams': ['frc?', 'frc?', 'frc?'] } } matches['qm'].append(Match( id=Match.renderKeyName( event_key, 'qm', 1, match_number), event=event.key, year=event.year, set_number=1, match_number=match_number, comp_level='qm', alliances_json=json.dumps(alliances), )) last_played_match_num = None if ranking_prediction_stats: last_played_match_key = ranking_prediction_stats.get('last_played_match', None) if last_played_match_key: last_played_match_num = last_played_match_key.split('_qm')[1] self.template_values.update({ "event": event, "matches": matches, "fake_matches": fake_matches, "match_predictions": match_predictions, "match_prediction_stats": match_prediction_stats, "ranking_predictions": ranking_predictions, "ranking_prediction_stats": ranking_prediction_stats, "last_played_match_num": last_played_match_num, }) if event.within_a_day: self._cache_expiration = self.SHORT_CACHE_EXPIRATION return jinja2_engine.render('event_insights.html', self.template_values)
def parse(self, response): matches = response['MatchScores'] event_key = '{}{}'.format(self.year, self.event_short) event = Event.get_by_id(event_key) match_details_by_key = {} for match in matches: comp_level = PlayoffType.get_comp_level(event.playoff_type, match['matchLevel'], match['matchNumber']) set_number, match_number = PlayoffType.get_set_match_number( event.playoff_type, comp_level, match['matchNumber']) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] game_data = None if self.year == 2018: # Switches should be the same, but parse individually in case FIRST change things right_switch_red = match['switchRightNearColor'] == 'Red' scale_red = match['scaleNearColor'] == 'Red' left_switch_red = match['switchLeftNearColor'] == 'Red' game_data = '{}{}{}'.format( 'L' if right_switch_red else 'R', 'L' if scale_red else 'R', 'L' if left_switch_red else 'R', ) for alliance in match.get('alliances', match.get('Alliances', [])): color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][key] = value if game_data is not None: breakdown[color]['tba_gameData'] = game_data if self.year == 2019: # Derive incorrect completedRocketFar and completedRocketNear returns from FIRST API for side1 in ['Near', 'Far']: completedRocket = True for side2 in ['Left', 'Right']: for level in ['low', 'mid', 'top']: if breakdown[color]['{}{}Rocket{}'.format( level, side2, side1)] != 'PanelAndCargo': completedRocket = False break if not completedRocket: break breakdown[color]['completedRocket{}'.format( side1)] = completedRocket match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
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
def _render(self, event_key): event = Event.get_by_id(event_key) if not event or event.year < 2016 or not event.details.predictions: self.abort(404) event.get_matches_async() match_predictions = event.details.predictions.get('match_predictions', None) match_prediction_stats = event.details.predictions.get('match_prediction_stats', None) ranking_predictions = event.details.predictions.get('ranking_predictions', None) ranking_prediction_stats = event.details.predictions.get('ranking_prediction_stats', None) cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches) matches = MatchHelper.organizeMatches(cleaned_matches) # If no matches but there are match predictions, create fake matches # For cases where FIRST doesn't allow posting of match schedule fake_matches = False if not matches['qm'] and match_predictions['qual']: fake_matches = True for i in xrange(len(match_predictions.keys())): match_number = i + 1 alliances = { 'red': { 'score': -1, 'teams': ['frc?', 'frc?', 'frc?'] }, 'blue': { 'score': -1, 'teams': ['frc?', 'frc?', 'frc?'] } } matches['qm'].append(Match( id=Match.renderKeyName( event_key, 'qm', 1, match_number), event=event.key, year=event.year, set_number=1, match_number=match_number, comp_level='qm', alliances_json=json.dumps(alliances), )) # Add actual scores to predictions distribution_info = {} for comp_level in Match.COMP_LEVELS: level = 'qual' if comp_level == 'qm' else 'playoff' for match in matches[comp_level]: distribution_info[match.key.id()] = { 'level': level, 'red_actual_score': match.alliances['red']['score'], 'blue_actual_score': match.alliances['blue']['score'], 'red_mean': match_predictions[level][match.key.id()]['red']['score'], 'blue_mean': match_predictions[level][match.key.id()]['blue']['score'], 'red_var': match_predictions[level][match.key.id()]['red']['score_var'], 'blue_var': match_predictions[level][match.key.id()]['blue']['score_var'], } last_played_match_num = None if ranking_prediction_stats: last_played_match_key = ranking_prediction_stats.get('last_played_match', None) if last_played_match_key: last_played_match_num = last_played_match_key.split('_qm')[1] self.template_values.update({ "event": event, "matches": matches, "fake_matches": fake_matches, "match_predictions": match_predictions, "distribution_info_json": json.dumps(distribution_info), "match_prediction_stats": match_prediction_stats, "ranking_predictions": ranking_predictions, "ranking_prediction_stats": ranking_prediction_stats, "last_played_match_num": last_played_match_num, }) if event.within_a_day: self._cache_expiration = self.SHORT_CACHE_EXPIRATION return jinja2_engine.render('event_insights.html', self.template_values)
def step(self): event = Event.get_by_id('2016nytr') if self._step == 0: # Qual match schedule added for match in copy.deepcopy(self._all_matches['qm']): for alliance in ['red', 'blue']: match.alliances[alliance]['score'] = -1 match.alliances_json = json.dumps(match.alliances) match.score_breakdown_json = None match.actual_time = None MatchManipulator.createOrUpdate(match) self._step += 1 elif self._step == 1: # After each qual match MatchManipulator.createOrUpdate(self._played_matches['qm'][self._substep]) if self._substep < len(self._played_matches['qm']) - 1: self._substep += 1 else: self._step += 1 self._substep = 0 EventDetailsManipulator.createOrUpdate(EventDetails(id='2016nytr')) elif self._step == 2: # After alliance selections EventDetailsManipulator.createOrUpdate(EventDetails( id='2016nytr', alliance_selections=self._alliance_selections_without_backup )) self._step += 1 elif self._step == 3: # QF schedule added for match in copy.deepcopy(self._all_matches['qf']): for alliance in ['red', 'blue']: match.alliances[alliance]['score'] = -1 match.alliances_json = json.dumps(match.alliances) match.score_breakdown_json = None match.actual_time = None MatchManipulator.createOrUpdate(match) self._step += 1 elif self._step == 4: # After each QF match new_match = MatchHelper.play_order_sort_matches(self._played_matches['qf'])[self._substep] MatchManipulator.createOrUpdate(new_match) if not self._batch_advance: win_counts = { 'red': 0, 'blue': 0, } for i in xrange(new_match.match_number): win_counts[Match.get_by_id( Match.renderKeyName( new_match.event.id(), new_match.comp_level, new_match.set_number, i+1)).winning_alliance] += 1 for alliance, wins in win_counts.items(): if wins == 2: s = new_match.set_number if s in {1, 2}: self._advancement_alliances['sf1']['red' if s == 1 else 'blue'] = new_match.alliances[alliance]['teams'] elif s in {3, 4}: self._advancement_alliances['sf2']['red' if s == 3 else 'blue'] = new_match.alliances[alliance]['teams'] else: raise Exception("Invalid set number: {}".format(s)) for match_set, alliances in self._advancement_alliances.items(): if match_set.startswith('sf'): for i in xrange(3): for match in copy.deepcopy(self._all_matches['sf']): key = '2016nytr_{}m{}'.format(match_set, i+1) if match.key.id() == key: for color in ['red', 'blue']: match.alliances[color]['score'] = -1 match.alliances[color]['teams'] = alliances.get(color, []) match.alliances_json = json.dumps(match.alliances) match.score_breakdown_json = None match.actual_time = None MatchManipulator.createOrUpdate(match) if self._substep < len(self._played_matches['qf']) - 1: self._substep += 1 else: self._step += 1 if self._batch_advance else 2 self._substep = 0 elif self._step == 5: # SF schedule added if self._batch_advance: for match in copy.deepcopy(self._all_matches['sf']): for alliance in ['red', 'blue']: match.alliances[alliance]['score'] = -1 match.alliances_json = json.dumps(match.alliances) match.score_breakdown_json = None match.actual_time = None MatchManipulator.createOrUpdate(match) self._step += 1 elif self._step == 6: # After each SF match new_match = MatchHelper.play_order_sort_matches(self._played_matches['sf'])[self._substep] MatchManipulator.createOrUpdate(new_match) if not self._batch_advance: win_counts = { 'red': 0, 'blue': 0, } for i in xrange(new_match.match_number): win_counts[Match.get_by_id( Match.renderKeyName( new_match.event.id(), new_match.comp_level, new_match.set_number, i+1)).winning_alliance] += 1 for alliance, wins in win_counts.items(): if wins == 2: self._advancement_alliances['f1']['red' if new_match.set_number == 1 else 'blue'] = new_match.alliances[alliance]['teams'] for match_set, alliances in self._advancement_alliances.items(): if match_set.startswith('f'): for i in xrange(3): for match in copy.deepcopy(self._all_matches['f']): key = '2016nytr_{}m{}'.format(match_set, i+1) if match.key.id() == key: for color in ['red', 'blue']: match.alliances[color]['score'] = -1 match.alliances[color]['teams'] = alliances.get(color, []) match.alliances_json = json.dumps(match.alliances) match.score_breakdown_json = None match.actual_time = None MatchManipulator.createOrUpdate(match) # Backup robot introduced if self._substep == 3: EventDetailsManipulator.createOrUpdate(EventDetails( id='2016nytr', alliance_selections=self._event_details.alliance_selections )) if self._substep < len(self._played_matches['sf']) - 1: self._substep += 1 else: self._step += 1 if self._batch_advance else 2 self._substep = 0 elif self._step == 7: # F schedule added if self._batch_advance: for match in copy.deepcopy(self._all_matches['f']): for alliance in ['red', 'blue']: match.alliances[alliance]['score'] = -1 match.alliances_json = json.dumps(match.alliances) match.score_breakdown_json = None match.actual_time = None MatchManipulator.createOrUpdate(match) self._step += 1 elif self._step == 8: # After each F match MatchManipulator.createOrUpdate( MatchHelper.play_order_sort_matches( self._played_matches['f'])[self._substep]) if self._substep < len(self._played_matches['f']) - 1: self._substep += 1 else: self._step += 1 self._substep = 0 ndb.get_context().clear_cache() # Re fetch event matches event = Event.get_by_id('2016nytr') MatchHelper.deleteInvalidMatches(event.matches, event) ndb.get_context().clear_cache() self._update_rankings()