AtCoder用環境構築

自分好みの環境構築で全部まとまってる記事は自分で作るしかない。


target


install MSYS2

(参考)
MSYS2の導入 - 東京大学工学部 精密工学科 プログラミング応用 I・II
Windows10の開発環境をMSYS2で再構築 - Qiita
MSYS2 による gcc 開発環境の構築 - Qiita


インストール先のフォルダを

C:\programming\msys64

に変更する。諸々のツールを追加する際に C ドライブ直下が散逸するのを防ぎたい。

起動する MSYS2 は MinGW 64bit 版で統一する。

run pacman

パッケージ管理ツールの更新には色々流儀がありそう。

$ pacman -Sy pacman
$ pacman --needed -S bash pacman pacman-mirrors msys2-runtime
$ pacman -Su
$ pacman -S base-devel mingw-w64-x86_64-toolchain

各コマンドごとにターミナルを再起動して、更新されなくなるまで再度同じコマンドを実行させると安心できそう。

最後の mingw-w64-x86_64-toolchain をインストールすると GCC とともに Python もインストールされるはず。Group: mingw-w64-x86_64-toolchain - MSYS2 Packages から

toolchain > pkgconf > meson > python

の順に遡って辿れるので多分そう。

add PATH

Windows -> MSYS2
  • ユーザー環境変数のPathに C:\programming\msys64\mingw64\bin を追加
MSYS2 -> Windows


install Git

(参考)
【超入門】初心者のためのGitとGitHubの使い方 - RAKUS Developers Blog | ラクス エンジニアブログ
VSCodeでGit・GitHubを使う方法を解説する【初心者向き】
リポジトリをクローンする - GitHub Docs


GitHub のプライベートリポジトリ上で競プロ用のアルゴリズムテンプレートを管理する。リポジトリ名は competitive にしてある。ついでに .vscode フォルダも push しておくと楽ができる。

改行コードの部分だけ気を付けてインストールする。デフォルトエディターの設定はそのままで問題ない。

git config

$ git config --global user.name [[ any_user_name ]]
$ git config --global user.email [[ any_email_address ]]

git clone

Git Bash を起動する。

$ cd /c/programming
$ git clone https://github.com/[[ user_name ]]/competitive.git

C:\programming\competitive フォルダが作成されていることを確認する。

GitHub 上に当該リポジトリをまだ作成していない場合は、

$ cd /c/programming
$ mkdir competitive
$ cd competitive
$ git init

でローカルリポジトリを作成する。


install Visual Studio Code

(参考)
VSCodeのインストール方法について解説する【初心者向き】


インストール先は変えずにそのままインストールする。PATH は自動的に追加される。

extensions

open folder

Visual Studio Code の [フォルダを開く] から

C:\programming\competitive

を開く。

git clone していない場合は .vscode フォルダ内の json ファイルを書き換えていく。それぞれファイルが存在しない場合は新規で作成すること。

.json files here (4 contents) 書き換えるべき部分だけ抜き出して記述してある。MSYS2 のインストール先が異なる場合はパスを適宜読み替えてほしい。

// c_cpp_properties.json

{
    "configurations": [
        {
            "name": "Win32",
            "includePath": [
                "${workspaceFolder}/**",
                "C:\\programming\\msys64\\mingw64\\include"
            ],
            "compilerPath": "C:\\programming\\msys64\\mingw64\\bin\\gcc.exe",
            "intelliSenseMode": "gcc-x64",
            "cppStandard": "c++20"
        }
    ],
    "version": 4
}
// settings.json

{
  "C_Cpp.default.includePath": [
    "C:\\programming\\msys64\\mingw64\\include",
  ],
  "C_Cpp.default.compilerPath": "C:\\programming\\msys64\\mingw64\\bin\\g++.exe",
  "C_Cpp.default.cppStandard": "c++20",
  "C_Cpp.default.intelliSenseMode": "gcc-x64"
}

