PApplet
[ActionScript 3.0] Fisher-Yatesアルゴリズムの可視化│miscellaneous を Groovy で実装したい。
依存関係がなく Groovy スクリプトから利用し易そうな Processing を使ってみる。
Processing を Grape から利用するための設定
公開されている Maven リポジトリに存在しないのでローカルリポジトリに core.jar をインストールする。
mvn install:install-file -Dfile=core.jar -DgroupId=processing -DartifactId=core -Dversion=1.2.1 -Dpackaging=jar -DgeneratePom=true
Groovy は Ivy でライブラリを管理している。Ivy からローカルの Maven リポジトリを参照するためには .groovy/grapeConfig.xml に設定を追加する。
参考: Re: Read from Maven local repository
Processing の利用方法
@Grab('processing:core:1.2.1') import processing.core.* class XXX extends PApplet { @Override void setup() {} @Override void draw() {} } PApplet.main(["XXX"] as String[])
- PApplet クラスを継承して使用する
- setup に初期化処理を記述する
- draw にアニメーション処理を記述する *2
- アプリケーションで実行するには PApplet.main にクラス名を渡す
API はチュートリアルやリファレンスを参考にした。
その他 Groovy からの使用例: Groovy and Processing.org! :: Thom Nichols
Groovy スクリプトなので内部クラスを使用したが、別クラスにする場合は @Delegate を使用するパターンが参考になるだろう。
fisher-yates.groovy *3
@Grab('processing:core:1.2.1') import processing.core.* class FisherYates extends PApplet { static final int RADIUS = 4 static final int DIAMETER = RADIUS * 2 static final int Y = 100 static final int INTERVAL = 10 def balls = [] def processing def i, j, t @Override void setup() { size(400, 200) for (i in 0..<40) { int c = new java.awt.Color(i*5, i*5, 0).RGB balls << new Ball(c, i * INTERVAL + RADIUS, Y) } smooth() noStroke() frameRate(30) } @Override void draw() { background(255) balls.eachWithIndex { ball, index -> int x = ball.x int y = ball.y if (processing && (index == i || index == j)) { def target = index == i ? balls[j] : balls[i] def h = index == i ? -40 : 40 x = map(t, 0, frameRate, ball.x, target.x) y = bezierPoint(y, y+h, y+h, y, t / frameRate as float) } fill(ball.color) ellipse(x, y, DIAMETER, DIAMETER) } if (processing) { t++ if (t >= frameRate) { swap() next() } } } @Override void mousePressed() { if (processing) return processing = true i = balls.size() next() } void next() { if (i > 1) { j = Math.random() * i as int i-- t = 0 } else { processing = false } } void swap() { if (i == j) return int temp = balls[i].x balls[i].x = balls[j].x balls[j].x = temp Collections.swap(balls, i, j) } class Ball { int color, x, y Ball(color, x, y) { this.color = color this.x = x this.y = y } } } PApplet.main(["FisherYates"] as String[])
Processing の値は主に float 型だが Groovy では float で演算した結果は double になるので注意する。