AtCoder Problemsの過去問を解いたグラフに時間の要素も追加したものをPythonで作る
前置き
大分久しぶりですね(そもそも多分1記事目を読んだ方があまりいない)。しかもこれが2記事目です。今これを書いている時には2018年最後のAtCoderのコンテストであるAtCoder Grand Contest 030が行われているわけですが私は直前までTwitter上で素振りしまくっていたにも関わらず始まって1分少しで事情ができ、✝no sub✝を決め込むことになったので今これを書いています(つらいですね)。
さて、突然ですがAtCoderユーザーの皆さんの9割9分がご存じであろうAtCoder Problemsというページがあります。超簡単に書くとAtCoderでの過去問に簡単にアクセスでき、提出履歴等も見れる優れものです。
その中に、自分のAC数の増加の軌跡が見られるグラフがあります。
これ、AC数の変動が分かって便利ですよね。しかし私としては「人と比較して見てみたい!」という欲求が強かったりします。まあProblemsは個人毎のページだから仕方ないんですけどね。なので入力された人(実装のところで詳しく説明)に対し、
・各個人のACした数(縦軸)の累積を日にち(横軸)にプロットする(Problemsのグラフ)
に加えて、
・その時系列は入力された人全員と共有し、表示する
ものをPython(3.6.6)で作ってみました。
実装
先にコードのリンクだけ置いておきます。
さて、このACs.pyを上の行から(主要な所だけ、コード中のコメントも参考にしてください)見て行きましょう(行の情報は執筆当時の情報なので変わるかもしれません)。
1~12行目:importしているだけです。グラフの表示にはmatplotlibを使用しました。
15行目:今回グラフを表示するユーザーを入力させています。スペース区切りで1人を区別できるように.split()がついています。
36行目~110行目までまとめて:1番外のfor文で入力された先頭のユーザーから見て行くため、諸々の変数、リスト等の初期化をしています。さらに対象となるユーザーの提出履歴(AtCoder ProblemsのAPI)をJSON形式で開いています(49・50行目)。
次に、51行目ではラムダ式を用いることでJSON形式のデータをresult(AC,WA,TLEとか)とepoch_second(提出された日時。説明はUNIX時間 - Wikipediaを見てください)。本来なら提出履歴をソートすることでO(NlogN)かかり、愚直に見るO(N)よりも効率が悪いことになりますが、後で説明する重複ACを排除する段階においてこちらの方が効率が良くなるため、ここでソートしています。
さらにresultでソートしておくと、結果のステータスでACが1番前に来るためこのソートをすると1番前には「ACの提出であり、提出された時間が早い」順に提出履歴が並ぶことになります。その為、その後で行っている処理で、forで提出履歴を順に見て行く際に、resultがACでないものが出てきたら、その後にACの提出が無いことになるので、その場でループを抜けることができます(63・64行目)。
次に、67~71行目で重複AC(同じ問題で複数回正解するやつ、グラフには1番早いACの記録を用いる)を弾いています。今までに見てあげた提出(contestsとproblems(43・45行目で宣言)に入っている)と比べてあげてコンテスト名及び問題名(ABCDのやつ)が同じならbreakFlagをTrueにすることによってその後の処理をスキップして(77~102行目)最後の処理に進ませることができます。
76行目~102行目は重複ACではない提出が進む処理です。このことからこの提出はグラフにプロットしなければいけない提出とわかります。
90行目~102行目では1つ前のACと同じ日にACしたかを判定しています。
そして、107行目でグラフに情報をプロットし、108行目で今まで見ていたユーザーの名前を削除し、次の人を見て行きます。
最後の数行:ではグラフの細かい設定を行っています。具体的には横軸と縦軸のラベル、縦軸の1番AC数が多い人のAC数での頭打ち、横軸の時刻表示を見やすくすためにいい感じに回転、最後にグラフの出力をしています。
結果
2つほど載っけます。
最後に(課題も)
結構後の方まで重複ACの存在を忘れていて丘People!?(分かる人は分かる)となっていたりしました。まあ無事に書けたので良かったです。
課題としては、縦軸は頭打ちできましたが横軸がうまい感じに頭打ちされないというのがあります。
超長文で最悪ですがここまで見てくださったようで何よりです。ありがとうございます。
では。