Greasy Fork is available in English.

AtCoderDifficultyDisplay

display a difficulty of AtCoder Problems.

Od 05.05.2020.. Pogledajte najnovija verzija.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

  1. // ==UserScript==
  2. // @name AtCoderDifficultyDisplay
  3. // @namespace https://github.com/hotarunx
  4. // @version 0.3
  5. // @description display a difficulty of AtCoder Problems.
  6. // @description:ja AtCoder ProblemsのDifficultyを表示します。
  7. // @author hotarunx
  8. // @match https://atcoder.jp/contests/*/tasks/*
  9. // @grant none
  10. // @connect https://kenkoooo.com/atcoder/resources/*
  11. // @connect https://kenkoooo.com/atcoder/atcoder-api/*
  12. // @license MIT
  13. //
  14. // Copyright(c) 2020 hotarunx
  15. // This software is released under the MIT License, see LICENSE or https://github.com/hotarunx/AtCoderMyExtensions/blob/master/LICENSE.
  16. //
  17. // ==/UserScript==
  18.  
  19. (function () {
  20.  
  21. // -------------------------------------------------------------------------
  22. // 次の変数の値を書き換えることで各数値を表示するかどうかを変更できます
  23.  
  24. // Difficultyを表示するかどうか
  25. const displayDifficulty = true;
  26.  
  27. // 提出状況を表示するかどうか
  28. const displaySubmissionStatus = true;
  29.  
  30. // true: 表示する
  31. // false: 表示しない
  32. // -------------------------------------------------------------------------
  33.  
  34. // URL of Estimated difficulties of the problems
  35. const CONTESTS_INFORMATION = "https://kenkoooo.com/atcoder/resources/contests.json";
  36. const SUBMISSION_API = "https://kenkoooo.com/atcoder/atcoder-api/results?user=" + userScreenName;
  37. const SUBMISSIONS_DATASET = "https://kenkoooo.com/atcoder/resources/problem-models.json";
  38.  
  39. if (displayDifficulty)
  40. fetch(SUBMISSIONS_DATASET)
  41. .then((response) => response.json())
  42. .then((jsonData) => {
  43. addDifficultyText(jsonData);
  44. });
  45.  
  46. if (displaySubmissionStatus && userScreenName != "")
  47. fetch(CONTESTS_INFORMATION)
  48. .then((response) => response.json())
  49. .then((contestsData) => {
  50.  
  51. fetch(SUBMISSION_API)
  52. .then((response) => response.json())
  53. .then((submissionData) => {
  54.  
  55. addSubmissionStatusText(contestsData, submissionData);
  56. });
  57. });
  58.  
  59.  
  60. })();
  61.  
  62. function getElementOfProblemStatus() {
  63. let element_status;
  64.  
  65. const main_container = document.getElementById('main-container');
  66. const elements_p = main_container.getElementsByTagName("p");
  67.  
  68. for (let i = 0; i < elements_p.length; i++) {
  69. const element = elements_p[i];
  70. if (element.textContent.match("メモリ制限:") || element.textContent.match("Memory Limit:")) {
  71. element_status = element;
  72. break
  73. }
  74. }
  75.  
  76. return element_status;
  77. }
  78.  
  79. // return rating color
  80. function colorRating(rating) {
  81. let color = '#FFFFFF'; // white
  82. if /**/ (rating < 0400) color = '#808080'; // gray
  83. else if (rating < 0800) color = '#804000'; // brown
  84. else if (rating < 1200) color = '#008000'; // green
  85. else if (rating < 1600) color = '#00C0C0'; // cyan
  86. else if (rating < 2000) color = '#0000FF'; // blue
  87. else if (rating < 2400) color = '#C0C000'; // yellow
  88. else if (rating < 2800) color = '#FF8000'; // orange
  89. else if (rating < 3200) color = '#FF0000'; // red
  90. else if (rating < 3600) color = '#E4E4E4'; // silver
  91. else /* */ color = '#FFD325'; // gold
  92.  
  93. return color;
  94. }
  95.  
  96. // correct rating under 400
  97. // see https://qiita.com/anqooqie/items/92005e337a0d2569bdbd#%E6%80%A7%E8%B3%AA4-%E5%88%9D%E5%BF%83%E8%80%85%E3%81%B8%E3%81%AE%E6%85%88%E6%82%B2
  98. function correctLowerRating(rating) {
  99. if (rating >= 400) return rating;
  100.  
  101. do {
  102. rating = 400 / Math.exp((400 - rating) / 400);
  103.  
  104. } while (rating < 0);
  105.  
  106. return rating;
  107. }
  108.  
  109. function generateDifficultyText(difficulty, is_experimental) {
  110. let text = " / ";
  111.  
  112. difficulty = correctLowerRating(difficulty)
  113.  
  114. // add difficulty value
  115. let colored_text = "Difficulty: ";
  116. if (is_experimental) colored_text += "🧪";
  117. colored_text += difficulty.toFixed();
  118.  
  119. // color difficulty value
  120. const color = colorRating(difficulty);
  121.  
  122. text += "<span style='color: " + color + ";'>" + colored_text + "</span>";
  123.  
  124. return text;
  125. }
  126.  
  127. function addDifficultyText(jsonData) {
  128. let text = "";
  129.  
  130. // get id
  131. const path = location.pathname.split("/");
  132. const id = path[path.length - 1];
  133.  
  134. // get Element of Problem Status
  135. let status = getElementOfProblemStatus();
  136.  
  137. const problem = jsonData[id];
  138. // if problem exist in json
  139. if (problem != null && problem.difficulty != null) {
  140. text += generateDifficultyText(problem.difficulty, problem.is_experimental);
  141. }
  142.  
  143. status.insertAdjacentHTML('beforeend', text);
  144. }
  145.  
  146. function addSubmissionStatusText(contestsData, submissionData) {
  147. let text = "";
  148.  
  149. // get (start,end)time from contests info API
  150. const contest = contestsData.filter(function (item, index) { if (item.id == contestScreenName) return true; })[0];
  151. const start = contest["start_epoch_second"];
  152. const duration = contest["duration_second"];
  153. const end = start + duration;
  154.  
  155. const path = location.pathname.split("/");
  156. const id = path[path.length - 1];
  157.  
  158. // get Element of Problem Status
  159. let status = getElementOfProblemStatus();
  160.  
  161. // submission status
  162. let contest_accepted = false, accepted = false, contest_submitted = false, submitted = false;
  163.  
  164. // search all submissions to this problem
  165. const submissions = submissionData.filter(function (item, index) { if (item.problem_id == id) return true; });
  166. for (const item of submissions) {
  167. const time = item["epoch_second"];
  168.  
  169. // update submission status
  170.  
  171. if (start <= time && time <= end) {
  172. contest_submitted = true;
  173. } else {
  174. submitted = true;
  175. }
  176. if (item["result"] == "AC") {
  177. accepted = true;
  178. }
  179. if ((start <= time && time <= end) && item["result"] == "AC") {
  180. contest_accepted = true;
  181. }
  182.  
  183. }
  184.  
  185. // generate text following submission status
  186. text += " / "
  187.  
  188. if (contest_accepted) text += "<span style='color: #5CB85C;'>★Accepted</span>";
  189. else if (accepted) text += "<span style='color: #5CB85C;'>Accepted</span>";
  190. else if (submitted) text += "<span style='color: #F0AD4E;'>Trying</span>";
  191. else if (contest_submitted) text += "<span style='color: #F0AD4E;'>★Trying</span>";
  192. else text += "Trying";
  193.  
  194. status.insertAdjacentHTML('beforeend', text);
  195. }