VSCodeで競技プログラミング 〜インストールからショートカットで自動サンプルテスト&提出まで〜

Table of Contents

はじめに

この記事はCompetitive Programming (1) Advent Calendar 2019の20日目として書かれました。

競技プログラミング勢は、コーディングの際のツールを使いこなしている人とそうでない人の差が大きいイメージがあります。 昔ICPCのチームメイトがメモ帳でプログラミングをしていた話を思い出し、そういった人の助けに少しでもなればいいなと思いこの記事を書きました。

なお、競プロには様々な向き合い方があり、こういうツールを必ず導入するべきだとはもちろん思っていません。 強い人でも全く使っていない人もいるので自分の好きなスタイルでやっていくのが一番だと思います。

今回の記事のメインターゲットは、
コンパイル (→ 実行 → サンプルをコピー → サンプルをペースト → 目で出力があっているか確認) *3~4回 → ソースコードをコピー → ソースコードをペースト→提出
の流れを毎回繰り返していて面倒くさいと思っている人です。 拡張機能のCode Runnerのショートカットの設定まででもやれば効率が大きく上がると思います。

使用言語はC++でMac環境を想定して書かれていますが、WindowsでもWSLを使えばほぼ同じことができるはずです。

インストール

公式サイトからインストールしましょう。 (今回は触れませんが、Macの場合はHomebrew Caskを使うとコマンドラインだけでインストールすることもできるので便利です)

拡張機能・設定

まず、拡張機能を2つインストールしてその設定をしていきましょう。

  • C/C++ C++のシンタックスハイライトなどをしてくれます。
  • Code Runner ソースコードがショートカットで実行できるようになります。

C/C++はインストールするだけで使えるようになるので、Code Runnerの設定をします。 まずCode->Preferences->Settingsを開いてsettings.jsonを編集しましょう。

// settings.json
{
    "code-runner.runInTerminal": true,
    "code-runner.executorMap": {
        // 自分で実行したいコマンドを設定する
        // $dir, $fileNameはそれぞれ編集中のファイルのディレクトリ、ファイル名を表す
        "cpp": "cd $dir && g++ -O0 -std=c++14 -D_MY_DEBUG -D_GLIBCXX_DEBUG $fileName && ./a.out",
    },
    "code-runner.saveFileBeforeRun": true,
    "code-runner.preserveFocus": false,
    "code-runner.ignoreSelection": true,
}

とりあえずこれでCode Runnerの設定ができました。

次にショートカットの設定をします。 Code->Preferences->Keyboard Shortcutsからkeybindings.jsonを編集しましょう。

// keybindings.json
[
  {
    "key": "ctrl+c",
    "command": "code-runner.run"
  },
]

これでC++のソースコード編集画面からctrl+cを押すとCode Runnerでコードが実行されるようになりました。 ここまで設定すれば競技プログラミングをするにあたって最低限の環境が構築できたと言っていいでしょう。

あとは、自分で試行錯誤しながら他の拡張機能なども入れてみると良いかもしれません。 自分はVimを入れています。

また、その他の設定も使いながら自分の好きなように変えていくと良いと思います。 参考までに、自分の設定の中で競プロ用に使っているものを載せておきます。

// settings.json
{
    // 以下参考
    // エディタ全般
    "editor.insertSpaces": true,
    "editor.tabSize": 4,
    "editor.minimap.enabled": false,
    "editor.acceptSuggestionOnCommitCharacter": false,
    "editor.formatOnSave": true,
    "editor.autoClosingOvertype": "always",
    "files.autoSave": "afterDelay",
    // VSCodeのUI
    "workbench.statusBar.visible": true,
    "workbench.activityBar.visible": true,
    "workbench.sideBar.location": "left",
    "workbench.startupEditor": "newUntitledFile",
    "workbench.panel.defaultLocation": "right",
    "workbench.settings.editor": "json",
    "workbench.settings.openDefaultSettings": true,
    // vim
    "vim.visualstar": true,
    "vim.hlsearch": true,
    "vim.leader": "<space>",
    "vim.easymotion": true,
}

ちなみにVSCodeではグローバルの設定とプロジェクト内のみに反映されるローカルの設定をすることができ、今回設定したのはグローバルのものです。

また、VSCodeはjsonファイルとGUIの両方で設定を変更することができます。 設定をバージョン管理できたり新しく環境構築する際にラクといった点から、jsonファイルを使うのが良いと思います。

自動フォーマット

C/C++ではclang-formatにもとづいたフォーマッティングに対応していて、settings.json

// settings.json
{
    "editor.formatOnSave": true,
}

を設定すると保存時に自動でフォーマットしてくれるようになります。 .clang-formatという設定ファイルをプロジェクト内に置いておくことでスタイルを変更することもできます。 自分は以下の設定で使っています。

---
BasedOnStyle: Google
IndentWidth: 4
AccessModifierOffset: -4
AllowShortCaseLabelsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: true
ColumnLimit: 120
AlwaysBreakTemplateDeclarations: false
---
  • コーディング中にフォーマットについて脳のリソースを割かなくて済む
  • スタイルを変えたときにライブラリなどを一括で変更できる
  • 他人のライブラリなどを貼り付けるときにスタイルを自分のものに合わせられる

