Greasy Fork is available in English.

AtCoderDifficultyDisplay

display a difficulty of AtCoder Problems.

2020-06-06 기준 버전입니다. 최신 버전을 확인하세요.

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