追記(2021/02/27)
諸々アップデートして実行環境をこちらにまとめました.
https://github.com/antyuntyuntyun/atcoder-cpp-template
はじめに
この前社内で行われたAtcoder Problemsでのバーチャルコンテストに
久々の競プロやってみるか~と軽い気持ちで参加してみたら、
コード書けない日本語読めないで全然問題解けず辛い気持ちになりました。
Atcoder、許すまじ。
なので、競プロ用環境整備をとりあえずして、ちゃんと学びなおさなければという気持ちになっており、その環境整備記録です。需要あれば流用してください。
整備内容はおおかまに以下です。
- VSCode上でのスニペット登録
- AtCorderへのテスト・提出をシェルからコマンドで行えるように調整
この記事の推奨対象者
- Linuxで作業できる人
- C++で頑張ろうとしている人
- Atcoderに復讐を誓っている人
WindowsでもMacでもどちらでもいいがLinuxで作業できる人対象です。
Windowsの人はwsl上で作業してください。
C++で頑張ろうとしている人を応援します。一緒に頑張りましょう。
業務でpython扱っているからとかそういうのは認めません。
男はC++です。
コンパイラ
sudo apt install build-essential
エディタ
VSCodeで整備するなら、以下の記事など参照。他にもググればたくさんあります。
Visual Studio Codeで競プロ環境構築(導入編)
Visual Studio Codeで競プロ環境構築(実践編)
エディタは宗教なのでお好みでいいと思います。私は、Sublime TextとVSCodeとvimを行ったり来たりしています。
VSCodeに登録するスニペット
この章はVSCode利用者対象です。
スニペットとは、よく使うパターンのコードを簡単に入力できるようにしたものです。
毎回 #include とか int main()とか書くのはしんどいので、簡単に記載できるようにします。
File > Preferences > User Snippets
からcppを選択して記載、もしくは、
コマンドパレットを開いてSnippetと打って、Preferences: Configure User Snippets
を選択すると設定できます。
私は以下のように設定しています。
{
// Place your snippets for cpp here. Each snippet is defined under a snippet name and has a prefix, body and
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
// same ids are connected.
// Example:
// "Print to console": {
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
"cpp template": {
"prefix": "cpptemplate",
"body": [
"/**",
"* author: antyuntyun",
"* created: $CURRENT_DATE.$CURRENT_MONTH.$CURRENT_YEAR $CURRENT_HOUR:$CURRENT_MINUTE:$CURRENT_SECOND",
"**/",
"",
"#include <bits/stdc++.h>",
"using namespace std;",
"",
"int main() {",
" int a, b;",
" cin >> a >> b;",
"",
" // 二次元配列",
" vector<vector<int>> c(${1:row num},vector<int>(${2:colum num}));",
" // vector<vector<int>> c(${1:row num},vector<int>(${2:colum num},3)); // 初期化する場合。初期値3の例",
" for(int i=0;i < ${1:row num};i++){",
" for(int j=0;j < ${2:colum num};j++){",
" cin >> c[i][j];",
" }",
" }",
"",
" vector<int> d(${3:vector num});",
" for(int i=0;i < ${3:vector num};i++) cin >> d[i];",
"",
" ceil(a); // 切り上げ",
" floor(b); // 切り捨て",
"",
" // 昇順",
" sort(d.begin(), d.end());",
" // 降順",
" sort(d.begin(), d.end(), greater<int>{});",
"",
" return 0;",
"}"
],
"description": "cpp_template"
},
"cin template": {
"prefix": "cintemplate",
"body": [
"cin >> $1;",
],
"description": "cin_template"
},
"cout template": {
"prefix": "couttemplate",
"body": [
"cout << $1 << endl;",
],
"description": "cout_template"
},
"for template": {
"prefix": "fortemplate",
"body": [
"for(int i=0; i < ${1:firstr loop num};i++){",
" ${2:code}",
"}",
],
"description": "for_template"
},
"forfor template": {
"prefix": "forfortemplate",
"body": [
"for(int i=0; i < ${1:firstr loop num};i++){",
" for(int j=0; j < ${2:second loop num};j++){",
" ${3:code}",
" {",
"}",
],
"description": "for_template"
}
}
流用する場合、author_nameの部分は適宜変更してください。
設定後、.cppファイル編集中に例えばcpp
と打つと以下のようにcpptemplate
が表示されて、
これをEnterで選択すると、テンプレートが一発で入力されます。
競プロだと基本数値 or 文字列の入力を最初に受け取るので、標準入力を受け取る部分を含めてテンプレートを書いています。
cpptemplateを実際に利用するときには、必要な標準入力受け取り部分だけ残し、
変数名は適宜変更して利用しています。
他にもいろいろ書いていますが、いろいろな言語を触っていると関数も文法も忘れてしまうので
ある意味メモ書き代わりでソートなどを書いています。ググる時間削減。
流用する場合はお好みで削除 or 追加してください。
他にもいくつか用意してる部分、例えばforループのテンプレはforと打ってあげれば、fortemplate
が表示されて同様に一発入力できます。
$
で指定している部分は、入力後にカーソルが合うので、初期値などがすぐに入力できます。
また入力後に、Tabで\$1 -> \$2というように飛んでいけるので、次々入力できます。
また、同じ変数、例えば${1:row num}
は別箇所にあっても同じスニペット内のものは同時入力されます。
とても便利ですね。
AtCorderにあシェル関数の設定
こちらのオンラインジャッジツールを用います。Atcoder以外にも対応しているそうです。
https://github.com/online-judge-tools/oj
python環境がある前提で進みます。
pip install online-judge-tools
こちらを導入すると、シェルからコマンドで問題ページにある入力・出力例を用いたテストやコードの提出ができるようになります。
特にテストができるようになるのが良いですこれ。
今までのブラウザ行って入力例コピーして、シェルでプログラム実行して入力例ペーストして、
ブラウザの出力例と比較する、といったしんどいテスト作業がコマンド一発で終わります。
シェルコマンドから簡単・便利に扱えるように、シェルの設定ファイル(~/.bashrc や ~/.zshrc など)に以下のように関数を設定してあげます。
下記を設定ファイルに追記して、source ~/.zshrc
等のコマンドで読み込むかシェルを新たに起動してあげれば、関数設定完了です。
もちろんC++用にしか書いてないです。男はC++。
# -------------------------------------
# atcorder
# -------------------------------------
# https://github.com/online-judge-tools/oj/blob/master/docs/getting-started.ja.md
# pip install online-judge-tools が必要
atcoder-login(){
oj login https://atcoder.jp/
}
atcoder-test(){
src=$1
contest_id=$2 # urlの/atcorder/contest/xxxxxx/tasks/... のxxxxxの部分
problem_id=$3 # urlの末尾。おそらく基本a,b,c,d
if [ -z "$src" -o -z "$contest_id" -o -z "$problem_id" ]; then
echo '\e[35mcommand Error \e[m'
echo 'src(.cpp)) and contest id and problem id must be specified.\n\n'
echo 'Usage: atcorder-test [<src> <contest_id> <problem_id>]'
echo 'url consists of /atcorder/contest/[$contest_id]/tasks/[$contest_id]_[$problem_id]'
return
fi
echo '\n\e[35m----------------- downlad test input ----------------- \e[m\n'
oj d "https://atcoder.jp/contests/${contest_id}/tasks/${contest_id}_${problem_id}"
# https://atcoder.jp/contests/language-test-202001
g++ -Wall -std=gnu++17 ./$1
echo '\n\e[35m------------ test src:' $src 'contest id:' $contest_id 'problem_id:' $problem_id '------------ \e[m\n'
oj test
echo '\n\e[35mrm test file ...\e[m\n'
rm -f a.out
rm -rf test
}
atcoder-submit(){
src=$1
contest_id=$2 # urlの/atcorder/contest/xxxxxx/tasks/... のxxxxxの部分
problem_id=$3 # urlの末尾。おそらく基本a,b,c,d
if [ -z "$src" -o -z "$contest_id" -o -z "$problem_id" ]; then
echo '\e[35mcommand Error \e[m'
echo 'src(.cpp)) and contest id and problem id must be specified.\n\n'
echo 'Usage: atcorder-submit [<src> <contest_id> <problem_id>]'
echo 'url consists of /atcorder/contest/[$contest_id]/tasks/[$contest_id]_[$problem_id]'
return
fi
echo '\n\e[35m----------------- submit code ----------------- \e[m\n'
oj s "https://atcoder.jp/contests/${contest_id}/tasks/${contest_id}_${problem_id}" $src
cmd.exe /C start "https://atcoder.jp/contests/${contest_id}/submissions/me"
# 上記はwsl用コマンド。mac なら上記をコメントアウトして下記をコメントイン
# open "https://atcorder.jp/contests/[$contest_id]/submissions/me"
}
AtCorderを扱うシェル関数の使い方
以下のコマンドで呼び出してください。
引数つけずに関数呼び出しした場合に、エラーメッセージによくあるコマンドhelpと同様に
”こういう引数を取って呼び出してください”という旨を
出力するようにしているので、忘れたらとりあえず何もつけずに関数呼んでみれば大丈夫です。
# テスト
# atcoderの問題ページのurlからcontest_idとproblem_idを確認する
# 問題ページのurlは http://atcorder/contest/[contest_id]/tasks/[contest_id]_[problem_id] という構成になっている
atcoder-test ./src.cpp contest_id problem_id
# ログイン
# コードを提出するために必要。コンテスト前に事前ログイン推奨
atcoder-login
# コード提出
# 提出後にブラウザで自分が提出したコード画面一覧が開く。
# おそらく oj 側の仕様で、ソースのある場所にcdしてないと上手く動かないです。
# 前章の関数のコメントで書いていますが、wsl用に一旦書いたのでmacの人はコメントに従って書き換えてください
# 他環境だとこう設定しないと動かないとかのコメントお待ちしてます
atcoder-submit ./src.cpp contest_id problem_id
docker
気が向いたらdockerに乗せるのもやろうかなと思います。
おわりに
これでサクサク問題に取り組めるようになりました。
あとは実践あるのみなので、(私みたいに)環境整備して満足感得て終わりではなく、
以下のような練習問題まとめサイトで実際にいっぱいコードを書いてみましょう。
https://kenkoooo.com/atcoder/#/training/Boot%20camp%20for%20Beginners
他にもこういうtipsが~とか、この練習サイトもおすすめ、みたいなコメントお待ちしてます。