AtCoder Heuristic Contestのレーティング予測計算機を作った
作ったもの
競技プログラミングサイトAtCoderのコンテストの一種であるAtCoder Heuristic Contestのレーティング予測計算機を作りました。
過去のコンテストの出場記録を元に、次回のコンテストでどれくらいのパフォーマンスを得るとどれくらいのレーティングに到達できるかをグラフで確認することができます。
(よろしければstarを頂けると幸いです)
動機
- Algorithmコンテストのレーティング予測計算サイトは複数存在しているが、Heuristicコンテストのものは自分が探した限りなかったので
- Svelteのお勉強で何か役に立つものを作りたかった
技術
Svelte
フロントエンドではSvelteというフレームワークを使用しました。
Svelteは公式Blog曰く、ReactやVueに比べて簡潔にコードが書け、パフォーマンスが優れている点が大きな特徴です。環境構築が簡単でTypeScriptにも対応しており、Svelteは初めてフロントエンド開発をやる方にはおすすめだと思います。
公式のサンプルコードを見てもらえればわかる通り、HTML, CSS, JavaScript (TypeScript)を合体させたような書き方をします。
Svelteの環境構築とデプロイについては以下のScrapsをご覧ください。
Rating計算
公式ドキュメントの通りに実装しました。
まず
このとき
そして補正後のRatingである
Chart.js
グラフ描画にはChart.jsを使用しました。綺麗なアニメーション付きのグラフを簡単に表示することができます。Chart.jsではグラフに背景を入れることができないため、背景のRatingの色はcanvasを直接操作して描画しました。
const drawBackground = (target) => {
const xScale = target.scales["x-axis-0"]
const yScale = target.scales["y-axis-0"]
for (const rate of [...Array(10).keys()].map((i) => {
return i * 400
})) {
chartCanvas.getContext("2d").fillStyle = `rgba(${colorRating(rate).join(
", "
)}, 0.2)`
chartCanvas
.getContext("2d")
.fillRect(
xScale.left,
Math.min(yScale.getPixelForValue(rate + 400), yScale.bottom),
xScale.width,
Math.min(yScale.getPixelForValue(rate), yScale.bottom) -
Math.min(yScale.getPixelForValue(rate + 400), yScale.bottom)
)
chartCanvas.getContext("2d").fillStyle = `rgba(${colorRating(rate).join(
", "
)}, 0.5)`
chartCanvas
.getContext("2d")
.fillRect(
xScale.getPixelForValue(rate),
yScale.bottom,
Math.min(xScale.getPixelForValue(rate + 400), xScale.right) -
Math.min(xScale.getPixelForValue(rate), xScale.right),
5
)
}
}
Google Apps Script
レーティング予測計算機として使えるものはとりあえず完成したのですが、このままでは過去全てのパフォーマンスを手入力する必要があり面倒なため、指定したアカウントの過去全てのコンテストの記録をAtCoderから取得できるようにしたいです。しかしフロントエンドだけではCORSエラーで不可能なため、Google Apps ScriptでAtCoderのWeb APIを叩くための自分用Web APIを作り、これを経由させてコンテストの記録を取得することにしました。
TypeScriptとVS Codeで開発したかったのでClaspというGoogle製のCLIツールを使用しました。
環境構築とデプロイについては以下のScrapsをご覧ください。
AtCoderにはUrlFetchApp.fetch
でGETリクエストを投げます。GETのパラメーターを綺麗に埋め込む方法が無さそうなため、テンプレートリテラルでAtCoderのURLに直接記述しています。返ってきたテキストはJSON.parse
でJavaScriptオブジェクトに変換します。
GASで返すデータはContentService.createTextOutput
でGoogleAppsScript.Content.TextOutput
オブジェクトを作成し、setContent
で返すデータをセットします。今回はAtCoderで受け取ったものをそのまま返すことにしました。
const doGet = (e) => {
const url: string = `https://atcoder.jp/users/${e.parameter.id}/history/json?contestType=${e.parameter.type}`
const params: GoogleAppsScript.URL_Fetch.URLFetchRequestOptions = {
"method": "get",
"headers": {}
}
const response = JSON.parse(UrlFetchApp.fetch(url, params).getContentText())
const output: GoogleAppsScript.Content.TextOutput = ContentService.createTextOutput()
output.setMimeType(ContentService.MimeType.JSON)
output.setContent(JSON.stringify(response))
return output
}
おわりに
Svelteの簡潔な文法やサンプルコードのページがわかりやすいこともあり簡単にフロントエンド開発を行うことができました。またGoogle Apps ScriptをTypeScriptで書いて簡易Web APIサーバーを立てることができました。この記事がどなたかの参考になれば幸いです。
Discussion