AtCoderACPercentage

自分と同じくらいのレートの人々の何%がその問題を解けているかを表示する。

当前为 2019-07-31 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name AtCoderACPercentage
  3. // @namespace https://github.com/null-null-programming
  4. // @version 0.2
  5. // @description 自分と同じくらいのレートの人々の何%がその問題を解けているかを表示する。
  6. // @author null_null
  7. // @license MIT
  8. // @include https://atcoder.jp/contests/*/standings*
  9. // @exclude https://atcoder.jp/contests/*/standings/json
  10. // @require https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
  11. // ==/UserScript==
  12.  
  13. (async function () {
  14. //参加者自身のRating
  15. const userRating = await getUserRating(userScreenName);
  16.  
  17. //問題名のリスト
  18. const problemNames = standings.TaskInfo.map(task => task.TaskScreenName);
  19. //問題名の記号(AとかBとか)配列 <-これを作っておかないとF1 F2 などが来たときにバグる
  20. const Assignment = standings.TaskInfo.map(task => task.Assignment);
  21.  
  22. let solvedPercentage;
  23.  
  24. updateData();
  25. updateView();
  26.  
  27. //ビューのupdate監視
  28. new MutationObserver(updateView).observe(
  29. document.getElementById("standings-tbody"),
  30. { childList: true }
  31. );
  32.  
  33. //リフレッシュボタンの監視(押されたとき/自動更新時に一瞬だけ無効化される)
  34. new MutationObserver(async mutationRecord => {
  35. const isDisabled = mutationRecord[0].target.classList.contains(
  36. "disabled"
  37. );
  38. if (isDisabled) {
  39. updateData();
  40. updateView();
  41. }
  42. })
  43. .observe(document.getElementById("refresh"), {
  44. attributes: true,
  45. attributeFilter: ["class"]
  46. });
  47.  
  48. function updateData(){
  49. //コンテスト情報を辞書型に直す userScreenName->Data
  50. const contestResultData = {};
  51. //参加回数が15回以上のコンテスト参加者のuserScreenNameリスト
  52. let contestUserName = [];
  53.  
  54. standings.StandingsData.forEach(res => {
  55. //辞書型に変換
  56. contestResultData[res.UserScreenName] = res;
  57.  
  58. //コンテスト参加回数10回未満、自分自身、未提出者は除いてリストに入れる
  59. if (res.Competitions >= 10 && res.UserScreenName !== userScreenName && res.TotalResult.Count > 0)
  60. contestUserName.push(res.UserScreenName);
  61. });
  62.  
  63. //TODO:評価関数の洗練
  64. //自身のレートとの絶対値の差が小さい順に並び替え。
  65. contestUserName.sort(function (x, y) {
  66. return Math.abs(userRating - contestResultData[x].Rating) - Math.abs(userRating - contestResultData[y].Rating);
  67. });
  68.  
  69. //TODO:選抜者人数の見直し
  70. //選抜者人数の10パーセントを選抜者人数とする。
  71. const USER_NUM = contestUserName.length * 0.1;
  72.  
  73. //自身のレートに近いUSER_NUM人の参加者を選抜
  74. contestUserName = contestUserName.slice(0, USER_NUM);
  75.  
  76. //何人が解けたかを問題ごとに集計
  77. solvedPercentage = problemNames.map(problemName => {
  78. let sum = 0;
  79.  
  80. //各ユーザーごとに集計
  81. contestUserName.forEach(userName => {
  82. if ((contestResultData[userName].TaskResults[problemName] || -1).Score > 0) sum++;
  83. });
  84.  
  85. //小数第1位までパーセントを表示
  86. return Math.round(sum * 10 * 100 / USER_NUM) / 10;
  87. });
  88. }
  89.  
  90. function initView(){
  91. //結果を表示するテーブルを作成する。
  92. //行を追加
  93. let table = document.getElementById('standings-tbody');
  94. let row = table.insertRow(-1);
  95.  
  96. row.id = 'ac-percentage-row';
  97.  
  98. //列を追加
  99. let cells = [];
  100.  
  101. for (let i = 0; i < problemNames.length + 1; i++) {
  102. cells[i] = row.insertCell(i);
  103.  
  104. if (i === 0) {
  105. //行の左端 題名を書き込む
  106. cells[i].innerText = 'AC Percentage';
  107. cells[i].style.color = '#00AA3E';
  108. cells[i].colSpan = '3';
  109. } else {
  110. cells[i].style.color = '#888888';
  111. }
  112. cells[i].style.fontSize = '80%';
  113. }
  114. }
  115.  
  116. function updateView(){
  117. //結果を表示するテーブルを作成する。
  118. //行を取得
  119. let row = document.getElementById('ac-percentage-row');
  120. if (!row) initView();
  121.  
  122. for (let i = 1; i < problemNames.length + 1; i++) {
  123. let cell = row.children[i];
  124. cell.innerText = Assignment[i - 1] + ':' + solvedPercentage[i - 1] + '%';
  125. }
  126. }
  127. })();
  128.  
  129. //参加しているコンテスト名を取得する。
  130. function getContestName() {
  131. let contestURL = location.href;
  132. let contestArray = contestURL.split('/');
  133. return contestArray[contestArray.length - 2];
  134. }
  135.  
  136. async function getUserRating(userScreenName) {
  137. let parser = new DOMParser();
  138. let archiveDom = parser.parseFromString((await $.get('https://atcoder.jp/users/' + userScreenName)), "text/html");
  139. let userRating = archiveDom.querySelector("#main-container > div.row > div.col-sm-9 > table > tbody > tr:nth-child(2) > td > span");
  140. return Number(userRating.innerText);
  141. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址