やることはタイトルの通りです。
LinuxやMacではBashだったりで色々便利なことだったりシェル芸人ができますがWindowsはBashが使えません(すべてはWSLを使えば解決しますが...)。
そこで、Windowsで似たような事ができるbatファイル(とPython)を使って競技プログラミング用の便利ないろいろを作ります。
前提として...
- パスの通し方を知っている
- 超かんたんなbatファイルなら普通にかける
- 競技プログラミングで結構フォルダやファイルを作る(書き捨てじゃなく過去のコードを保存している)
ような人を対象としています。
crun
コンテストに出るときはPythonで書いたほうがいい場面でもC++で書いています。
でもC++のコンパイルって結構面倒なんですよね。
Rustを使っている場合はcargo runを呼んでしまえばコンパイルから実行まで自動でやってくれますし、VSCode + Pythonならctrl+F5を押すだけでいいです。(C++でも同じようにできる設定がありますが面倒でやってないんです。)
エディタにVSCodeを使っていますが、コードを書き終わってctrl + ~
を押してg++ code.cpp
を打ってa
を打ってctrl + v
でサンプルをコピーして...とかなり動作が多いです。
手始めにこいつを自動化します。
@echo off
g++ -std=gnu++17 "%1"
makecase.py
a < "%~d1%~p1in.txt"
@echo off
でエコーバックを無効化しています。
これがないと後にcallで呼んだ処理がすべてVSCodeのターミナル上に出力されます。
結構スクロールするので前の出力結果と見比べたいときなどは面倒です。
コンパイル
次にg++を呼びます。
C++17でコンパイルするようにしています。
ここで使っている%1
を使うことでコマンドプロンプトからの引数を受け取ることができます。
正確には%0
から存在するのですが%0
はバッチファイルを呼び出すコマンドが必ず格納されるので実際にユーザーが使える引数は%1
からになります。
入力データの生成
次にmakecase.py
というPythonのスクリプトを呼んでいます。
import pyperclip
p = "in.txt"
f = open(p, "w", encoding = "UTF-8")
text = pyperclip.paste()
f.write(text)
f.close()
中身はこの様になっていて、現在クリップボードにクリップされている情報をtxtファイルに出力します。
ここでファイルの出力先を指定していませんが、pythonのファイル(or コマンド)が呼ばれたcmdのディレクトリが参照されるので特別指定する必要はありません。
このmakecase.pyというのはソースコードがあるディレクトリと全く違うパスの通った別ディレクトリにありますが、しっかりとソースコードのあるディレクトリに入力データを生成してくれます。
実行
最後にa < "%~d1%~p1in.txt"
で実行し、in.txt
にペーストされた入力データを標準入力に流します。
わざわざここで入力ファイルを作った理由ですが、Windowsにはクリップボードの情報をペーストするコマンドがないからです。
LinuxやMacにはあるのですが、Windowsはクリップボードにコピーすることしかできません。
なので、別に入力ファイルを作ってやらないといけなかったわけです。
使い方
クリップボードに入力データをコピーかつcmdのディレクトリをソースコードのあるディレクトリに移動させた上で以下のコマンドを打ちます。
crun [ソースコード名]
コマンドを実行すると標準出力だけが出てきます。
ちなみにプログラムが間違っていたりするとエラーが出てきます。
それ以前にコンパイルなどをしていなければいいのですが、していてすでにディレクトリにa.exe
が存在する場合はそれが呼ばれてしまうので落ち着いてctrl + z
で抜けます。
そこまで便利?
実際そこまで必要なものでもありませんが、出力がちょっと面倒なときにこのcrunを使うと結構わかりやすくなります。
例えば ABC212 - D - Querying Multiset という問題は普通にコピーペーストすると入力と出力がごっちゃになります。
もともとはこのような入力をして下の出力が得られればいいわけですが、
コピーペーストで実行すると以下のようになります。
入力と出力が混ざってしまいました。
このように、入力の途中で出力を行うようなコードを書くと上のようなことになってしまいます。
AtCoderなどではこのような形式で出力させられることが随分少ないように感じますが、Codeforcesなどではテストケース数が事前に伝えられてその分だけ入力と出力がある...という形式になっているので上のようなことが毎回起こります。
これは、コマンドプロンプトが1行ずつ入力をa.exeに送っているのが原因で最初に一括で入力を読むようなコードにすればいいですが、わざわざそんなことをするのも面倒です。
しかしここでcrunコマンドを使うと...
こんな感じに標準出力だけがされます。
入力ログがないだけでかなり見やすくなります。
crunの説明はこれくらいにして次のbatファイルに行きます。
cpdir
いわゆるmkdirの強化版みたいなやつです。
これくらいなら競技プログラミングをやってる人で持ってる人も多いかもしれません。
mkdir同様cpdir [ディレクトリ名]
と打つことで新しくディレクトリを作ってくれます。
違うのはその後。
テンプレートが記載されたcppファイルをコピーしてきて、cmdのディレクトリを作成したディレクトリに変更してVScodeで開くところまで自動でやってくれます。
普段コンテストに参加するときはマウスを使って新規ファイルやフォルダを作成して回るのが面倒なのでだいたいmkdirやcdを多用していますがけっこうだるいので自動化しました。
@echo off
mkdir "%1"
XCOPY "D:\bash\template\code.cpp" "%1"
cd %1
code "code.cpp"
ディレクトリを作る
言わずもがなmkdirを使います。
ここまでは普通に自分でコマンドを打つのと変わりません。
テンプレートを持ってくる
別に持ってこなくてもVSCodeにスニペットがあるのでatc
と入力してEnterを押すと勝手にテンプレートが出てくるのですが、面倒なのでそれも自動化します。
XCOPY
というコマンドを使っていますがcopy
の上位互換だと思ってもらえれば良いです。
ディレクトリの移動
これもおなじみ。
cd
で移動します。
VSCodeで開く
VSCodeはインストールするとPathを通してくれるのでcode
コマンドを使ってVSCodeを開くことが可能です。
引数に渡してやるとそのファイルを自動で開いてくれますし、そこにないファイル名を指定したときはそのファイルを作成してくれます。(正確にはcodeコマンドを打ったときに作成されるのではなく、開かれたファイルを保存したときに新たに作成されます。)
使ってみると便利なbatファイルたち
今までほとんど使ったことがなかったんですが、初めてまともにbatファイルを書きました。
わかってくるといい感じに自動化が捗るのでみなさんもよかったら使ってみてください。