TL;DR

  • 便利というだけではレートは上がらないことを忘れないようにしよう
  • (Windows ユーザなら) WSL と Windows ターミナルと VS Code を入れよう
  • シェルについて学ぼう
  • (C++ を使っているなら) オプションに -Wall -fsanitize=undefined -D_GLIBCXX_DEBUG を指定しよう
  • デバッガを使おう
  • oj コマンドと oj-template コマンドを使おう (宣伝)

目次

1. 注意

1.1. この記事について

この記事は、競技プログラミング (競プロ) において「環境構築」と呼ばれている行為について説明します。 「実際にやってみましょう」という体裁で書かれてはいますが、「あなたは何をすればよいか」の説明がしたいわけではなく、「それは何であるか」「それは何ができるのか」について適切に理解してもらうことを目的としています1

この記事は 2020 年 11 月に書かれました。 「原理的に何が実現できるのか (例: サンプルでのテストは自動化できる)」についての知識はかなりの時間が経ってもほとんど変化しませんが「具体的にどう実現するのがおすすめか (例: oj コマンドを使うとよい)」については比較的短い時間 (数年ほど) で時代遅れになるかもしれないことに注意してください2

1.2. 対象読者

対象読者は、「環境構築」と呼ばれる作業をすでに行なったつもりでいるが、自分が行なった作業が正確にはどういうものなのかあまりよく理解できていないという人です。

この記事のみで実際に「環境構築」をするのは少し難しい可能性があります。これから「環境構築」をしようという人が読む場合は、場合は他のより具体的な手順が書かれているものを探してきてそれと同時に並行して読むのがよいでしょう。

2. 前提

2.1. 「環境構築」と呼ばれているものは何か?

通常の競プロerが言う「環境構築」が指す「環境」とは「競プロを快適に行なうための環境」のことです。 競プロをするための環境、つまり「それがないと競プロをすることができないようなもの3」ではありません。 このことは「環境構築」という言葉を使う人のほとんどが「これから競プロを初めようとしている人」ではなく「競プロを初めてしばらく経った人」であることから理解できます。

この「環境」という語の意味を踏まえると、「環境構築」という語は「競プロを行なうための環境をより快適にすること」を意味すると言えるでしょう。

2.2. 「環境構築」をすると何がうれしいのか?

「環境構築」とは「競プロを快適に行なうための環境を準備するもの」であるので、競プロを快適に行なうことができるようになります。ですので、そのうれしさは「環境が快適になること」です。

単純に「環境構築」をしてもレートは上がりません。 「環境が快適になること」と「レートが上がること」は異なるためです。

「環境構築」をした結果を上手に使いこなすことができればレートを多少は上げることができるかもしれません。しかし、レートを上げられるのは元々すでに AtCoder 青色やそれ以上のレートがある人に限られるでしょう4

2.3. 「環境構築」はどのタイミングでやるべきか?

「環境構築」は、ある程度レートが高くなって、だんだんレートが伸び悩んできたタイミングでやるとよいでしょう。

逆に、競プロを初めたばかりの人は、まだ「環境構築」をする必要はないでしょう。 単純に「環境構築」をしてもレートは上がらないことと、初めたばかりなら問題をすこし解いただけですぐレートが上がることから、初心者が「環境構築」がどうこうという横道に逸れるのは遠回り (たとえばテスト前の部屋の掃除のようなもの) でしかないかもしれません5

3. 基本的な開発環境の準備

まず、コードを書いてコンパイルして実行できるところまで準備します。 実際にやってみましょう。

3.1. UNIX 互換環境を用意する (Windows Subsystem for Linux を導入する) (Windows の人のみ)

(Linux や mac を使っている人はこの節は無視してください)

Windows Subsystem for Linux (WSL) を導入してください。 これは Windows の内部に「本物の Ubuntu」をインストールしてくれます。 公式のドキュメント (Windows Subsystem for Linux (WSL) を Windows 10 にインストールする | Microsoft Docs) に従ってインストールしてください。 Linux ディストリビューションをいろいろ選べますが最新の Ubuntu を選択しましょう。

