TopCoder の強欲プラグイン、Greed を使う!

  • 47
    いいね
  • 1
    コメント
この記事は最終更新日から1年以上が経過しています。

TopCoder の強欲プラグイン、Greed を使う!

TopCoder の中で比較的新しいプラグイン、Greed は非常に柔軟にカスタマイズできますが、日本語での解説はあまりなかったのでまとめます。vexorian先生も絶賛する Greed を導入して TopCoder に参戦しましょう。

導入

まず、公式ページから最新の jar をダウンロードして保存します。現時点で最新版は2.0-RC。version1 系から仕様は変わっているので、最新版を使用したほうがよいです。

保存したら Arena を立ち上げてログイン後、メニューからOptions -> Editor を開く。Name には Greed 等の任意の名前、EntryPoint には greed.Greed、ClassPath には先ほどダウンロードした jar を指定して OK。

greed_config.png

Default、At Startup にチェックを入れて、Configure を押し、設定ファイルなどが保存される workspace ディレクトリを入力し、Verify & Save。

greed_conf.png

これで導入は終了。Greed は基本的なテンプレートを内蔵しているので、この状態ですぐにコンテストに参加することができます。試しに適当に Practice Room に入って問題を開くと、ワークスペースにコンテスト名のディレクトリが作成され、その下に問題名のついたソースコードと、問題の html ファイル、テストケースの入力が生成されます。生成されたコードをコンパイル、実行すると、スコア付きで実行結果を表示します。

greed_out.png

Greed ではテストケースを外部ファイル .sample に保存するため、テストケースを追加も簡単です。
もし上手くいかない場合は、公式ページの手順を参照してください。

Greed のカスタマイズ

Greed の特徴は、そのカスタマイズの自由度にあります。テンプレートエンジンの jmte を利用してコードを生成することで、様々なソーステンプレート、テストテンプレートを生成することができます。jmte は文法も簡単なので、コーディングスタイルに合わせて独自のテンプレートを作成するとよいです。以下では、Emacs + C++ で参加している自分のカスタマイズ例を紹介しますが、他の言語でも十分役立つと思います。記法の詳細は wiki を参照してください。私の設定ファイルの詳細は、こちらから参照してください。

全体の設定

Greed 全体の設定は workspace/greed.conf に記述します。デフォルトの設定はこちら。自分は以下のように設定しています。

greed.conf
greed.codeRoot = ""
greed.shared.templateDef.problem-desc {
  options {
    theme = darkgray
    gridArrays = true
  }
}

greed.language.cpp {
  longIntTypeName = LL
  templateDef {
    source.templateFile = template.cpp
    filetest.templateFile = tester.cpp
    script {
      overwrite = skip
      outputFile = "${Problem.Name}.script"
      templateFile = template.cpp
      afterFileGen {
        execute = /path/to/script/afterFileGen.sh
        arguments = [ "${Problem.Name}" ]
      }
    }
  }
  templates = [ filetest, source, problem-desc, script ]
}
  • codeRoot

自分は Greed 以前は同じディレクトリに全てのコンテストのソースコードを突っ込んでいて、今更ディレクトリを分けるのはめんどくさいのでgreed.codeRoot = ""として、保存先をすべて workspace にしています。もしコンテストごとにディレクトリを作る場合はgreed.codeRoot = "${Contest.Name}" とします。

  • greed.shared.templateDef.problem-desc.options

Greed を導入してからは、ブラウザで問題文を読むようになりました(後述のスクリプトを参照)。problem-desc.optionsの指定でスタイルの設定と、引数が配列の時に見やすくするように調整しています。

  • greed.language.cpp.longIntTypeName

問題で long long を使用する場合、greed が生成するテンプレートの型名を指定できるます。LL派。

  • greed.language.cpp.templateDef

Greed では、ソースコードやテストファイルなどは templateDef の下に template として一連の設定をすることができます。templateDef.source はソースコード生成に使用する template で、filetest はテストコードを生成する template です。それぞれの templateFile に、templateとして使用するファイルを指定します。この設定の場合は、workspace ディレクトリ直下に template.cpp、tester.cpp が存在します。

  • greed.language.cpp.templateDef.script

