はじめに
この記事では VSCode 上に C++ での競技プログラミングの環境を構築し、AtCoder や Codeforces 等のコンテストに出る際、ファイルの用意から提出までをサポートできるようにする方法を紹介します。
競技プログラミング用ワークスペースの作成
適当な競プロ用のディレクトリ(ここでは contests
とします)を作成します。
特に言及しない限り、記事内ではこのディレクトリをカレントディレクトリとします。
C++ の環境構築
C++
のインストールについて書かれた記事は大量にあるので、適当に調べて自分の環境に合わせたものをインストールすれば良いです。
Ubuntu であれば build-essential パッケージを多くの場合インストール済みだと思います。これに g++
が同梱されているので、特に何も追加でやらなくて問題ないです。
この記事では g++
で説明していきますが、他の clnag++
でも大きく変わらないと思うので、そちらを使う場合は適宜読み替えてください。
VSCode における C++ の設定
C/C++ をインストールします。
これによって、VSCode 上で簡単にビルドやデバッグ、補完が行えるようになります。
ただし、この記事ではデバッグについては特に説明せず、コードの補完についてはより強力な clangd
を用いるので、基本的にはビルドのためにインストールしています。
コード補完の設定
clangd をインストールします。
これによって、強力なコードの補完が行えるようになります。
他にも色々な機能があるので、興味のある方は以下の記事を参照してみてください。
インストールの際に、先程導入した C/C++ の IntelliSense を無効化するか聞かれると思うので、無効化します。
その後 clnagd
を導入したことが無ければ、インストールするかどうかを聞かれると思うので、そのまま Install
を押してインストールします。
ワークスペース内で補完が効くようにするため .clnagd
というファイルを作成して、以下のようにします。
If:
PathMatch: .*
CompileFlags:
Add:
- --target=x86_64-linux-gnu
- --include-directory=/usr/include/c++/11
- --include-directory=/usr/include/x86_64-linux-gnu/c++/11
# コンパイル時に使用しているものがあれば、ここに追記します
Compiler: g++
環境によって、多少設定する値は変わるので、そのあたりは適当に合わせてください。
また .clangd
では、上記で挙げた記事にもあるように、様々な設定ができるので、好みで設定を追加してください。
追加できる設定については、以下を参照してください。
CompileFlags
で外部ライブラリのインクルードを行う等、ディレクトリやファイルの指定を行うときは、絶対パスで記述してください。
相対パスには対応していません。
フォーマッタの設定
ClangFormat を使ってコードの整形をできるようにしていきます。
.clang-format
ファイルを作成して、以下に従ってルールを作成していきます。
参考
参考程度に、私の設定ファイルを置いておきますが、好みが分かれると思うので、自分で作成する方が良いと思います。
---
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: BlockIndent
AlignArrayOfStructures: Right
AlignConsecutiveAssignments: None
AlignConsecutiveBitFields: None
AlignConsecutiveDeclarations: None
AlignConsecutiveMacros: None
AlignEscapedNewlines: Left
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AllowShortEnumsOnASingleLine: false
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAfterJavaFieldAnnotations: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeConceptDeclarations: true
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakInheritanceList: AfterColon
BreakStringLiterals: false
ColumnLimit: 88
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Regroup
IncludeCategories:
- Regex: ^"(llvm|llvm-c|clang|clang-c)/
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: ^(<|"(gtest|gmock|isl|json)/)
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: .*
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: (Test)?$
IncludeIsMainSourceRegex: ""
IndentAccessModifiers: false
IndentCaseBlocks: false
IndentCaseLabels: false
IndentExternBlock: Indent
IndentGotoLabels: false
IndentPPDirectives: None
IndentRequires: false
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
LambdaBodyIndentation: Signature
Language: Cpp
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PPIndentWidth: -1
PackConstructorInitializers: NextLine
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right
QualifierAlignment: Right
ReferenceAlignment: Pointer
ReflowComments: false
RemoveBracesLLVM: false
SeparateDefinitionBlocks: Always
ShortNamespaceLines: 1
SortIncludes: CaseSensitive
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceAroundPointerQualifiers: Both
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDeclarationName: false
AfterFunctionDefinitionName: false
AfterIfMacros: true
AfterOverloadedOperator: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInCStyleCastParentheses: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: c++17
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: ForContinuationAndIndentation
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
作成したら .vscode
ディレクトリ内の .settings.json
に "C_Cpp.clang_format_style": "file"
を追記して、作成したファイルからフォーマット時のルールを読み込むようにします。
こだわりがなければ "C_Cpp.clang_format_style": "Google"
等とデフォルトで用意されているものから選んで設定する方が楽です。
また、保存時にコードが整形されるようにすると便利なので .settings.json
に "editor.formatOnSave": true
も追記します。
これにより Ctrl
+S
で整形されるようになります。
ここでやったことをまとめると、以下のものが .vscode/.settings.json
に追記されます。
{
"C_Cpp.clang_format_style": "file",
"editor.formatOnSave": true
}
コンテスト用環境の構築
ここからは、問題を解く際のファイルやディレクトリを用意したり、テストケースでの実行を行ったり、コードの提出を行ったり、することを補助するための環境を構築していきます。
online-judge-tools の設定
ここでは online-judge-tools/oj
と online-judge-tools/template-generator
の2つを導入します。
これらについての説明は、以下のURLを見てください。
- https://github.com/online-judge-tools/oj/blob/master/docs/getting-started.ja.md
- https://github.com/online-judge-tools/template-generator/blob/master/README.ja.md
導入方法についてもそれぞれの GitHub に書いてありますが、この記事でも一応記述しておきます。
これらのツールの導入のために pip
等を使えるようにしてください。
pip
等のインストールについての説明は省略します。
また、この記事では uv
を使ってインストールするので、それ以外の場合は適宜読み替えてください。
oj のインストール
下記のコマンドでインストールします。
uv add online-judge-tools
oj でのログイン
コンテストサイトにログインをします。
これによって、コンテスト用のディレクトリの作成や、コードの提出が自動で行えるようになります。
uv run oj login https://atcoder.jp
上記のコマンドを入力すると、AtCoder でのユーザー名とパスワードを求められるので入力します。
[SUCCESS] You have already signed in.
と言うような表示が出れば大丈夫です。
template-generator のインストール
基本的には以下に従います。
下記のコマンドでインストールします。
uv add online-judge-template-generator
VSCode における online-judge-tools の設定
提出等を簡単に行えるようにするため、VSCode のタスクを定義していきます。
シェルスクリプトの作成
タスクとして使いやすいように、コマンドの塊をシェルスクリプトとして定義していきます。
まず configs
ディレクトリを作成し、その中にシェルスクリプトを入れていきます。
コードの提出を行うためのスクリプトを submit.sh
という名前でファイルを作成します。
そのファイルに以下のように書きます。
#!/bin/bash
submit_file=$1 # relative file path (${service_name}/${contest_id}/${problem_id}/main.cpp)
service_name=${submit_file%%/*}
contest_id=$(basename ${submit_file%/*/*})
problem_id=$(basename ${submit_file%/*})
case "$service_name" in
"AtCoder" )
problem_url="https://atcoder.jp/contests/${contest_id}/tasks/${problem_id}"
;;
"Codeforces" )
problem_url="https://codeforces.com/contest/${contest_id}/problem/${problem_id}"
;;
esac
# 環境に応じて書き換える
uv run oj s -y ${problem_url} ${submit_file}
その後 chmod 755 configs/submit.sh
を実行してパーミッションを変更します。
同じように、テストケースのダウンロードを行うためのスクリプトを dltest.sh
という名前でファイルを作成し、以下のように記述して、パーミッションを変更します。
#!/bin/bash
problem_dir=$1 # relative directory path (${service_name}/${contest_id}/${problem_id})
service_name=${problem_dir%%/*}
contest_id=$(basename ${problem_dir%/*})
problem_id=${problem_dir##*/}
test_dir=${problem_dir}/test
case "$service_name" in
"AtCoder" )
problem_url="https://atcoder.jp/contests/${contest_id}/tasks/${problem_id}"
;;
"Codeforces" )
problem_url="https://codeforces.com/contest/${contest_id}/problem/${problem_id}"
;;
esac
if [ ! -e ${test_dir} ]; then
# 環境に応じて書き換える
uv run oj d -d ${test_dir} ${problem_url}
fi
テンプレート等の作成
configs/
ディレクトリに prepare.config.toml
を以下の内容で作成します。
以下に従って適当に追記すると良いです。
contest_directory = "{service_name}/{contest_id}"
problem_directory = "{problem_id}"
[templates]
"main.cpp" = "my_main.cpp"
そして ~/.config/online-judge-tools/template/
ディレクトリに my_main.cpp
を作成します。
これがテンプレートファイルになるので、使いやすいように変更してください。
以下に従ってテンプレートを作成すると、入出力まで自動で書かれたファイルが生成されます。
スタイル等にこだわりがなく、初期のままで良ければ、テンプレートファイルを作る必要はありませんので prepare.config.toml
をそのようにしてください。
組み込みのテンプレートファイル main.cpp
では入出力まで自動で生成されるようになっています。
テンプレートの例(入出力自動化無し)
<%!
import os
from logging import getLogger
import onlinejudge_template.generator.cplusplus as cplusplus
import onlinejudge_template.generator.topcoder as topcoder
import onlinejudge_template.generator.hook as hook
%>\
<%
logger = getLogger(__name__)
data["config"]["indent"] = "\t"
data["config"]["scanner"] = "cin"
data["config"]["printer"] = "cout"
hook.register_filter_command(["sed", "-e", "s/std:://g", "-e", r"s/'\\n'/endl/g"], data=data)
%>\
#include <iostream>
using namespace std;
int main() {
return 0;
}
タスクの登録
.vscode
ディレクトリに tasks.json
を作成し、以下のように記述して保存します。
自身の環境に合わせてコマンドや引数の部分を書き換えてください。
特にコンパイルオプションの部分はかなり好みが出ると思うので、見直すと良いと思います。
これは少し長いので折りたたんでおきます。
タスクの登録
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "build",
"command": "/usr/bin/g++",
"args": [
"-std=c++17",
"-O2",
"-pedantic-errors",
"-Wall",
"-fsanitize=undefined,address",
"-g",
"${file}",
"-o",
"${fileDirname}/a.out"
],
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "compiler: /usr/bin/g++",
"presentation": {
"focus": true
}
},
{
"type": "shell",
"label": "download test cases",
"command": "${workspaceFolder}/configs/dltest.sh",
"args": [
"${relativeFileDirname}"
]
},
{
"type": "shell",
"label": "do oj-prepare",
"command": "uv",
"args": [
"run",
"oj-prepare",
"--config-file",
"configs/prepare.config.toml",
"${input:service_url}/${input:contest_id}"
],
"problemMatcher": []
},
{
"type": "shell",
"label": "do oj test",
"command": "uv",
"args": [
"run",
"oj",
"t",
"-c",
"${fileDirname}/a.out",
"-d",
"${fileDirname}/test"
],
"dependsOn": [
"build",
"download test cases"
],
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"focus": true
}
},
{
"type": "shell",
"label": "submit",
"command": "${workspaceFolder}/configs/submit.sh",
"args": [
"${relativeFile}"
]
}
],
"inputs": [
{
"id": "service_url",
"type": "pickString",
"description": "Contest site URL",
"options": [
"https://atcoder.jp/contests",
"https://codeforces.com/contest"
],
"default": "https://atcoder.jp/contests"
},
{
"id": "contest_id",
"type": "promptString",
"description": "Contest ID"
}
]
}
Ctrl
+Shift
+P
を押して Tasks: Run Task
を選択すると、登録したタスクが出てきて、選択するだけで実行できるようになっています。
一応、使用するタスクを説明しておくと、
-
do oj-prepare
: コンテストのディレクトリ作成とテストケースのダウンロード -
do oj test
: 入力例などによるテスト -
submit
: コードの提出
となっています。
挙げていない他のタスクを直接使用することは、あまりないと思います。
また、始まっていないコンテストで do oj-prepare
はできないので注意してください。
タスクをショートカット一発で実行できるようにする場合は keybindings.json
に適当に追記すればよいです。
私は Ctrl
+Shift
+T
でテストが行えるように設定しています。
あとは実際に問題を解いて提出してみてください。
オプション: 競プロ用ライブラリの include
競プロ用のライブラリを持っており、使う度にコピペをしているという場合は online-judge-tools/verification-helper の oj-bundle を導入すると、コーディング体験がかなり良くなると思います。
これを利用すると include guard を考慮した上で include を自動で展開してくれます。
競プロ用ライブラリのコピー
競プロ用のライブラリを git 等で管理している場合は clone をします。
もし、このコンテスト用のディレクトリを git で管理しようと思っているのであれば submodule の方がよいかもしれません。
git 等で管理していないのであれば、適当にリンクを張ってください。
ここでは競プロ用ライブラリのディレクトリ名を library
と置いて説明していきます。
clangd の修正
補完でライブラリのコードが出るように .clangd
ファイルを修正します。
@@ -6,4 +6,5 @@
- --target=x86_64-linux-gnu
- --include-directory=/usr/include/c++/11
- --include-directory=/usr/include/x86_64-linux-gnu/c++/11
+ - -I<projectDirectoryAbsolutePath>/library
Compiler: g++
<projectDirectoryAbsolutePath>
のところは適宜変えてください。
環境によっては target
や include-directory
の部分も全然違うと思うので、その場合も適宜変更してください。
前述したように、パスは絶対パスで記述しないと読み込まれません。
修正後のファイル
-I
の後に、ライブラリまでのパスを絶対パス書けば良いです。
If:
PathMatch: .*
CompileFlags:
Add:
- --target=x86_64-linux-gnu
- --include-directory=/usr/include/c++/11
- --include-directory=/usr/include/x86_64-linux-gnu/c++/11
- -I<projectDirectoryAbsolutePath>/library
Compiler: g++
online-judge-tools/verification-helper のインストール
このツールに含まれている oj-bundle
は、自作ライブラリから include したものを一つのファイルにまとめる機能があります。
これによって、一つのファイルしか提出できないコンテストサイトでも、問題なく提出できるようになります。
下記のコマンドでインストールします。
uv add online-judge-verify-helper
シェルスクリプトの追加作成と修正
コードを一つのファイルにまとめるためのスクリプトを bundle.sh
という名前でファイルを作成し、以下のように記述して、パーミッションを変更します。
oj-bundle
を使うと #line ...
のような表示や、余分な空行がでてくるので、それらを消す処理も入れています。
#!/bin/bash
file_dir_name=$1
file_basename_no_extension=$2
file_extname=$3
file=${file_dir_name}/${file_basename_no_extension}${file_extname}
bundled_file=${file_dir_name}/${file_basename_no_extension}_bundled${file_extname}
uv run oj-bundle -I library ${file} \
| grep -v '^#line ' \
| cat -s \
| sed -e '1{/^$/d}' \
| clang-format --style=file \
> ${bundled_file}
configs/submit.sh
がバンドル前のファイルを提出するようになっているので、バンドル後のファイルを提出するように修正します。
@@ -1,10 +1,15 @@
#!/bin/bash
-submit_file=$1 # relative file path (${service_name}/${contest_id}/${problem_id}/main.cpp)
+file_dir_name=$1
+file_basename_no_extension=$2
+file_extname=$3
-service_name=${submit_file%%/*}
-contest_id=$(basename ${submit_file%/*/*})
-problem_id=$(basename ${submit_file%/*})
+file=${file_dir_name}/${file_basename_no_extension}${file_extname}
+bundled_file=${file_dir_name}/${file_basename_no_extension}_bundled${file_extname}
+
+service_name=${file%%/*}
+contest_id=$(basename ${file%/*/*})
+problem_id=$(basename ${file%/*})
case "$service_name" in
"AtCoder" )
@@ -15,4 +20,4 @@ case "$service_name" in
;;
esac
-uv run oj s -y ${problem_url} ${submit_file}
+uv run oj s -y ${problem_url} ${bundled_file}
修正後のファイル
#!/bin/bash
file_dir_name=$1
file_basename_no_extension=$2
file_extname=$3
file=${file_dir_name}/${file_basename_no_extension}${file_extname}
bundled_file=${file_dir_name}/${file_basename_no_extension}_bundled${file_extname}
service_name=${file%%/*}
contest_id=$(basename ${file%/*/*})
problem_id=$(basename ${file%/*})
case "$service_name" in
"AtCoder" )
problem_url="https://atcoder.jp/contests/${contest_id}/tasks/${problem_id}"
;;
"Codeforces" )
problem_url="https://codeforces.com/contest/${contest_id}/problem/${problem_id}"
;;
esac
uv run oj s -y ${problem_url} ${bundled_file}
タスクの修正
tasks.json
を修正して、バンドルしたファイルを提出するようにします。
@@ -12,6 +12,8 @@
"-Wall",
"-fsanitize=undefined,address",
"-g",
+ "-I",
+ "./library",
"${file}",
"-o",
"${fileDirname}/a.out"
@@ -79,7 +81,22 @@
"label": "submit",
"command": "${workspaceFolder}/configs/submit.sh",
"args": [
- "${relativeFile}"
+ "${relativeFileDirname}",
+ "${fileBasenameNoExtension}",
+ "${fileExtname}"
+ ],
+ "dependsOn": [
+ "do oj-bundle"
+ ],
+ },
+ {
+ "type": "shell",
+ "label": "do oj-bundle",
+ "command": "${workspaceFolder}/configs/bundle.sh",
+ "args": [
+ "${relativeFileDirname}",
+ "${fileBasenameNoExtension}",
+ "${fileExtname}"
]
}
],
修正後のファイル
{
"version": "2.0.0",
"tasks": [
{
"type": "cppbuild",
"label": "build",
"command": "/usr/bin/g++",
"args": [
"-std=c++17",
"-O2",
"-pedantic-errors",
"-Wall",
"-fsanitize=undefined,address",
"-g",
"-I",
"./library",
"${file}",
"-o",
"${fileDirname}/a.out"
],
"problemMatcher": [
"$gcc"
],
"group": {
"kind": "build",
"isDefault": true
},
"detail": "compiler: /usr/bin/g++",
"presentation": {
"focus": true
}
},
{
"type": "shell",
"label": "download test cases",
"command": "${workspaceFolder}/configs/dltest.sh",
"args": [
"${relativeFileDirname}"
]
},
{
"type": "shell",
"label": "do oj-prepare",
"command": "uv",
"args": [
"run",
"oj-prepare",
"--config-file",
"configs/prepare.config.toml",
"${input:service_url}/${input:contest_id}"
],
"problemMatcher": []
},
{
"type": "shell",
"label": "do oj test",
"command": "uv",
"args": [
"run",
"oj",
"t",
"-c",
"${fileDirname}/a.out",
"-d",
"${fileDirname}/test"
],
"dependsOn": [
"build",
"download test cases"
],
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"focus": true
}
},
{
"type": "shell",
"label": "submit",
"command": "${workspaceFolder}/configs/submit.sh",
"args": [
"${relativeFileDirname}",
"${fileBasenameNoExtension}",
"${fileExtname}"
],
"dependsOn": [
"do oj-bundle"
],
},
{
"type": "shell",
"label": "do oj-bundle",
"command": "${workspaceFolder}/configs/bundle.sh",
"args": [
"${relativeFileDirname}",
"${fileBasenameNoExtension}",
"${fileExtname}"
]
}
],
"inputs": [
{
"id": "service_url",
"type": "pickString",
"description": "Contest site URL",
"options": [
"https://atcoder.jp/contests",
"https://codeforces.com/contest"
],
"default": "https://atcoder.jp/contests"
},
{
"id": "contest_id",
"type": "promptString",
"description": "Contest ID"
}
]
}
これで提出時にバンドルされたファイルが提出されるようになりました。
おわりに
これらの環境構築を行うと、問題を解くこと以外に取られる時間はかなり減ると思います。
面倒だなと感じる箇所があればどんどん変えていって、自分にとってやりやすい環境を作っていきましょう!
今回紹介したツール以外にも、競プロ用の便利なツール等がたくさんあるので、吟味してみると良いかもしれません。