同時に Windows ターミナルも導入しておきましょう。 これも公式のドキュメント (Windows ターミナルのインストール | Microsoft Docs) に従ってインストールしてください。

MSYS2 や MinGW や Cygwin については忘れましょう。 これらは「自分のことを UNIX だと思い込んでいる Windows」を作るものです。 これらは「UNIX ぽいものが使いたいのだが、Windows であることが重要である」という場合に利用されます。 そうでない場合にこれらを利用するのは、ただ面倒が多いだけでしょう。

なぜ UNIX 互換環境が必要かというと、UNIX 互換環境の方が Windows 環境よりも (プログラマ向けのたいていの) ソフトウェアの利用や開発が簡単であるためです。 「イケイケのエンジニアが mac を使いがち」だったり「Microsoft 社が Windows 内で Linux を動かせる仕組みを開発してくれている」のはこのためです。 もちろん、Windows に特化したソフトウェアの開発 (たとえばゲーム制作) など Windows の方が適している場面もありますが、少なくとも競技プログラミングはそうではありません。

3.2. IDE / エディタを用意する (Visual Studio Code を導入する)

Visual Studio Code (VS Code) を利用しましょう6。 公式ページ (https://code.visualstudio.com/) からインストーラーをダウンロードしてきて、適当にマウスをポチポチするとインストールできると思います。 他のエディタや IDE に慣れているという人も、とりあえずまず 1 週間程度は VS Code を使ってみましょう。それから元々の IDE を使い続けるか VS Code に乗り換えるかの判断は、しばらく使ってみてからでも遅くはありません7

WSL 内から VS Code を利用できるように追加の設定もしましょう。 公式のドキュメント (Windows Subsystem for Linux で VS Code の使用を開始する | Microsoft Docs) に従って拡張機能をインストールしましょう。

3.3. コンパイラや処理系を用意する

コンパイラや処理系をインストールしましょう。 Windows ターミナルを通して WSL 内の Ubuntu を開き、以下のように入力して Enter キーを押してください。 パスワードが聞かれればパスワードを入力し、 Yes / No が聞かれれば Yes と入力しましょう。

$ sudo apt install build-essentail git g++ clang python3 python3-pip

コマンドの実行についての注意を述べておきます。 行頭の $ は「この行はターミナルに入力すべきコマンド文字列である」ということを示す記号 (たとえば円記号 のようなもの) であり、実際には入力する必要はありません8。 実行してみて、「成功した」「インストールされた」などの意味の文章 (英語の場合もあります) が表示されれば、それは「成功した」ことを意味します。 「失敗した」「インストールされなかった」「コマンドが見つからなかった」などの意味の文章 (英語の場合もあります) が表示されれば、それは「失敗した」ことを意味します。もし失敗した場合は、周囲に「なぜ失敗したのか」を説明する文章 (英語の場合もあります) が表示されているので、これを読んでその説明を理解し、原因を修正してもう一度やり直しましょう。 これらは以降の手順においても同様です。

(Linux の人はターミナルを開いて同様にしてください) (mac の人は自分で頑張ってください) (C++ や Python 以外の言語を使いたい人は頑張ってください)

3.4. 実際にコードを書いて実行してみる

C++ であれば、以下のようにします。実際にやってみましょう。

  1. $ code main.cpp を実行して VS Code を起動する
  2. 起動した VS Code 内で適当な C++ のコードを書く
  3. $ g++ main.cpp を実行してコンパイルし a.out というファイルを作る
  4. $ ./a.out を実行する
  5. 自分が書いたコードが実行されたことを確認する

Python であれば、以下のようにします。

  1. $ code main.py を実行して VS Code を起動する
  2. 起動した VS Code 内で適当な Python のコードを書く
  3. $ python3 main.py を実行する
  4. 自分が書いたコードが実行されたことを確認する

(他の言語の人はうまくやってください)

3.5. 確認

確認しましょう9

  • WSL をインストールした
  • Windows ターミナルをインストールした
  • VS Code をインストールした
  • コンパイラや処理系をインストールした
  • 実際にコードを書いて実行した

4. 基本的な知識の準備

ひとまずパソコン用語の解説をしておきます。

4.1. 黒い画面: シェルとターミナル

いわゆる「黒い画面」は「シェル」と「ターミナル」から構成されます。 ターミナルは「黒い画面」のウィンドウの部分、シェルは「黒い画面」の中に文字を表示するプログラムのことです。 シェルはプログラミング言語としての機能も持っており、入力されたコマンド (シェルの言語のプログラム) を実行し、結果を表示してくれます。

ターミナルとして動作するプログラムにもシェルとして使われるプログラムにも様々な種類がありますが、ここまで指示通りに進めていると、ターミナルとしては「Windows ターミナル」が使われ、シェルとしては「Bash」が使われているでしょう。

よい説明はいくらでもあると思うので、詳細は各自で検索して理解してください。

4.2. 環境変数

環境変数とは、OS の機能であり、プログラムを起動するときに自動的に渡される変数です。主にシステム全体の設定 (たとえば、ユーザ名は何か、表示は日本語がいいのか英語がいいのか、など) が格納されています。 環境変数の値は、たとえば C++ であれば std::getenv 関数によって、Python であれば os.environ によって取得できます。

シェル変数とは、シェル (プログラミング言語) における変数です。 環境変数はシェルを通して設定され、また記法もかなり共通していますが、シェル変数と環境変数は異なる概念であることに注意してください10

環境変数は主に ~/.bash_profile (あるいは ~/.bashrc) というファイルで設定されます。 環境変数 $XXX の値を yyy に設定するにはこれら設定ファイルに export XXX=yyy と書き、$ source ~/.bash_profile を実行してファイルを読み込み直します。

よい説明はいくらでもあると思うので、詳細は各自で検索して理解してください。

4.3. 環境変数 PATH

$PATH という環境変数は、ディレクトリ (フォルダ) の列を格納しており、シェルなどにコマンドが入力されたときに「実際にどのプログラムを実行するのか」を決定するために用いられます。シェルは、コマンドとして実行すべきプログラムの名前だけ (例: g++) が与えられたとき、そのプログラムが実際にある位置 (例: /usr/bin/g++) を調べるために、$PATH に登録されているディレクトリのみを検査します。

たとえば、GNU C++ コンパイラ (g++) として知られるプログラムの本体であるファイルがハードディスクのどこかに記録されていて、$ g++ main.cpp というコマンドが入力されたとしましょう。 さて実際の g++ はハードディスクのどこにあるでしょうか。 「ハードディスク内のすべてのファイルを調べてまわる」のではかなり非効率です。 そこでシェルは「$PATH に含まれているディレクトリの中だけを調べる」という挙動をします。 たとえば $PATH/usr/local/bin/usr/bin/bin というみっつのディレクトリを含んでいたとします。 このときシェルは、まず /usr/local/bin/g++ 存在するか調べ、次に /usr/bin/g++ が存在するか調べ、のように順番に調べていき、もしファイルが見つかればそれを実行します。 $PATH はたいてい /usr/bin を含んでおり、g++ はたいてい /usr/bin/g++ という位置に保存されているので、$ g++ main.cpp と入力すれば実際にはたいてい /usr/bin/g++ にあるファイルが実行されます。

逆に、いくらプログラムをダウンロードしてきても、それを $PATH に登録されたディレクトリに配置しない限りは、プログラムの名前を入力するだけではそのプログラムを実行することはできません。 新しいプログラムをインストールしたつもりなのに “not found” などと言われて実行ができないときは、たいてい「プログラムがダウンロードされていない」か「プログラムが $PATH に登録されたディレクトリに配置されていない」かのどちらかです。

なお、パソコンの文脈で一般名詞として「パス」や “path” と言うと「ファイルの位置を指し示す文字列」を意味します。たとえば /home/ubuntu/.ssh/config C:\Windows\System32\notepad.exe bits/stdc++.h ./a.out ../../xxx/yyy/zzz.txt などはパスです。この “path” は $PATH とは異なることに注意してください。

よい説明はいくらでもあると思うので、詳細は各自で検索して理解してください。

4.4. alias とシェル関数

alias とは、コマンドに別名を付けるためのシェルの機能です。 alias hoge='echo fuga piyo' と書くと、それ以降は $ echo fuga piyo の代わりに単に $ hoge と書くことができるようになります。

シェル関数とは、シェル (プログラミング言語) の上で定義できる関数です。 たとえば Bash で「受け取った文字列を 2 回出力する関数 echo2」は以下のように書きます。 定義された関数は $ echo2 hello のように呼び出すことができます。

function echo2() {
    echo "$@"
    echo "$@"
}

alias やシェル関数は主に ~/.bashrc というファイルで設定されます。 設定を書き加えた後は $ source ~/.bashrc を実行してファイルを読み込み直す必要があります。 これらは環境変数の設定の場合と同様です。

alias とシェル関数の差は基本的には表現力の差のみです。どちらでも書ける処理はどちらで書いても構いません。ただし、複雑な処理を書くにはシェル関数の方が適しているでしょう。

よい説明はいくらでもあると思うので、詳細は各自で検索して理解してください。

4.5. 確認

それぞれ最大 140 字程度で自分なりの説明を書いてみましょう9

  • 「シェル」がなんであるか説明できる
  • 「ターミナル」がなんであるか説明できる
  • 「シェル変数」がなんであるか説明できる
  • 「環境変数」がなんであるか説明できる
  • 「パス」がなんであるか説明できる
  • $PATH」がなんであるか説明できる
  • 「alias」がなんであるか説明できる
  • 「シェル関数」がなんであるか説明できる

(省略可) 余力のある人は以下もやってみましょう。

  • 基本的なコマンドについて調べて実際に試してみる (例: echo ls cd cp rm cat find grep awk sed man g++ python3 など)
  • man bash を上から下まで軽く眺める
  • Bash 言語で AtCoder の簡単な問題を解く

5. 競プロ特有の環境の構築

ここからが本題です。競プロの便利環境を作っていきましょう。 重要だと思われる順に書かれているので、順番にそれぞれ実際にやってみましょう。

5.1. コンパイルオプションの設定

(C++ を利用する人のみ)

g++ など C++ のコンパイラが持つ便利な機能1112の多くはデフォルトでは無効になっています。オプションが指定されることでそれらは有効になります。 C++ のコンパイラにオプションとして -Wall を指定すると、コンパイル時に怪しいコードを検出して警告してくれます。 さらに -D_GLIBCXX_DEBUG -fsanitize=undefined などを指定すると、実行時に (実行速度と引き換えに) 未定義処理などを検出して警告してくれます。 デバッグの効率が上昇し、レートの上昇に繋がります。レートが上がるので利用しましょう。

多くのオプションを付けるとコマンドが長くなるので、alias を設定しておくと便利でしょう。たとえば以下のようにします。

alias cxx='g++ -std=c++17 -Wall -O2'
alias cxxg='g++ -std=c++17 -Wall -O2 -g -fsanitize=undefined -D_GLIBCXX_DEBUG'

詳細は各自で検索したり公式のドキュメントを読んだりして理解してください。

5.2. デバッガの利用

デバッガとは、デバッグ作業を支援してくれるプログラムのことです。 たとえば「segmentation fault したときの状況 (どの関数がどの順番で呼ばれており、変数にはどのような値が入っていたか) を確認する」「変数の値などを確認しながらプログラムを 1 行ずつ実行する」「プログラムの実行途中で一時的に実行を止め、変数の値を書き換え、続きから再実行する」のような操作ができます。

デバッガには様々なものがあり、たいてい言語ごとに異なるものを使うことになります。有名なのは C++ 用の GDB や Python 用の pdb でしょう131415。またたいていの IDE は、その IDE が注力している言語についてのデバッガ機能を備えています。

GDB を利用するには $ gdb a.out を実行します。 インストールは $ sudo apt install gdb でできます。 詳しい使い方は検索してください。

pdb を利用するには $ python3 -m pdb main.py を実行します。 標準ライブラリの一部であるのでインストール操作は不要です。使い方は公式のドキュメント (pdb — Python デバッガ — Python 3.9.0 ドキュメント) を読んでください。

VS Code 上でデバッガを利用することもできます。 公式のドキュメント (Debugging in Visual Studio Code, Get Started with C++ and Windows Subsystem for Linux in Visual Studio Code) に従って設定しましょう。

(C++ や Python 以外の人は自分で調べてください)

5.3. AC Library の導入

(C++ を利用する人のみ)

AC Library は、AtCoder が公式で提供している C++ のライブラリです。 AtCoder 上でならなにも設定なしで使うことができますが、自分の環境で使うには設定が必要です。 公式のドキュメント (Appendix インストール方法 - AC Library Document) を読み、書かれていることに従って導入しましょう。

5.4. テストの自動化

競プロの問題文中に書かれているサンプルケースを用いたテストを自動で行なったり、コードの提出を自動で行なったりすることのできるツールがあります。便利なので利用しましょう16

これをしてくれるコマンドラインツールとして oj コマンドなどがあります17181920。 公式のドキュメント (README.md - online-judge-tools/oj, docs/getting-started.ja.md) を読み、書かれていることに従って導入しましょう。

コマンドライン上でなく IDE 経由で使いたければ、Competitive Companion と連携して動く IDE プラグインを使うのがおすすめです。公式のページ (README.md - jmerle/competitive-companion) に従い、ブラウザ拡張と IDE のプラグインを選んで導入しましょう。

このようなテストの自動化のためのツールは「手で作成したテストケースを追加する機能」や「プログラムを書いてランダムケースを大量生成する機能」を持っていたり、「インタラクティブ問題のテストを可能にするための機能」を持っていたりします。そのような機能を適切に利用することでデバッグの効率が上昇し、レートの上昇に繋がります。レートが上がるのでこのような発展的機能も使えるようにしておきましょう21

5.5. コード生成の自動化

競プロの問題を解析して main 関数などを自動で生成するツールがあります。便利なので利用しましょう。

これをしてくれるツールとして oj-template コマンドおよび oj-prepare コマンドがあります17221823。 公式のドキュメント (README.ja.md - online-judge-tools/template-generator) を読み、書かれていることに従って導入しましょう。

これらのコマンドはランダムケース生成器の雛形を生成することもできます。 ランダムケースの自動生成とそれを用いたテストが気軽にできるようになれば、レートの上昇に繋がります。レートが上がるのでこの機能も利用しましょう。

5.6. シェルや IDE の設定

シェルや IDE を適切に設定しておくと便利です。 たとえば「コンパイルとサンプルテストの実行を連続してやってくれるシェル関数を用意しておく」「VS Code で保存ボタンを押すと自動でサンプルテストされるように設定しておく」などです。 便利なので設定しておきましょう2425

5.7. 確認

コンテスト本番で使えるようにしておきましょう。

  • (C++ のみ) 未定義動作の発生が自動で検出される
  • デバッガが利用できる。変数の値などを確認しながらプログラムを 1 行ずつ実行できる
  • (C++ のみ) AC Library が使える
  • サンプルケースのテストが自動でできる
  • 自分の手で作ったテストケースでのテストが自動でできる
  • ランダムに大量生成したテストケースでのテストが自動でできる
  • ソースコードのテンプレート (main 関数などを含む) の自動生成ができる
  • これらの機能が簡単に呼び出せる

(省略可) 余力のある人は以下もやってみましょう。

  • (動的型付け言語のみ) 静的型検査器を使えるようにする。「ここどうみても型がおかしいよ」が自動で報告されるようにする
  • linter を使えるようにする。「ここ良くない書き方してるよ」が自動で報告されるようにする
  • code formatter を使えるようにする。コードの整形が自動でされるようにする
  • (ライブラリを自作している人のみ) ライブラリを GitHub で管理して push のたびに自動で verify がされるようにする

注釈

  1. つまり「考え方とかはどうでもいいから答えだけ教えろ」というタイプの人はこの記事を読むべきではありません。 

  2. 他の記事を読む場合でも同様です。まれにですが「数年前の記事の内容をほとんどコピペして書かれた最新の記事」が書かれていることもあるので注意する必要があります。 

  3. Wandbox のようなオンラインコンパイラや AtCoder のコードテスト機能などは、このような「競プロをするための必要最低限の環境」と言えるでしょう。「自分のパソコン上で C++ や Python のコードをコンパイルし実行できるようにすること」は「C++ や Python のコードを書けるようになること」よりはるかに難しいので、プログラミング初心者は初めのうちはオンラインコンパイラで済ませておくのがおすすめです。 

  4. 「環境構築」のうちでレートの上昇に寄与する機能はほとんどがテストやデバッグに関連しています。テストを活用した効率的なデバッグを行うためには、強力なテストケースを用意する能力も要求されます。なお、この能力は作問においても重要です。 

  5. このあたりは、ツール開発に時間をかけすぎている人についても似たことが言えます。 

  6. ちゃんとしたエディタや IDE であればなんでもよい (AtCoder の提出ページのテキストボックスやメモ帳を使わなければなんでもよい) ので、VS Code であることに必然性はありません。他にも Vim や Emacs などはよい選択肢です。私は Vim を使っています。 

  7. VS Code には Vim キーマップを実現するプラグイン VSCodeVim などもあります。 

  8. この他にも、例示されたコマンドを常にそのまま貼り付ければよいというわけではないことに注意しましょう。例として示されたコマンド中の path/to/...YOUR_NAME などは、あなたの環境や状況に応じて修正する必要があります。これは、書類の記入例に「日本花子」や「免許太郎」と書かれていたとしても、そのまま「日本花子」や「免許太郎」と書けばよいということではないことと同じです。 

  9. こういうものを置いておかないと、人間はすぐ手順を飛ばします。  2

  10. 環境変数を定義したつもりでシェル変数のみを定義するというミスは初心者によく見られます。 

  11. コンパイラが持つ便利な機能は、コンパイラごとに異なります。 

  12. すこし不適切です。ここで紹介する _GLIBCXX_DEBUG マクロは、C++ の標準ライブラリの実装のひとつである libstdc++ の機能であり、コンパイラの機能ではありません。このため、標準ライブラリに libc++ を選択している場合は -D_GLIBCXX_DEBUG の代わりに -D_LIBCPP_DEBUG=0 などを使う必要があります。 

  13. C++ のデバッガとしては LLDB も有名です。 

  14. Python のデバッガには PDB 以外にもいろいろあります。ipdb が有名です。 

  15. 私は GDB を使っています。 

  16. サンプルでのテストやコードの提出をただ自動化するだけでは、レートはほとんど上がりません。面倒なサンプルでのテストが省略されてしまうことを防ぐ、出力の目視比較で見間違えることを防ぐ、提出時の言語選択を間違えることを防ぐ、などの効果はありますが、レートへの影響はあまり大きくないはずです。 

  17. 私が作りました。  2

  18. AtCoder 専用でよければ atcoder-tools などを使うこともできます。  2

  19. Codeforces 専用でよければ cf-tool を使うこともできます。 

  20. Rust 専用でよければ tanakh/cargo-atcoder などを使うこともできます。 

  21. AC Library が使えるようになったとたん急にレートが上がったという人はほとんどいないと思います。同様に、便利なツールが使えるようになったとたん急にレートが上がるということはありません。レートを上げる目的で使いたいのならば、それらを効果的に利用する方法を学習しなければなりません。 

  22. この手のツールは必然的に対応言語が少なくなりがちです。自分の使っている言語に対応していない場合は、ツールの開発に参加しましょう。また、自分ですべて作り直すという選択肢もあります。 

  23. Topcoder 専用でよければ Greed を使うこともできます。 

  24. 面倒な作業は省略されてしまうことが多くあります。ある機能を簡単に呼び出せることは、それだけではレートの上昇に繋がりませんが、それによりレートに影響するような重要な作業の省略を防ぐことができるならばレートの上昇に繋がるでしょう。 

  25. 私は設定していません。ある程度シェルに慣れていれば、シェルのヒストリ機能の方が便利であるように感じます。