どうも、退職アドカレを書こうと思ってエントリーだけして逃げた者です。
必要なもの
- Emacs
- 好きな言語の環境 (私の場合 Rust)
- emacs-quickrun
emacs-quickrun の標準入力
前述の emacs-quickrun では ソースファイル名(含拡張子).qrinput
としてファイルを定義すると、そのファイルの内容が実行時に標準入力として渡されるようになります。しかし、この仕様では標準入力を1つまでしか用意できません。
そこで、 AtCoder が用意する2~3のテストケースを一括でテストする方法を考えました。
テストスクリプト
詳しい実装はあまりにも自明なので説明しません。
カレントディレクトリから input-*.txt
と output-*.txt
を探してそれぞれにテストを実行します。
# !/usr/bin/env bash
set -u
IFS=$'\n\t'
# run-tests.sh --- Run AtCoder test cases
# author: Seong Yong-ju <sei40kr@gmail.com>
red="$(tput setaf 1)"
green="$(tput setaf 2)"
yellow="$(tput setaf 3)"
bold="$(tput bold)"
reset="$(tput sgr0)"
cmd="$@"
buffile="$(mktemp)"
errfile="$(mktemp)"
shopt -s nullglob
for infile in input-*.txt; do
outfile="output-${infile:6}"
if [[ ! -f $outfile ]]; then
continue
fi
echo -n "${infile} - "
eval "${cmd[@]}" <"$infile" 1>"$buffile" 2>"$errfile"
if [[ "$?" != 0 ]]; then
cat <<EOM
${bold}${red}err${reset}
error output:
$(cat "$errfile")
EOM
break
fi
if diff -q "$buffile" "$outfile" >/dev/null; then
echo "${bold}${green}ok${reset}"
else
cat <<EOM
${bold}${yellow}ng${reset}
expected:
$(cat "$outfile")
actual:
$(cat "$buffile")
EOM
fi
done
rm -f "$buffile" "$errfile"
本当はTLEのチェックもしたかったのですが、まあいいや。
テストケースを用意する
こんな感じで。
5 2
1 7
1 10 0
ちなみにこれを自動化するために、 Python でツールを書きました。
https://github.com/sei40kr/atcoder-scraper
$ atcoder-scraper https://atcoder.jp/contests/abc090/tasks/arc091_b
こんな感じです。ちなみにこれの完全上位互換のツールが存在することを作った後に知りました。
https://github.com/kyuridenamida/atcoder-tools
Spacemacs の quickrun レイヤー
今言っても仕方ありませんが、以前は Spacemacs の quickrun 用のレイヤーを作っていました。
ソースコードのファイル名(含拡張子).qrinput*
形式のファイルが複数ある場合に helm で選べるようにするものです。
https://github.com/sei40kr/spacemacs-quickrun
.dir-locals.el の設定
ソースコードを置いているプロジェクトの先祖ディレクトリのどこかに .dir-locals.el
を用意して、 quickrun の実行コマンドを書き換えます。
プロジェクトのルートを特定するために eval
を使ってます。適宜変更してください。
ちなみに 1.15.1
は AtCoder の Rust のバージョンです。 rustc --emit=mir
がないので同じバージョンでLinterを動かせない...。
;;; .dir-locals.el --- -*- lexical-binding: t; -*-
;; Copyright (C) 2018 Seong Yong-ju
;; Author: Seong Yong-ju <sei40kr@gmail.com>
((rust-mode . ((racer-rust-src-path . "~/.rustup/toolchains/1.15.1-x86_64-apple-darwin/lib/rustlib/src/rust/src")
(eval . (setq quickrun-option-cmd-alist
(list
'(:command . "rustup")
(cons :exec
(list
"%c run --install 1.15.1 rustc %o -o %e %s"
(concat (projectile-project-root) "utils/run-tests.sh env RUST_BACKTRACE=1 %e %a")))
'(:compile-only . "%c run --install 1.15.1 rustc %o -o %e %s")
'(:remove . ("%e"))
'(:description . "Compile rust and execute via rustup")))))))
[先程のスクリプト] [実行コマンド...]
といった感じですね。テストケースの数に依らず、コンパイルは1回です。