g++ でデバッグすることも考慮して以下の 2 つも一応書き換えておく。ショートカットキーはあとで上書きするので、少なくとも AtCoder をやる上では意図せずデバッグが開始されることはない。

// tasks.json

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "g++.exe build active file",
      "type": "process",
      "command": "C:\\programming\\msys64\\mingw64\\bin\\g++.exe",
      "args": [
        "-std=c++20",
        "-g",
        "-O2",
        "${file}",
        "-o",
        "${fileDirname}\\${fileBasenameNoExtension}.exe",
        "-lgdi32"
      ],
      "group": {
        "kind": "build",
        "isDefault": false
      }
    }
  ]
}

"isDefault": true のままだと atcoder-tools でビルドしたときに "args" が上記の内容に置き換わってしまうので注意する。

// launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "(gdb) Launch",
      "type": "cppdbg",
      "request": "launch",
      "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
      "args": [],
      "environment": [],
      "cwd": "${workspaceFolder}",
      "stopAtEntry": false,
      "externalConsole": true,
      "MIMode": "gdb",
      "miDebuggerPath": "C:\\programming\\msys64\\mingw64\\bin\\gdb.exe",
      "setupCommands": [
        {
          "description": "Enable pretty-printing for gdb",
          "text": "-enable-pretty-printing",
          "ignoreFailures": true
        }
      ],
      "preLaunchTask": "g++.exe build active file"
    }
  ]
}

customize

左下の歯車アイコン、あるいは Ctrl+, から [設定] を開き、右上のアイコンから [設定 (JSON) を開く] を探し出して settings.json を開く。好みに合わせてカスタマイズする。

// settings.json

{
    "workbench.startupEditor": "none",
    "editor.tabSize": 2,
    "files.eol": "\n"
}


install atcoder-tools

(参考)
Visual Studio Code の統合ターミナルで MSYS2 の bash を選択できるようにする - Qiita
MSYS2 で pip を使う - Qiita
VSCodeでAtCoder用環境を構築する|デロイト トーマツ ウェブサービス株式会社(DWS)公式ブログ
便利! AtCoder で競技プログラミングをするときに重宝する AtCoder Tools のご紹介 - Qiita
GitHub - kyuridenamida/atcoder-tools: Convenient modules & tools for AtCoder users, written in Python 3.6


ここからが結構長い。

before installing...

set MSYS2 as default terminal

Visual Studio Code の規定のターミナルを MSYS2 に変更する。カスタマイズ時に使用した settings.json に追記する。"PowerShell" "Command Prompt" "Git Bash" の項目は変更しなくて良い。もしこれらの項目が存在していないなら、Ctrl+, で設定を開き terminal.integrated.profiles.windows で検索して [settings.json で編集] を押せば自動入力されるはず。

// settings.json

{
    "terminal.integrated.profiles.windows": {
        "PowerShell": {
            "source": "PowerShell",
            "icon": "terminal-powershell"
        },
        "Command Prompt": {
            "path": [
                "${env:windir}\\Sysnative\\cmd.exe",
                "${env:windir}\\System32\\cmd.exe"
            ],
            "args": [],
            "icon": "terminal-cmd"
        },
        "Git Bash": {
            "source": "Git Bash"
        },
        "MSYS2 Bash": {
            "path": [
                "C:\\programming\\msys64\\usr\\bin\\bash.exe"
            ],
            "args": [
                "--login"
            ],
            "env": {
                "MSYSTEM": "MINGW64",
                "CHERE_INVOKING": "1"
            },
            "overrideName": true
        }
    },
    "terminal.integrated.defaultProfile.windows": "MSYS2 Bash"
}
install pip

MSYS2 MINGW64 を起動する。MSYS2 で pip コマンドを使用できるようにする。Visual Studio Code のターミナルでも作業可能だが、その際は

$ cd ~

