async def generate_vc_ranklist(self, contest_id, handle_to_member_id): handles = list(handle_to_member_id.keys()) contest, problems, standings = await cf.contest.standings(contest_id=contest_id, show_unofficial=True) # Exclude PRACTICE, MANAGER and OUR_OF_COMPETITION standings = [row for row in standings if row.party.participantType == 'CONTESTANT' or row.party.members[0].handle in handles] standings.sort(key=lambda row: row.rank) standings = [row._replace(rank=i + 1) for i, row in enumerate(standings)] now = time.time() rating_changes = await cf.contest.ratingChanges(contest_id=contest_id) current_official_rating = {rating_change.handle : rating_change.oldRating for rating_change in rating_changes} # TODO: assert that none of the given handles are in the official standings. handles = [row.party.members[0].handle for row in standings if row.party.members[0].handle in handles and row.party.participantType == 'VIRTUAL'] current_vc_rating = {handle: cf_common.user_db.get_vc_rating(handle_to_member_id.get(handle)) for handle in handles} ranklist = Ranklist(contest, problems, standings, now, is_rated=True) delta_by_handle = {} for handle in handles: mixed_ratings = current_official_rating.copy() mixed_ratings[handle] = current_vc_rating.get(handle) ranklist.predict(mixed_ratings) delta_by_handle[handle] = ranklist.delta_by_handle.get(handle, 0) ranklist.delta_by_handle = delta_by_handle return ranklist
async def generate_ranklist(self, contest_id, *, fetch_changes=False, predict_changes=False): assert fetch_changes ^ predict_changes contest, problems, standings = await cf.contest.standings(contest_id=contest_id, show_unofficial=True) now = time.time() # Exclude PRACTICE and MANAGER standings = [row for row in standings if row.party.participantType in ('CONTESTANT', 'OUT_OF_COMPETITION', 'VIRTUAL')] if fetch_changes: # Fetch final rating changes from CF. # For older contests. is_rated = False try: changes = await cf.contest.ratingChanges(contest_id=contest_id) # For contests intended to be rated but declared unrated, an empty list is returned. is_rated = len(changes) > 0 except cf.RatingChangesUnavailableError: pass ranklist = Ranklist(contest, problems, standings, now, is_rated=is_rated) if is_rated: delta_by_handle = {change.handle: change.newRating - change.oldRating for change in changes} ranklist.set_deltas(delta_by_handle) elif predict_changes: # Rating changes have not been applied yet, predict rating changes. # For running/recent contests. _, _, standings_official = await cf.contest.standings(contest_id=contest_id) has_teams = any(row.party.teamId is not None for row in standings_official) if cf_common.is_nonstandard_contest(contest) or has_teams: # The contest is not rated ranklist = Ranklist(contest, problems, standings, now, is_rated=False) else: current_rating = await CacheSystem.getUsersEffectiveRating(activeOnly=False) current_rating = {row.party.members[0].handle: current_rating.get(row.party.members[0].handle, 1500) for row in standings_official} if 'Educational' in contest.name: # For some reason educational contests return all contestants in ranklist even # when unofficial contestants are not requested. current_rating = {handle: rating for handle, rating in current_rating.items() if rating < 2100} ranklist = Ranklist(contest, problems, standings, now, is_rated=True) ranklist.predict(current_rating) return ranklist