0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【AtCoder】atcoder-tools + ファイルオープン + 問題オープン 自動化スクリプト

Last updated at Posted at 2024-09-01

概要

atcoder-tools はAtCoderのコンテストのディレクトリ作成、テストケースダウンロード、提出などを全て行うことができる便利なツールです。

↓お世話になってます

atcoder-tools gen {コンテストID} 機能を使うとソースファイル自動生成+テストケースのダウンロードまでができて非常に便利です。
ただ、その後問題文をブラウザで、ソースファイルをエディタで一括で開くところまで自動化したかったのでシェルスクリプトの勉強もかねて書いてみました。

できること:

  1. 指定したコンテストIDのディレクトリを atcoder-tools を用いて作成
  2. 全問題のmain.cpp をエディタで開く
  3. atcoder-tools が自動生成した各問題の metadata.json から問題IDを取得しブラウザで該当する問題を開く

前提:

  • bashスクリプトです。Windows PowerShell では動きません
  • 以下のコマンドに依存します:
    • atcoder-tools v2.14.0
    • jq-1.7.1
      • JSONのパースに用います
    • open
      • Mac, Linux ではデフォルトで使用できます(はずです)。エディタとブラウザのオープンに用います。WSLやLinux では xdg-open に書き換えてください

atcoder-tools と jq は pip 経由でインストールできます。

使い方

  1. 適当なディレクトリにatcoder_prepareなどの名前で上のスクリプトを保存し、そのディレクトリでchmod 700 atcoder_prepare などを実行して実行権限を付与します。

  2. ターミナルで以下を実行

    # スクリプトが置いてあるディレクトリで
    ./atcoder_prepare <contest_id> 
    # またはPATHを通して
    atcoder_prepare <contest_id>
    

<contest_id> には、AtCoderのコンテストIDを指定してください。

例) atcoder_prepare abc390

その他設定

  • ATCODER_TOOLS_WORKSPACE 環境変数を設定することでatcoder-tools の作業ディレクトリをスクリプトに教えることができ、(2) と (3) のステップで使用されます
    • 設定されていない場合 atcoder-tools本家にならい ~/atcoder-workspace/ となります
    # 例
    # 環境変数を設定
    export ATCODER_TOOLS_WORKSPACE=`~/CompetitiveProgramming/AtCoder/`
    # 実行
    atcoder_prepare abc300
    

やっていること (24/09/09追記)

1. 指定したコンテストIDのディレクトリを atcoder-tools を用いて作成

atcoder-tools gen を実行すると、生成されたディレクトリ内は以下のような構造になります;

.
├── A
│   ├── in_1.txt # 入力サンプル
│   ├── in_2.txt # 入力サンプル
│   ├── main
│   ├── main.cpp
│   ├── metadata.json # 問題に関するメタデータが記述されている。
│   ├── out_1.txt # 出力サンプル
│   └── out_2.txt # 出力サンプル
└── B
    ├── in_1.txt # 入力サンプル
    ├── in_2.txt # 入力サンプル
    ├── main.cpp
    ├── metadata.json # 問題に関するメタデータが記述されている。
    ├── out_1.txt # 出力サンプル
    └── out_2.txt # 出力サンプル
└── C
......

metadata.json を後で使います。

2. 全問題のmain.cpp をエディタで開く

スクリプト内の codeopen_tooldir 関数で実装しています。

コンテストのディレクトリ内の全てのディレクトリを走査して、その中のmain.cpp を全てエディタで開ければ良さそうです。
*によるワイルドカードマッチングを用いると "${workspace_dir}"*/ で workspace_dir 以下のサブディレクトリのフルパスが配列として得られます。この要素ひとつひとつを directory 変数としてfor文で回しています。
directory変数の後ろにmain.cppを結合させることで CPPファイルの絶対パスを得られるため openコマンドで開くことができます。ユーザー設定におけるデフォルトのエディタが開かれるはずです。

function codeopen_tooldir() {
    local workspace_dir="$1"

    # Ensure path ends with /
    [[ "${workspace_dir}" != */ ]] && workspace_dir="${workspace_dir}/"

    for directory in "${workspace_dir}"*/; do 
        # コンテストディレクトリ内の全てのディレクトリを走査
        # 変数 directory は "/path/to/contest/directory/A/" のような形式になっているので、
        local cppfile="${directory}main.cpp"
        if [[ ! -f "${cppfile}" ]]; then
            log_warn "main.cpp does not exist for directory \"$(basename "${directory}")\". Skipping opening cpp file with default editor."
            continue    
        fi
        open "${cppfile}"
    done
}

3. 全問題のURLをブラウザで開く

browseropen_tooldir 関数で実装しています。

これまたatcoder-toolsが自動生成してくれる情報を使います。便利ですね。
各ディレクトリにある metadata.json には問題のIDなどのメタ情報が含まれていて problem_id を抽出すればよさそうです。
ここではJSONのパースに jq コマンドを用いており、JSON形式のデータから特定のフィールドをパースし、AtCoderのURLにアクセスします。

jq を使っている部分以外は 2 とほぼ同じ処理を行っています。各ディレクトリにある metadata.json から problem_id を抽出していますが、もし何らかの理由で jq コマンドが失敗したり、metadata.jsonproblem_id が含まれていない場合警告メッセージを表示し、その問題の処理はスキップされます。

workspace_dir 以下の各ディレクトリを走査し、metadata.json が存在すればその中から problem_id を取得します。そして、コンテストIDおよび problem_id に基づき、AtCoderのコンテストページに対応するURLを生成します。ここはハードコードしています。

最後に open コマンドを使ってブラウザでページを開きます。
ここで、一度に8問くらい開いてしまうとToo many requests エラーが出てしまうので、各URLを開いた後に少しの間スリープしています。

function browseropen_tooldir() {
    local workspace_dir="$1"
    local contest_id
    contest_id="$(basename "${workspace_dir}")"

    # Ensure path ends with /
    if [[ "${workspace_dir}" != */ ]]; then
        workspace_dir="${workspace_dir}/"
    fi

    for directory in "${workspace_dir}"*/; do
        local metadata="${directory}metadata.json"
        if [[ ! -f "${metadata}" ]]; then
            log_warn "metadata.json for directory \"$(basename "${directory}")\" doesn't exist. Skipping opening problem."
            continue
        fi

        local problem_id
        problem_id="$(jq -r '.problem.problem_id' "${metadata}" 2>/dev/null)"
        if [[ $? -ne 0 || "${problem_id}" == "null" ]]; then
            log_warn "Failed to get problem ID for \"$(basename "${directory}")\". Skipping opening problem."
            continue
        fi

        local url="https://atcoder.jp/contests/${contest_id}/tasks/${problem_id}"
        open "${url}"
        log_info "Opened ${url} for problem \"$(basename "${directory}")\"."
        # sleep to avoid too many requests
        sleep 0.2
    done
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?