でホームディレクトリに移動しておく必要があるかも[要検証]

$ pacman -S python3-pip
$ pip3 install --upgrade pip

installing now...

そのまま MSYS2 上で作業を進める。

$ pip3 install atcoder-tools
$ pip3 install markupsafe==2.0.1

after installing...

~/.atcodertools.toml を作成する。ホームディレクトリは /c/programming/msys64/home/[[ user_name ]] になっているはず。

# .atcodertools.toml

[codestyle]
indent_type='space' # 'tab' or 'space'
indent_width=2
template_file='/c/programming/competitive/template.cpp'
workspace_dir='/c/programming/competitive/atcoder-workspace/'
lang='cpp' # Check README.md for the supported languages.
# code_generator_toml="~/universal_code_generator.toml"
[postprocess]
# exec_on_each_problem_dir=''
# exec_on_contest_dir=''
[compiler]
compile_command='g++ main.cpp -o main -std=gnu++20 -O2 -Wall -Wextra'
compile_only_when_diff_detected=true
[tester]
compile_before_testing=true
compile_only_when_diff_detected=true
timeout_adjustment=1.2
[etc]
download_without_login=false
parallel_download=false
save_no_session_cache=false
skip_existing_problems=true
in_example_format="in_{}.txt"
out_example_format="out_{}.txt"

[postprocess] についてはまた後で設定する。

コード生成テンプレートファイルがない場合は作成する。

template.cpp here (1 content)

// template.cpp

#include <bits/stdc++.h>
using namespace std;

#define ALL(a) begin(a), end(a)
#define RALL(a) rbegin(a), rend(a)
using ll = long long;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
template<typename T> using Graph = vector<vector<T>>;
template<typename T> using Spacial = vector<vector<vector<T>>>;
template<typename T> using greater_priority_queue = priority_queue<T, vector<T>, greater<T>>;
{% if mod %}
constexpr int MOD = {{ mod }};
{% else %}
constexpr int MOD = 998244353;
{% endif %}
const int dx[4] = { 1, 0, -1, 0 };
const int dy[4] = { 0, 1, 0, -1 };
char interval[2] = {' ', '\n'};

template<typename T, typename... Args> auto make_vector(T x, int arg, Args... args) { if constexpr(sizeof...(args) == 0) return vector<T>(arg, x); else return vector(arg, make_vector<T>(x, args...)); }

template<typename T> struct is_plural : false_type{};
template<typename T1, typename T2> struct is_plural<pair<T1, T2>> : true_type{};
template<typename T> struct is_plural<vector<T>> : true_type{};
template<typename T> struct is_plural<complex<T>> : true_type{};
template<> struct is_plural<string> : true_type{};

template<typename T1, typename T2> istream& operator>>(istream& is, pair<T1, T2>& p) { return is >> p.first >> p.second; }
template<typename T1, typename T2> ostream& operator<<(ostream& os, const pair<T1, T2>& p) { return os << p.first << ' ' << p.second; }
template<typename T> istream& operator>>(istream& is, vector<T>& vec) { for(auto itr = vec.begin(); itr != vec.end(); ++itr) is >> *itr; return is; }
template<typename T> ostream& operator<<(ostream& os, const vector<T>& vec) { if(vec.empty()) return os; bool pl = is_plural<T>(); os << vec.front(); for(auto itr = ++vec.begin(); itr != vec.end(); ++itr) os << interval[pl] << *itr; return os; }
template<typename T> istream& operator>>(istream& is, complex<T>& x) { T a, b; is >> a >> b; x = complex<T>(a, b); return is; }
template<typename T> ostream& operator<<(ostream& os, const complex<T>& x) { return os << x.real() << ' ' << x.imag(); }

bool CoutYN(bool a, string yes = {% if yes_str %}"{{ yes_str }}"{% else %}"Yes"{% endif %}, string no = {% if no_str %}"{{ no_str }}"{% else %}"No"{% endif %}) { cout << (a ? yes : no) << '\n'; return a; }

