VSCodeで競技プログラミング向けC++の作業環境をつくってみた。

#VSCodeで競技プログラミング向けC++環境のおすすめ環境

とても参考になった以下の記事を自分なりに改良してみました。
競技プログラミングやLinux環境を始めたばかりなのでアドバイス等ありましたら、コメントの方よろしくお願いします。

[Visual Studio Codeで競プロ環境構築(導入編)](https://qiita.com/AokabiC/items/e9312856f588dd9303ed)
[Visual Studio Codeで競プロ環境構築(実践編)](https://qiita.com/AokabiC/items/af685bfd205dda44ec45)
[VSCodeでの競プロ向けC++環境をWSLにRemote Developmentする形で作る]
(https://qiita.com/yoyomion/items/ed60a89009616f2efd55)



基本的には記事通りですが、過去に書いたコードをわかりやすく分類できるようにしました。
参考にされる方がいましたら幸いです。

##準備
まず、[Visual Studio Codeで競プロ環境構築(導入編)](https://qiita.com/AokabiC/items/e9312856f588dd9303ed)を参考に、環境構築を頑張ってください。

次に[Visual Studio Codeで競プロ環境構築(実践編)](https://qiita.com/AokabiC/items/af685bfd205dda44ec45)を参考にC++環境を整えてください。

今回は自動でサンプルケースを検証する機能を付けたいので、こちらの自動ツールを使う。([Visual Studio Codeで競プロ環境構築(実践編)](https://qiita.com/AokabiC/items/af685bfd205dda44ec45)の最後の*最後の自動でサンプルケースを検証する*で使っているツールです。)[online-judge-toolsを導入](https://online-judge-tools.readthedocs.io/en/master/introduction.ja.html)


#ソースコードをビルドするまで

##フォルダ構成
VSCodeのワークスペースフォルダはwslのルートからこの位置にあると思います。

``` bash:フォルダー構成
wsl/
└── home/
    └── foo/
        └── workspace/
```
これをVSCodeのワークスペースに以下のような構造を創っていきます。

``` bash:フォルダー構成
.workspace
├── Makefile  # 新規作成
├── scr  # 実行ファイル置き場(最初は中身が空)
│   ├── abc114_a # こんな名前のファイルが作られていく
│   └── abc114_b
├── cptest_atcoder.sh  # ツールを使ってデバッグする
├── atcoder.sh  # 新しいコンテスト用に使う
├── ord_source # 過去に解いた.cppを中に収納する
├── library
├── template
│   ├── temp.cpp # このファイルをコピーして問題用のファイルを作る
│   └── input.txt # ここに書いてある入力を使ってデバッグする
├── work
│   └── Contestname # このフォルダの名前がコンテスト名になる
│        ├── a.cpp # ここで問題を解く
│        └── b.cpp
└── src  # ソースコード置き場 全部フラットに配置するように変更
    ├── bin # 実行ファイル置き場
    │    ├── a
    │    └── b
    └── test  # AtCorderから自動取得したテストケース置き場(最初は中身が空)
        ├── abc114_a # こんな名前のフォルダーやファイルが作られていく
        │   ├── sample-1.in
        │   ├── sample-1.out
        │   ├── sample-2.in
        │   └── sample-2.out
        └── abc114_b
            ├── sample-1.in
            ├── sample-1.out
            ├── sample-2.in
            ├── sample-2.out
            ├── sample-3.in
            └── sample-3.out
```
 cptest_atcoder.shとatcoder.shはあとでエイリアスを通します。
#ビルドとデバッグ

次に.vscodeの中の設定ファイルを構築していきます。
とりあえず`F5`を押します。
`C++ (GDB/LLDB)`からの`g++-7 build and debug active file`を押してみます。まあ、どれ選んでもいいです。

これで、`.vscode/launch.json`と`.vscode/tasks.json`ができているので、これらを編集します。

```json:launch.json
{
    // IntelliSense を使用して利用可能な属性を学べます。
    // 既存の属性の説明をホバーして表示します。
    // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "g++-9 - アクティブ ファイルのビルドとデバッグ",
            "type": "cppdbg",
            "request": "launch",
            "program":"${workspaceFolder}/scr/bin/${fileBasenameNoExtension}",
            "args": [
                "<",
                "${fileDirname}/input.txt"
            ],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}/scr/bin",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb",
            "setupCommands": [
                {
                    "description": "gdb の再フォーマットを有効にする",
                    "text": "-enable-pretty-printing",
                    "ignoreFailures": true
                }
            ],
            "preLaunchTask": "g++-9 build active file",
            "miDebuggerPath": "/usr/bin/gdb"
        }
    ]
}
```
初期ファイルとだいぶ変わっているので、気を付けてください。
`${workspaceFolder}とかのいみは[VS Codeの設定をキレイに変数置換](https://qiita.com/ShortArrow/items/dc0c8cacd696154510f1)を参照するとわかりやすいと思います。

```json:tasks.json
{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "test_atcorder_sample",
            "type": "shell",
            "command": "cptest ${workspaceFolderBasename}",
            "problemMatcher": [
                "$gcc"
            ]
        },
        {
            "label": "test_manual_input",
            "group": {
                "kind": "test",
                "isDefault": true
            },
            "type": "shell",
            "command": "make",
            "args": [
                "problem=${fileBasenameNoExtension}",
                "run"
            ]
        },
        {
            "type": "shell",
            "label": "cd",
           
            "command": "cd",
            "args": [
                "${workspaceFolder}"
            ],
        },

        {
            "type": "shell",
            "label": "g++-9 build active file",
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "command": "make",
            "args": [
                "problem=${fileBasenameNoExtension}"
            ],
            "problemMatcher": [
                "$gcc"
            ],
            "dependsOn": [
                "cd"
            ]
        }
    ]
}
```

色々変わっているのでコピペおすすめです。
各要素の意味は書くのが面倒になってきたので調べてください。知っておくと、うまく動かなくなったときに自分で直せます。

Makefileがないと動かないので、Makefileを編集します。

```Makefile
# 例：
# make problem=a
# これでaという実行ファイルが作れる

# 例2：
# make problem=a run
# これでabc111_aという実行ファイルが作れて、input.txtを入力として受け取り動く

all: scr/bin/${problem}
.PHONY : all

# aという実行ファイルを作るためには./src/a.cppが必要
scr/bin/${problem}: work/*/${problem}.cpp
	g++ -g -O0 -std=c++14 -o scr/bin/${problem} work/*/${problem}.cpp

# aという実行ファイルを動かすためにはaが必要
run: scr/bin/${problem}
	./scr/bin/${problem} < input.txt

```




### サンプル検証するスクリプト
[Visual Studio Codeで競プロ環境構築(実践編) - Qiita](
https://qiita.com/AokabiC/items/af685bfd205dda44ec45#%E8%87%AA%E5%8B%95%E3%81%A7%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%82%B1%E3%83%BC%E3%82%B9%E3%82%92%E6%A4%9C%E8%A8%BC%E3%81%99%E3%82%8B)
を使わせてもらって、ちょっと変更して下記を作りました。
スクリプト内でログインするため、username、passwordを自分のものに書き換えてください。

```bash:cptest_atcoder.sh
#!/bin/bash
cd /home/foo/workspace
workpath="work/*"
folderpath=`find $workpath -type d`
contestname=`basename $folderpath`

problemfilepathes="work/*/*"
problempath=`find $problemfilepathes -type f -name \*${1}.cpp`
problemfile=`basename $problempath`
programname="${problemfile:0:1}"

problemname="${contestname}_${programname}"
echo "${contestname} ${programname}"
 

# 企業コンテストの場合、下記のようにtasksの前はハイフンになるため対策する
# https://atcoder.jp/contests/ddcc2020-qual/tasks/ddcc2020_qual_a

baseurl=${problemname:0:-2}
baseurlreplaced=${baseurl//_/-}

cd /home/foo/workspace
# 本番中に使うためにログインする
oj login -u username -p password "https://atcoder.jp/" 
# username, passwordは適切な文字列にする
oj login --check "https://atcoder.jp/"

queurl="https://atcoder.jp/contests/${baseurlreplaced}/tasks/${problemname}"

# testディレクトリがなければ取得する
if [ ! -e scr/test/${programname} ]; then
  oj dl -d scr/test/${programname}/ ${queurl} > /dev/null
fi

make "problem=${programname}"

oj test -c "./scr/bin/${programname}" -d scr/test/${programname}/
```

###新規のコンテストを始める前に

新たにコンテストを始めるときに`atcoder contestname`とすることで、
`test/`と`bin/`の中身を消し、`work`内を`ord_source`に移動。
`template`から新しいコンテスト用のフォルダを`work`内に配置するスクリプトを書きます。

```bash:atcoder.sh
#!/usr/bin/bash
cd /home/yudai/Atcoder_Cpp

rm -f scr/bin/* 
rm -f scr/test/* 

cp -r work/* ord_source/
rm -r work/*

cp -r template work/"$1"
cd work/"$1"

for index in a b c d e f
do
  cp temp.cpp $index.cpp 
done
rm temp.cpp
```

###エイリアスの設定
エイリアスとは変数みたいなもので`alias ll='ls -s'`とすることで`ls -s`というコマンドを`ll`で実行できるようになります。

エイリアスは`/home/user/.bashrc`を書き換えることで設定します。
bashで`sudo vi /home/user/.bash`を実行し、

```bash:.bashrc
…
…
alias ll='ls -l'
alias cptest='/home/foo/workspace/cptest_atcoder.sh' # 追加
alias atcoder="/home/foo/workspace/atcoder.sh" # 追加
```

###まとめ
始め方はまず、bashに`atcoder contestname`と打ちます。
例えば、`atcoder abc123`と打てば、`work/abc123`がa.cppからf.cppまでできて、これらを編集していきます。

デバッグの時は、
`ctrl+shift+B`でコンパイル
`F5`でinput.txtを入力したときのデバッグ
`cptest a`でa問題の自動テスト（本当はツールに自動提出機能があるため、ここで全問正解したら自動で提出ができるようにしたかったが、謎のエンコードエラーがでて実装できなかった）

大体こんな感じです。

また新しいコンテストを始めるときは、`atcoder newcontestname`を打てばいいです。
そしたら、自動でabc123フォルダがord_sourceに格納されます。

VSCodeはworkspaceを開いて使用してください。
また、workspaceのフォルダを名は自動で取得するため、どんな名前でも構いません。