などがフォーマッタを使うメリットだと思います。

競プロ界隈はフォーマッタを使用している人が少ないイメージがあるので、ぜひ皆さん使っていきましょう。

スニペット作成

VSCodeには、自分でkeyとして設定したワードをタイプしたときに、対応するコード片を貼り付けてくれるというスニペット機能があります。 ただこれを使うには独自のjsonファイルを作成しなければならず、ライブラリをこのように管理していると同期が取りづらいというデメリットがあります。

そのためテキストファイルがたくさん入ったディレクトリからスニペットを作成するスクリプトを書きました。
https://github.com/knshnb/vscode_snippet_generator
スニペット化したいファイルの入ったディレクトリに対して実行することで、cpp.jsonが出力されます。
これをCode->Preferences->User Snippetsから設定することで、自分が普段から管理しているライブラリなどのスニペットが使えるようになります。

競プロ用ツールの導入

AtCoderとCodeforcesでサンプルの自動テスト・提出ができるようにします。

AtCoder

まず、AtCoder用に@kyuridenamidaさんが作成しているAtCoder Toolsを導入します。 書いてあるとおりにpip3 install atcoder-toolsでインストールして~/.atcodertools.tomlに設定を保存してください。 これでatcoder-toolsのコマンドが使えるようになりました。

それでは、atcoder-tools testatcoder-tools submitのコマンドをtaskとして登録してショートカットで呼び出せるようにしましょう。 新しく作られるプロジェクト内の.vscode/tasks.json

// tasks.json
{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "competitiveTestSample",
      "type": "shell",
      "command": "cd ${fileDirname} && g++ -O0 -std=c++14 -D_GLIBCXX_DEBUG ${fileBasename} && atcoder-tools test",
      "presentation": {
        "reveal": "always",
        "focus": true,
        "panel": "shared",
      }
    },
    {
      "label": "competitiveSubmit",
      "type": "shell",
      "command": "cd ${fileDirname} && g++ -O0 -std=c++14 -D_GLIBCXX_DEBUG ${fileBasename} && atcoder-tools submit -u",
      "presentation": {
        "reveal": "always",
        "focus": true,
        "panel": "shared",
      }
    }
  ]
}

が保存されるように.vscode/tasks.jsonを適当な場所に保存し、~/.atcodertools.toml

exec_on_contest_dir='ln -s ../.vscode ./.vscode && code .'

などと書いておきましょう。 これで、atcoder-tools gen {contest id}のコマンドを呼んだときに自動でプロジェクト内でtaskが設定されるようになります。

最後に、グローバルのkeybindings.json

[
  {
    "key": "ctrl+t",
    "command": "workbench.action.tasks.runTask",
    "when": "editorTextFocus",
    "args": "competitiveTestSample"
  },
  {
    "key": "ctrl+s",
    "command": "workbench.action.tasks.runTask",
    "when": "editorTextFocus",
    "args": "competitiveSubmit"
  },
]

を追加しましょう。 これで、

  • ctrl+t: 自動サンプルテスト
  • ctrl+s: サンプルテストが成功したら自動提出

が行われるようになります。

Codeforces

Codeforces用にはこちらのツールを使います。 https://github.com/xalanq/cf-tool/releases からバイナリをダウンロードするのが楽だと思います。

cf configから指示に従って設定をして、AtCoderと同じように

{
  // See https://go.microsoft.com/fwlink/?LinkId=733558
  // for the documentation about the tasks.json format
  "version": "2.0.0",
  "tasks": [
    {
      "label": "competitiveTestSample",
      "type": "shell",
      "command": "cd ${fileDirname} && cf test",
      "presentation": {
        "reveal": "always",
        "focus": true,
        "panel": "shared",
      }
    },
    {
      "label": "competitiveSubmit",
      "type": "shell",
      "command": "cd ${fileDirname} && cf submit",
      "presentation": {
        "reveal": "always",
        "focus": true,
        "panel": "shared",
      }
    }
  ]
}

が新しいプロジェクトごとにコピーされるようにしましょう。 AtCoder Toolsのexec_on_contest_dirのような機能がなかったので、自分は以下のようなシェルスクリプトを使っています。

#!/bin/sh

cf race $1
for dir in `ls $1`;
do
    # 問題ごとにテンプレートファイルを作成
    # 自分の設定に合わせて書き換える
    cp ~/.competitive_template.cpp ./$1/$dir/main.cpp
done
cd $1
ln -s ../.vscode ./.vscode && code .

これで、このシェルスクリプトで作成したプロジェクト内で、さきほどkeybindings.jsonで設定したショートカットが同じように使えるようになりました。 submitの仕様が異なり、cf-toolでははsubmitの際にtestが行われないことに注意してください。

以上で、ショートカットのみでサンプル自動テスト→提出ができるようになりました。 競技プログラミングをやっていると何度も行う作業なので、1度設定すると捗ると思います。

終わりに

お疲れさまでした。
自動テストツールなどを作ってくださっている方には感謝しています。
さらに便利になる方法などがあればtwitterで教えていただけると助かります。