template<typename T1, typename T2> inline bool chmax(T1& a, T2 b) { return a < b && (a = b, true); }
template<typename T1, typename T2> inline bool chmin(T1& a, T2 b) { return a > b && (a = b, true); }

template<typename... Args> void debugger(int, const char*, const Args&...);
#define debug(...) debugger(__LINE__, #__VA_ARGS__, __VA_ARGS__)


/* -------- <templates end> -------- */


void solve() {
  
}


/* -------- <programs end> -------- */


#define DEBUG
#ifdef DEBUG
void dbg() { cerr << '\n'; }
template<typename T, typename... Args> void dbg(const T& x, const Args&... args) { cerr << '\n' << x; dbg(args...); }
template<typename... Args> void debugger(int line, const char* str, const Args&... args) { cerr << line << " [" << str << "]:"; dbg(args...); };
#else
template<typename... Args> void debugger(int line, const char* str, const Args&... args) {};
#endif

#define COMPLEX_COMPARE
#ifdef COMPLEX_COMPARE
namespace std { template<typename T> bool operator<(const complex<T>& l, const complex<T>& r) { return real(l) != real(r) ? real(l) < real(r) : imag(l) < imag(r); } }
#endif

signed main() {
  cin.tie(nullptr);
  ios::sync_with_stdio(false);
  cout << fixed << setprecision(10);
  solve();
  return 0;
}

これで一旦、ターミナル経由ならば atcoder-tools のコマンドが不自由なく使用できるようになっている。


set up keyboard shortcuts

(参考)
コマンドライン | 非公式 - Visual Studio Code Docs
Visual Studio Codeでタスク機能を使ってみよう - とことんDevOps | 日本仮想化技術のDevOps技術情報メディア
【VSCode】キーボードショートカットを編集してみる


キーボードショートカットだけで機能させることを最終目標としている。

behavior of atcoder-tools gen

通常はファイルを生成して終わりだが、折角なので生成ファイルを全て開きたい。

よほどのことがない限り前から問題を解いていくので、後ろから生成ファイルを開いていく。AC してファイルを閉じていくと幸せになれそう。

set postprocess in .atcodertools.toml

一旦放置していた .atcodertools.toml を修正する。

# .atcodertools.toml

[postprocess]
exec_on_each_problem_dir='basename `pwd` >> ../.atcodertools_directories.txt'
exec_on_contest_dir='data=(`tac .atcodertools_directories.txt`); if [ ${#data[@]} -le 10 ]; then for dir in ${data[@]}; do code -g ${dir}/main.cpp:45:2; done; fi'

ファイル生成ごとにディレクトリ名を *\atcoder-workspace\[[ contest_id ]]\.atcodertools_directories.txt に追記し、すべてのファイル生成が終了したら追記内容を逆順に読み込み、読み込んだディレクトリ名順に *\atcoder-workspace\[[ contest_id ]]\[[ dirname ]]\main.cpp の 45 行 2 列目にキャレットを置いて開く、という挙動になっている。もし問題数が 10 問を超えていたらファイルを開かないようにしてある。

それなりに重たい処理になるので、マシンパワーが足りなければコメントアウトすることを推奨する。

set atcoder-tools commands in tasks.json

C:\programming\competitive\.vscode\tasks.json に追記する。もちろん、既に GitHub 上で管理できているなら不要な作業である。

tasks.json here (1 content)

// tasks.json

