From 4e85ea8cc24bf75ee4a0174bcd1e7ffa50d43602 Mon Sep 17 00:00:00 2001 From: Null Chilly <56817415+nullchilly@users.noreply.github.com> Date: Thu, 11 Apr 2024 23:07:48 +0700 Subject: [PATCH] Improve performance estimates for finished contests (#53) ...by considering that users with pre-contest rating 0 are in fact unrated. Only applies to contests after the introduction of fake ratings. --- carrot/src/background/background.js | 3 +- .../src/background/cache/contests-complete.js | 29 +++++++++++++++++-- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/carrot/src/background/background.js b/carrot/src/background/background.js index d5389fa..43d9a70 100644 --- a/carrot/src/background/background.js +++ b/carrot/src/background/background.js @@ -114,7 +114,8 @@ function predictForRows(rows, ratingBeforeContest) { function getFinal(contest) { // Calculate and save the performances on the contest object if not already saved. if (contest.performances === null) { - const ratingBeforeContest = new Map(contest.ratingChanges.map((c) => [c.handle, c.oldRating])); + const ratingBeforeContest = new Map( + contest.ratingChanges.map((c) => [c.handle, contest.oldRatings.get(c.handle)])); const rows = contest.rows.filter((row) => { const handle = row.party.members[0].handle; return ratingBeforeContest.has(handle); diff --git a/carrot/src/background/cache/contests-complete.js b/carrot/src/background/cache/contests-complete.js index 30ba6cc..d984425 100644 --- a/carrot/src/background/cache/contests-complete.js +++ b/carrot/src/background/cache/contests-complete.js @@ -2,11 +2,12 @@ * Wrapper for all useful contest data. */ export class Contest { - constructor(contest, problems, rows, ratingChanges, fetchTime, isRated) { + constructor(contest, problems, rows, ratingChanges, oldRatings, fetchTime, isRated) { this.contest = contest; this.problems = problems; this.rows = rows; this.ratingChanges = ratingChanges; // undefined if isRated is not YES + this.oldRatings = oldRatings; // undefined if isRated is not YES this.fetchTime = fetchTime; this.isRated = isRated; this.performances = null; // To be populated by someone who calculates the performances. @@ -57,6 +58,7 @@ export class ContestsComplete { const { contest, problems, rows } = await this.api.contest.standings(contestId); let ratingChanges; + let oldRatings; let isRated = Contest.IsRated.LIKELY; if (contest.phase === 'FINISHED') { try { @@ -64,6 +66,7 @@ export class ContestsComplete { if (ratingChanges) { if (ratingChanges.length > 0) { isRated = Contest.IsRated.YES; + oldRatings = adjustOldRatings(contestId, ratingChanges); } else { ratingChanges = undefined; // Reset to undefined if it was an empty array } @@ -79,7 +82,7 @@ export class ContestsComplete { } const isFinished = isRated === Contest.IsRated.NO || isRated === Contest.IsRated.YES; - const c = new Contest(contest, problems, rows, ratingChanges, Date.now(), isRated); + const c = new Contest(contest, problems, rows, ratingChanges, oldRatings, Date.now(), isRated); // If the contest is finished, the contest data doesn't change so cache it. // The exception is during new year's magic, when people change handles and handles on the @@ -104,3 +107,25 @@ export class ContestsComplete { return c; } } + +const FAKE_RATINGS_SINCE_CONTEST = 1360; +const NEW_DEFAULT_RATING = 1400; + +function adjustOldRatings(contestId, ratingChanges) { + const oldRatings = new Map(); + if (contestId < FAKE_RATINGS_SINCE_CONTEST) { + for (const change of ratingChanges) { + oldRatings.set(change.handle, change.oldRating); + } + } else { + for (const change of ratingChanges) { + oldRatings.set(change.handle, change.oldRating == 0 ? NEW_DEFAULT_RATING : change.oldRating); + } + // Note: This a band-aid for CF's fake ratings (see Github #18). + // If CF tells us that a user had rating 0, we consider that the user is in fact unrated. + // This unfortunately means that a user who truly has rating 0 will be considered to have + // DEFAULT_RATING, but such cases are unlikely compared to the regular presence of unrated + // users. + } + return oldRatings; +}