Emacs Lisp for PKU Judge Online and others

id:halwhiteさんがpkuのスクリプトを公開していたので私も公開.poj-modeっていうのは知らなかった…

http://code.google.com/p/icpc-online-judge-scripts/source/browse/trunk/icpc-online-judge.el#

このLispは外部スクリプトをプロセスを生成して実行します.それにより以下の機能を提供します.

機能

  • PKUなどのオンラインジャッジサイトへの自動サブミット
  • 上記の結果はポップアップする.
  • ファイルを開いたときにテンプレートファイルの自動挿入
  • ファイルを開いたときに自動的にサンプル入出力を作成する
  • サンプルテスト用コンパイルコマンドの補助(C-c C-cなどに割り当てると便利)

使い方

まず,適当なディレクトリに入れてload-fileしてください.

例:~/site-lisp/icpc-online-judge.elに保存した場合,
.emacsに次のように記述

(load-file "~/site-lisp/icpc-online-judge.el")

(この際,find-file-hookにいくつかの関数をhookします)

次に,icpc-online-judge.elを開いて最初の行,icpc-judge-alistを編集します.
icpc-judge-alistはパラメータリストのリストです.パラメータリストは次の構成になっています.

  1. スクリプトを適用するファイルの正規表現
  2. 1にマッチしたとき挿入するテンプレートファイル
  3. 1のファイル名部分から,問題番号を抜き出す正規表現
  4. 適用するスクリプト
  5. 入出力ファイルを作成するときにスクリプトに渡す引数
  6. サブミットする時にスクリプトに渡す引数
  7. 1をコンパイルするときのコマンド

パラメータ中では%に続けて特殊文字列が使えます.特殊文字列は次のようになっています.

例えば,pku1000.cppというファイルを1000.in,1000.outでテストする場合次のように記述します.

g++ %f && ./a.out < %p.in | diff %p.out -

これは次のように置き換えられます.

g++ pku1000.cpp && ./a.out < 1000.in | diff 1000.out -

関数は次の通りです.

  • icpc-submit-current-buffer 現在開いているファイルをサブミットする
  • icpc-submit-current-buffer-with-args サブミットするとき,引数を指定する
  • icpc-compile-and-test パラメータ7によりコンパイルする
  • icpc-mode-toggle 自動テンプレート挿入などの有効/無効を切り替える.

スクリプト

このlispは外部スクリプトを実行するため,スクリプトが別に必要になります.私の作ったpkuのperlスクリプトはこちらです.
http://code.google.com/p/icpc-online-judge-scripts/source/browse/trunk/pku.pl
このスクリプトの$idと$passを自分のものに書き換えて下さい.
あまりperl書かないから汚いです.
また,入出力の作成が全然甘いのですが,spojのスクリプトも作りました.
http://code.google.com/p/icpc-online-judge-scripts/source/browse/trunk/spoj.pl
本当は流行りのcodeforceで作ろうと思ったけど,googleopenidが上手くできない…

補足

このスクリプトは引数が次のようになっている

*サブミット
# ./pku.pl submit 問題番号 送信するファイル
*入出力作成
# ./pku.pl sample 問題番号 入力保存先 出力保存先

とりあえず使ってみるなら

icpc-judge-onlineとpku.plを~/site-lisp/に保存,テンプレートファイルを~/icpc/icpc_template.cppに保存,pkuのファイルを~/icpc/pku/1000.cppに保存してみれば動くはずです.

(スクリプト作成者向け)スクリプト作成方法

このlispスクリプトはexit codeと出力で会話をします.スクリプトの方で

print "hello world";
exit 0;

とすると,emacsのミニバッファにはhello worldが表示されます.またexit 1とすると,hello worldがポップアップします.また,exit 2では,emacsはカレントバッファをスクリプトが出力したものにします.

どうでも良い話

emacs lispの困るところは,マルチスレッドができないところで,昔emacs lispで送信もするものを使っていたのですが,問題のTLEが長い時やそもそもPKUが落ちているときはなかなか結果が帰ってこなくて,ずっとemacsが固まってました.それはとても嫌だったので,lispで固まらない方法はないかと探して外部スクリプトを実行してexit codeでやりとりする方法を考えました.emacs lispがマルチスレッドに対応してくれればこんなにめんどくさいことをしなくてすむのですが.

UVaとかスクリプトを他の言語でとか,誰か作って欲しいなぁ.