Greed では、問題を開いた時に任意のコマンドを実行する tmeplate を作成ことができます。ここでは、script という template を作成する。script は後で説明します。

  • greed.language.cpp.templates

templates で、実行する template のリストを指定します。

ソースコードテンプレート

標準のテンプレートでもあまり問題はないですが、さらなる使い勝手を求めてカスタマイズ。

template.cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define REP(i, N) for (int i = 0; i < (int)N; i++)

${<if Problem.Description.Modulo}
  static const int MOD = ${Problem.Description.Modulo};
${<end}

struct ${ClassName} {
${<foreach Method.Params p}
  ${p.Type} ${p.Name};
${<end}
  ${Method.ReturnType} ${Method.Name}(${foreach Method.Params p , }${p.Type} _${p.Name}${end}) {
    ${foreach Method.Params p , }${p.Name} = _${p.Name}${end};
    return ${Method.ReturnType;zeroval};
  }
};

${CutBegin}
${<TestCode}
${CutEnd}
  • include

vexorian 先生の blog によると、<bits/stdc++> を include すると標準ライブラリをすべて include できます。テンプレートがスッキリするのでおすすめ。

  • マクロなど

REP、FOR など任意のマクロを記述します。

  • MOD の自動生成

Greed は、返り値に Module が必要なことを自動で判別して抽出することができます。

MOD生成
${<if Problem.Description.Modulo}
  static const int MOD = ${Problem.Description.Modulo};
${<end}

ただし、SRM 626 ReflectiveRectangle では 'modulo 10^9 + 7' と 普段と違う記述をしていたせいか正しくパースできていませんでした。完璧ではありません。

  • メンバー変数に引数を copy

私は、関数の引数を他の関数でも使うときにグローバル変数に移したりすることがあります。その作業を自動化するテンプレートを記述しています。SRM 626 ReflectiveRectangle では以下のコードが自動的に生成されます。

ReflectiveRectangle.cpp
struct ReflectiveRectangle {
  int sideA;
  int sideB;
  int bounces;
  int findSum(int _sideA, int _sideB, int _bounces) {
    sideA = _sideA, sideB = _sideB, bounces = _bounces;
    ...

関数の引数にはアンダースコアを先頭に付け、関数の最初にメンバー変数へコピーしています。

テストテンプレート

vexorian 先生はテストテンプレートに色を付けたり、入力を表示したりしています。

test画面

私はそこまでカスタマイズはしていませんが、標準のままだとデバッグ出力をした時、デバグ出力がtestcase # の直後に表示されてよみにくいです。

読みにくい出力
  Testcase #0 ... debug
message
FAILED! (0.00 seconds)
           Expected: 25
           Received: 0
  Testcase #1 ... debug
message

これを修正しています。

スクリプトテンプレート

スクリプトテンプレートのために、私は次のようなスクリプトを記述しました。

afterFileGen.sh
open $1.html
/usr/local/bin/emacsclient $1.cpp

こうすることで、問題を開くと自動的にブラウザによってローカルの問題文を表示して、更に emacs で問題のコードを開きます。Emacs では事前に(start-server)の実行が必要です。アプレットではなくブラウザで問題文を開くとなかなか読みやすいです。ブラウザの拡張も使えるので、わからない単語を調べたりなどは便利です。

このスクリプトテンプレートのために問題名.script ファイルが生成されます。これはちょっと気持ち悪いですが、このファイルの存在判定によって、再度開いた時に問題を開きなおしたりすることを制御できます。

まとめ

Greed plugin は柔軟にカスタマイズすることができます。Greed を導入したことで、私は特にテストケースの追加が簡単にできるようになったことと、問題を開いたと同時にブラウザで問題文を読むこと、ソースコードを Emacs で開くことがお気に入りです。色々と面白い Greed のカスタマイズがあると思うので、何か便利な活用法を考えたらぜひ共有してほしいです。とりあえず、Practice 用のテストケースを.sample にしてくれるスクリプトが欲しいなあ。

リンク集