{
  "tasks": [
    {
      "label": "atcoder-tools gen",
      "type": "shell",
      "command": "atcoder-tools gen ${input:contest_id}",
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "shared",
        "showReuseMessage": true,
        "clear": false,
        "close": true
      },
      "options": {
        "cwd": "${workspaceRoot}"
      }
    },
    {
      "label": "atcoder-tools test",
      "type": "shell",
      "command": "atcoder-tools test",
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": false,
        "panel": "shared",
        "showReuseMessage": true,
        "clear": false,
        "close": false
      },
      "options": {
        "cwd": "${fileDirname}"
      }
    },
    {
      "label": "atcoder-tools submit",
      "type": "shell",
      "command": "atcoder-tools submit -u",
      "presentation": {
        "echo": true,
        "reveal": "always",
        "focus": true,
        "panel": "shared",
        "showReuseMessage": true,
        "clear": false,
        "close": false
      },
      "options": {
        "cwd": "${fileDirname}"
      }
    }
  ],
  "inputs": [
    {
      "id": "contest_id",
      "type": "promptString",
      "description": "enter the AtCoder contest_id",
      "default": ""
    }
  ]
}

特に "tasks": "focus""tasks": "close" については好みに合わせて書き換えるべし。

"cwd" の設定はキーバインドと連携させるので記述通りにすること。

set keyboard shortcuts in keybindings.json

左下の歯車アイコン、あるいは Ctrl+K Ctrl+S から [キーボード ショートカット] を開き、右上のアイコンから [キーボード ショートカットを開く (JSON)] を探し出して keybindings.json を開く。

// keybindings.json

[
  {
    "key": "Ctrl+F1",
    "command": "workbench.action.tasks.runTask",
    "when": "resourceDirname == /c/programming/competitive",
    "args": "atcoder-tools gen"
  },
  {
    "key": "F5",
    "command": "workbench.action.tasks.runTask",
    "when": "editorTextFocus && resourcePath =~ /^.*atcoder-workspace.*main.cpp$/",
    "args": "atcoder-tools test"
  },
  {
    "key": "F9",
    "command": "workbench.action.tasks.runTask",
    "when": "editorTextFocus && resourcePath =~ /^.*atcoder-workspace.*main.cpp$/",
    "args": "atcoder-tools submit"
  }
]

Visual Studio Codeエクスプローラー上で C:\programming\competitive が開いているなら問題なく動作するはず。

F5 に atcoder-tools test を割り当てることで [デバッグの開始] を抑制している。別のキーを割り当てる際は [キーボード ショートカット] から検索をかけてみて、意図しない挙動が起こらないように注意する。


git push (optional)

(参考)
【超入門】初心者のためのGitとGitHubの使い方 - RAKUS Developers Blog | ラクス エンジニアブログ (再掲)
VSCodeでGit・GitHubを使う方法を解説する【初心者向き】 (再掲)


簡潔に記す。わからなければ上記サイトを参照すること。

.gitignore

C:\programming\competitive\.gitignore を作成する。

.gitignore here (1 content)

# .gitignore

# git ls-files --others --exclude-standard

# Ignore files generated by atcoder-tools
/atcoder-workspace/

# Ignore any other files if needed

push

Visual Studio Code の左上のアイコン群から [ソース管理] を開き、ステージングしてから [コミットしてプッシュ] する。


winning run...

後書きのようなもの。

PC を新調したので、競プロ歴 5 年目にしてようやく自動化ツールを導入した。

当初は online-judge-tools を導入する予定だったが、WSL 環境を嫌って MSYS2 でどうにかならないか丸 1 日かけて、結局どうにもならず。エラーが発生する度に原因を探し出して解決し、そして新たなエラーが発生する、というループを何度か繰り返しているうちにエラーを解決できなくなって諦めた。

atcoder-tools の方でも、インストール自体は難なくできたものの細かな仕様が不明瞭で(それはそう)、ソースコードを辿ったりシェルコマンドの構文を調べたり実験してみたり、そうこうしているうちに更に 2 日かかってしまった。その分個人的にはかなり満足のいく環境になったので良しとする。

あとはアルゴリズムテンプレートの自動挿入ができれば完璧か。


[2023/09/20 追記] 自動挿入できるようになった。

kyokkounoite.hatenablog.jp