From a5cc369a6602808ac806e6fd71025c1d81f4bae8 Mon Sep 17 00:00:00 2001 From: conlacda Date: Sun, 1 Sep 2024 23:12:45 +0900 Subject: [PATCH] update: improve accuracy for the current user Fix the bug that occurs when the current user is rated but there is no data on the server --- .../algo_predicted_standing_table.js | 4 ++-- .../scripts/rating-estimator/contest.js | 8 +++---- .../heuristic_predicted_standing_table.js | 4 ++-- .../scripts/rating-estimator/main.js | 21 ++++++++++++++++++- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/browser-extension/chrome-extension/scripts/rating-estimator/algo_predicted_standing_table.js b/browser-extension/chrome-extension/scripts/rating-estimator/algo_predicted_standing_table.js index 97023d3..fadaa4c 100644 --- a/browser-extension/chrome-extension/scripts/rating-estimator/algo_predicted_standing_table.js +++ b/browser-extension/chrome-extension/scripts/rating-estimator/algo_predicted_standing_table.js @@ -34,7 +34,7 @@ class AlgoPredictedStandingTable extends StandingTable { const rank = standingsData[i].RatedRank; // rank has not been rounded const upPerformance = this.rank2Perf[Math.floor(rank) - 1] ?? 0; // prevents out of bound error when new users joined after the last generated time const downPerformance = this.rank2Perf[Math.ceil(rank) - 1] ?? 0; - const perfInContest = positivize(Math.floor((upPerformance + downPerformance) / 2)); + const perfInContest = Math.floor((upPerformance + downPerformance) / 2); const competitionNum = standingsData[i].Competitions; let newRating = oldRating; if (isRated && !isDeleted) { @@ -47,7 +47,7 @@ class AlgoPredictedStandingTable extends StandingTable { } this.perfRatingData.set(userScreenName, { - performance: perfInContest, + performance: positivize(perfInContest), userScreenName: userScreenName, oldRating: oldRating, newRating: newRating, diff --git a/browser-extension/chrome-extension/scripts/rating-estimator/contest.js b/browser-extension/chrome-extension/scripts/rating-estimator/contest.js index 258b15c..d1965d3 100644 --- a/browser-extension/chrome-extension/scripts/rating-estimator/contest.js +++ b/browser-extension/chrome-extension/scripts/rating-estimator/contest.js @@ -86,9 +86,9 @@ class Contest { * If need to cache, cache for algo contests only, do not cache for heuristic contests * because the number of participants is not fixed until the contest ends. */ - async fetchPredictedPerfArr(needTocache = false) { + async fetchPredictedPerfArr(needToCache = false) { const resourceUrl = `https://raw.githubusercontent.com/conlacda/ac-perf-data/main/data/${this.contestName}_ranking_to_perf.json`; - const option = (needTocache) ? {} : { cache: "no-store" }; // headers: { 'Cache-Control': 'max-age=120' } + const option = (needToCache) ? {} : { cache: "no-store" }; // headers: { 'Cache-Control': 'max-age=120' } let res = await fetchWithRetry(resourceUrl, option); if (res.status !== 200) return []; @@ -100,9 +100,9 @@ class Contest { /** * Fetch the rounded performance history of all participants before contest ~ the data of a contest with 10k users is about 5MB. */ - async fetchRoundedPerfHistory(needTocache = false) { + async fetchRoundedPerfHistory(needToCache = false) { const resourceUrl = `https://raw.githubusercontent.com/conlacda/ac-perf-data/main/data/${this.contestName}_rounded_perf_history.json`; - const option = (needTocache) ? {} : { cache: "no-store" }; // headers: { 'Cache-Control': 'max-age=120' } + const option = (needToCache) ? {} : { cache: "no-store" }; // headers: { 'Cache-Control': 'max-age=120' } let res = await fetchWithRetry(resourceUrl, option); if (res.status !== 200) return []; diff --git a/browser-extension/chrome-extension/scripts/rating-estimator/heuristic_predicted_standing_table.js b/browser-extension/chrome-extension/scripts/rating-estimator/heuristic_predicted_standing_table.js index 6325dc3..b56bf40 100644 --- a/browser-extension/chrome-extension/scripts/rating-estimator/heuristic_predicted_standing_table.js +++ b/browser-extension/chrome-extension/scripts/rating-estimator/heuristic_predicted_standing_table.js @@ -29,7 +29,7 @@ class HeuristicPredictedStandingTable extends StandingTable { const rank = this.standings.StandingsData[i].RatedRank; // rank has not been rounded const upPerformance = this.rank2Perf[Math.floor(rank) - 1] ?? 0; // prevents out of bound error when new users joined after the last generated time const downPerformance = this.rank2Perf[Math.ceil(rank) - 1] ?? 0; - const perfInContest = positivize(Math.floor((upPerformance + downPerformance) / 2)); + const perfInContest = Math.floor((upPerformance + downPerformance) / 2); let newRating = oldRating; if (isRated && !isDeleted) { // Prefer calculating based on the performance history to calculate based on last performance @@ -38,7 +38,7 @@ class HeuristicPredictedStandingTable extends StandingTable { } this.perfRatingData.set(userScreenName, { - performance: perfInContest, + performance: positivize(perfInContest), userScreenName: userScreenName, oldRating: oldRating, newRating: newRating, diff --git a/browser-extension/chrome-extension/scripts/rating-estimator/main.js b/browser-extension/chrome-extension/scripts/rating-estimator/main.js index 85029ae..89c7658 100644 --- a/browser-extension/chrome-extension/scripts/rating-estimator/main.js +++ b/browser-extension/chrome-extension/scripts/rating-estimator/main.js @@ -53,6 +53,21 @@ const getUserSettings = () => { return JSON.parse(meta.content); } +const joinedAsRatedUser = (standings, userScreenName) => { + for (let i = 0; i < standings.StandingsData.length; i++) { + if (standings.StandingsData[i].UserScreenName === userScreenName && standings.StandingsData[i].IsRated) { + return true; + } + } + return false; +} + +const getPerfHistory = async (userScreenName, contest_type) => { + const res = await fetchWithRetry(`https://atcoder.jp/users/${userScreenName}/history/json?contestType=${contest_type}`); + const userPerfHistory = await res.json(); + return userPerfHistory.filter(item => item.IsRated).map(item => item.Performance); +} + const USER_SETTINGS = { PREDICT: { ALWAYS: 0, @@ -93,7 +108,7 @@ const USER_SETTINGS = { */ if (fixedResult.length > 0) { const standings = (typeof vueStandings !== 'undefined' && vueStandings.hasOwnProperty('standings')) ? vueStandings.standings : (await contest.fetchStandingFromAtcoder()); - const rank2Perf = await contest.fetchPredictedPerfArr(needTocache = true); + const rank2Perf = await contest.fetchPredictedPerfArr(needToCache = true); new FixedStandingTable(standings, fixedResult, rank2Perf); } else { if (userSettings.prediction === USER_SETTINGS.PREDICT.PAST_CONTESTS_ONLY) @@ -107,6 +122,10 @@ const USER_SETTINGS = { const standings = (typeof vueStandings !== 'undefined' && vueStandings.hasOwnProperty('standings')) ? vueStandings.standings : (await contest.fetchStandingFromAtcoder()); const contest_type = await contest.getContestType(); const roundedPerfHistories = await contest.fetchRoundedPerfHistory(); + // userScreenName is the currently logged-in user and defined on Atcoder + if (joinedAsRatedUser(standings, userScreenName) && !(userScreenName in roundedPerfHistories)) { + roundedPerfHistories[userScreenName] = await getPerfHistory(userScreenName, contest_type); + } if (contest_type === 'algo') { new AlgoPredictedStandingTable(roundedPerfHistories, rank2Perf, standings); } else if (contest_type === 'heuristic') {