AtCoderACPercentage

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

Versión del día 31/07/2019. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         AtCoderACPercentage
// @namespace    https://github.com/null-null-programming
// @version      0.3
// @description  自分と同じくらいのレートの人々の何%がその問題を解けているかを表示する。
// @author       null_null
// @license      MIT
// @match        https://atcoder.jp/contests/*/standings*
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
// ==/UserScript==

(async function () {
    //jsonのときは何もしない
    if (window.location.href.endsWith("json")) return;
    //参加者自身のusername
    const userScreenName = getUserScreenName();
    //参加者自身のRating
    const userRating = await getUserRating(userScreenName);
    //コンテスト情報
    const contestData = await getContestStandingsData();

    //問題名のリスト
    const problemNames = contestData.TaskInfo.map(task => task.TaskScreenName);
    //問題名の記号(AとかBとか)配列 <-これを作っておかないとF1 F2 などが来たときにバグる
    const Assignment = contestData.TaskInfo.map(task => task.Assignment);


    //コンテスト情報を辞書型に直す userScreenName->Data
    const contestResultData = {};
    //参加回数が15回以上のコンテスト参加者のuserScreenNameリスト
    let contestUserName = [];

    contestData.StandingsData.forEach(res => {
        //辞書型に変換
        contestResultData[res.UserScreenName] = res;

        //コンテスト参加回数10回未満、自分自身、未提出者は除いてリストに入れる
        if (res.Competitions >= 10 && res.UserScreenName !== userScreenName && res.TotalResult.Count > 0)
            contestUserName.push(res.UserScreenName);
    });

    //TODO:評価関数の洗練
    //自身のレートとの絶対値の差が小さい順に並び替え。
    contestUserName.sort(function (x, y) {
        return Math.abs(userRating - contestResultData[x].Rating) - Math.abs(userRating - contestResultData[y].Rating);
    });

    //TODO:選抜者人数の見直し
    //選抜者人数の10パーセントを選抜者人数とする。
    const USER_NAM = contestUserName.length * 0.1;

    //自身のレートに近いUSER_NAM人の参加者を選抜
    contestUserName = contestUserName.slice(0, USER_NAM);

    //何人が解けたかを問題ごとに集計
    let solvedPercentage = problemNames.map(problemName => {
        let sum = 0;

        //各ユーザーごとに集計
        contestUserName.forEach(userName => {
            if ((contestResultData[userName].TaskResults[problemName] || -1).Score > 0) sum++;
        });

        //小数第1位までパーセントを表示
        return Math.round(sum * 10 * 100 / USER_NAM) / 10;
    });

    //結果を表示するテーブルを作成する。

    //行を追加
    let table = document.getElementById('standings-tbody');
    let row = table.insertRow(-1);

    //列を追加
    let cells = [];

    for (let i = 0; i < problemNames.length + 1; i++) {
        cells[i] = row.insertCell(i);

        if (i === 0) {
            //行の左端  題名を書き込む
            cells[i].innerText = 'AC Percentage';
            cells[i].style.color = '#00AA3E';
            cells[i].colSpan = '3';
        } else {
            //問題欄  計算結果と問題名アルファベットを書き込む
            cells[i].innerText = Assignment[i - 1] + ':' + solvedPercentage[i - 1] + '%';
            cells[i].style.color = '#888888';
        }
        cells[i].style.fontSize = '80%';
    }


})();


//参加しているコンテスト名を取得する。
function getContestName() {
    let contestURL = location.href;
    let contestArray = contestURL.split('/');
    return contestArray[contestArray.length - 2];
}

//コンテストデータを取得する。
async function getContestStandingsData() {
    return await $.ajax(`https://atcoder.jp${window.location.pathname}/json`);
}

//参加者自身のusernameを取得する。
function getUserScreenName() {
    let userScreenName = document.querySelector("#navbar-collapse > ul.nav.navbar-nav.navbar-right > li:nth-child(2) > a").textContent.split(' ');
    return userScreenName[1];
}

async function getUserRating(userScreenName) {
    let parser = new DOMParser();
    let archiveDom = parser.parseFromString((await $.get('https://atcoder.jp/users/' + userScreenName)), "text/html");
    let userRating = archiveDom.querySelector("#main-container > div.row > div.col-sm-9 > table > tbody > tr:nth-child(2) > td > span");
    return Number(userRating.innerText);
}