AtCoderACPercentage

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

As of 2019-07-30. See the latest version.

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