VSCodeのdevcontainerでAtCoder環境を構築
せっかくだからいろいろな言語でAtCoderをやってみたい、と思っている皆さんには、ちょっと参考になることもあるかと。
環境の前提
- Windows
- WSL2
- VSCode
ディレクトリ構造
冒頭から、ディレクトリ構造を。
Workspaces
├─ C++
│ ├─ .devcontainer
│ │ ├─ Dockerfile
│ │
│ ├─ .vscode
│ │ ├─ tasks.json
│ │ ├─ cpp.code-snippets
│ │
│ ├─ C++.code-workspace
│ ├─.Contest
│ │ ├─ A.cpp
│ │
│ ├─ test
│ │ ├─ sample-1.in
│ │ ├─ sample-1.out
│ │
│ ├─ a.out
│ ├─ .Library
│ ├─ DP
│
├─ Python
├─ Nim
Solved_Code
├─ ABC
├─ 123
├─ A.cpp
├─ B.py
├─ C.nim
-
環境部分は複数言語用意することを念頭に、提出コード集とはわけてみた
※そもそも提出コードを保存する意味あるのか?という話もあるが、単なる思い出だけでなく、検索できるのは一定の意味があるかと -
環境部分は言語毎の以下のセット
- Dockerfile含む.devcontainerディレクトリ
- tasks.jsonやら、snippetsやらを含む.vscodeディレクトリ
- .code-workspaceファイル
それに加えて
- 解答中のプログラムを一時的に入れておく.Contestディレクトリ(.をつけて上にあげるといい感じ)
- テストを落とすtsstディレクトリ(なんでoj-prepareを使わないんだよ、という話ですが、ぽつぽつ1問ずつ解くこともあるじゃないですか、ということです)
- コンパイル後の実行ファイル
- お手製のライブラリを入れる.Library
-
提出コード集の方は、コンテストカテゴリー別にしつつ、言語はごちゃ混ぜ
-
Windowsだし、個人作業ならOneDriveは非常に快適なので、gitはお好みで
Dockerfile
基本はubuntunに、2023年の言語アップデート時の提案シート通りにinstall commandを書いていくだけ。
みんな大好きonline-judge-toolsと、verification-helperも入れておきます。
(online-judge-toolsについては、このDockerfileを使ったVSCodeのdevcontainer内でsubmitしても、結果表示のブラウザが立ち上がらなかったので、submit.pyのshow resultのところのutils.webbrowser_register_explorer_exe()の行をコメントアウトして使っています。)
FROM ubuntu:22.04
# g++-12 gdb
RUN apt update && apt install -y g++-12 gdb build-essential
# GMP
RUN apt install -y libgmp3-dev
WORKDIR /tmp
# ac-library
RUN apt install -y wget &&\
wget https://github.com/atcoder/ac-library/releases/download/v1.5.1/ac-library.zip -O ac-library.zip &&\
mkdir /opt/ac-library &&\
apt-get install -y unzip &&\
unzip /tmp/ac-library.zip -d /opt/ac-library
# boost
RUN wget https://archives.boost.io/release/1.82.0/source/boost_1_82_0.tar.gz -O boost_1_82_0.tar.gz &&\
tar xf boost_1_82_0.tar.gz
WORKDIR /tmp/boost_1_82_0
RUN ./bootstrap.sh --with-toolset=gcc --without-libraries=mpi,graph_parallel &&\
./b2 ました toolset=gcc variant=release link=static runtime-link=static cxxflags=""-std=c++2b"" stage &&\
./b2 -j3 toolset=gcc variant=release link=static runtime-link=static cxxflags=""-std=c++2b"" --prefix=/opt/boost/gcc install
# Eigen
RUN apt install -y libeigen3-dev=3.4.0-2ubuntu2
# git
RUN apt install -y git
# online-judge-tools/verification-helper
RUN apt install -y python3-pip &&\
#pip3 install online-judge-tools &&\
pip3 install git+https://github.com/sukenori/oj.git &&\
pip3 install online-judge-verify-helper
# Docker
RUN apt install -y docker.io
devcontainer.json
そのDockerfileをdevcontainerにしていくわけですが、その際、まずは、環境を置いてあるフォルダをマウントし、さらに、提出コード集を分離したので、それも別にマウントしてやります。
{
"name": "AtCoder-C++",
"build": {
"dockerfile": "Dockerfile_AtCoder-C++"
},
"workspaceMount": "source=C:/Users/ユーザー名/OneDrive/ローカルの保管場所/AtCoder-C++,target=/workspaces/AtCoder-C++,type=bind",
"workspaceFolder": "/workspaces/AtCoder-C++",
"mounts": [
"source=C:/Users/ユーザー名/OneDrive/ローカルの保管場所/Solved_Code,target=/workspaces/Solved_Code,type=bind",
"source=/var/run/docker.sock,target=/var/run/docker.sock,type=bind"
],
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.cpptools",
"GitHub.copilot",
"ms-azuretools.vscode-docker"
]
}
},
"postCreateCommand": "./.devcontainer/postCreateCommand.sh",
}
postCreateCommand.sh
文字通り、コンテナクリエイト後に走るスクリプトですので、stdc++.hのプリコンパイルを置いたり、ojのログインなんかをします。
#!/bin/bash
cp /workspaces/AtCoder-C++/stdc++.h.gch /usr/include/x86_64-linux-gnu/c++/12/bits
oj login -u ログイン名 -p パスワード https://atcoder.jp/
.code-workspace
さっきマウントしておいたディレクトリで、ワークスペースを構成します。
(提出コード集部分は一例です。)
コンテストが終わったら、.Contesutから中身を移していったりします。
{
"folders": [
{
"name": "AtCoder-C++",
"path": "/workspaces/AtCoder-C++"
},
{
"name": "AtCoder_Beginner_Contest",
"path": "/workspaces/Solved_Code/AtCoder/AtCoder_Beginner_Contest"
},
{
"name": "AtCoder_Problems-Recommendation",
"path": "/workspaces/Solved_Code/AtCoder/AtCoder_Problems-Recommendation"
}
]
}
tasks.json
ojの自動化を導入するので、コンパイル、テストのダウンロード、テスト、提出の各taskを用意します。
コンパイルオプションは、これもしつこく言語アップデート時の提案シートに揃えてみたりしています。
コンパイルをデフォルトのタスクにして、提出のタスクにショーカットをつければ、その2つのショートカットでほぼほぼCLI要らずになります。というのも、提出のタスクは、testディレクトリの削除→サンプルケースのダウンロード→テスト→提出のコンボにしてあるからです。URL渡しは、サンプルケースのダウンロード時に、出てくるウィンドウに問題文URLをコピペするだけです(Chrome拡張機能を使うとさらにいい感じです)。
加えて自作ライブラリをoj-bundleで展開して提出できるようにしておきます(.vscodeに後述のbundle.shを入れておく)。
{
"version": "2.0.0",
"tasks": [
{
"label": "cpp build",
"group": {
"kind": "build",
"isDefault":true
},
"type": "shell",
"command": "/usr/bin/g++-12",
"args": [
"-std=gnu++2b",
"-O2",
"-DONLINE_JUDGE",
"-DATCODER",
"-Wall",
"-Wextra",
"-mtune=native",
"-march=native",
"-fconstexpr-depth=2147483647",
"-fconstexpr-loop-limit=2147483647",
"-fconstexpr-ops-limit=2147483647",
"-I/opt/ac-library",
"-I/opt/boost/gcc/include",
"-L/opt/boost/gcc/lib",
"-oa.out",
"${file}",
"-lgmpxx",
"-lgmp",
"-I/usr/include/eigen3",
"-I${workspaceFolder}/.Library",
"-ggdb3"
],
"presentation": {
"panel": "shared"
}
},
{
"label": "remove test",
"type": "shell",
"command": "rm",
"args": [
"-rf",
"test"
],
"presentation": {
"panel": "shared"
}
},
{
"label": "download test",
"type": "shell",
"command": "oj",
"args": [
"d",
"${input:url}",
"-d",
"test",
"-s"
],
"presentation": {
"panel": "shared",
"showReuseMessage": false
},
"dependsOn": ["remove test"],
"dependsOrder": "sequence"
},
{
"label": "test",
"type": "shell",
"command": "oj",
"args": [
"t",
"-c",
"${workspaceFolder}/a.out",
"-d",
"${workspaceFolder}/test/"
],
"presentation": {
"panel": "shared"
}
}, {
"label": "cpp bundle",
"type": "shell",
"command": "${workspaceFolder}/.vscode/bundle.sh",
"presentation": {
"panel": "shared"
},
"options": {
"env": {
"workspaceFolder": "${workspaceFolder}",
"file": "${file}"
}
}
},
{
"label": "cpp submit",
"type": "shell",
"command": "oj",
"args": [
"s",
"${input:url}",
"bundled.cpp",
"-w",
"0",
"-y"
],
"presentation": {
"panel": "shared"
},
"dependsOn": ["cpp build","download test","test","cpp bundle"],
"dependsOrder": "sequence"
},
],
"inputs": [
{
"type":"promptString",
"id":"url",
"description": "URL of the task"
}
]
}
#!/bin/bash
oj-bundle -I ${workspaceFolder}/.Library "${file}"\
|grep -v '^#line '\
|cat -s|sed -e '1{/^$/d}'\
> ${workspaceFolder}/bundled.cpp
これで、提出前にimportした自作ライブラリを展開してbundled.cppとし、それを提出してくれます。
まぁ、これだけやったところで、精進しなけりゃレートはちっとも上がらないんですけどね…
Discussion