ビジュアライズしたい。
ライフゲーム
これをアニメーションするのにターミナルを使い、
それをttyrecで録画。ttygifでgif生成したのだけど、
イマイチかくかく。
ビジュアライズに限れば適当なplotを使えば良いのだろうけど、
gifも欲しい。ttygifの中身はImageMagickなわけだから、
直接使ってしまおうと。
RMagick
ImageMagickのRuby binding
追記 new_imageを使おう
自前でtempfile使うより簡潔です。
new_imageしていくだけでGIFのワンフレーム追加できます。
def make_gif(name = "", x = 0, y = 0, fps = 0, &d)
m = Magick::ImageList.new
(0..fps).each { |n|
m.new_image(x,y)
d.call(m,n)
}
m.write(name)
end
make_gif
一時ファイルにワンフレームごと書き出し、
最後にそれらをひとつのGIFにまとめる。
非効率臭い。
rmagick_make_gif
require "RMagick"
require "tempfile"
def make_gif(name = "", x = 0, y = 0, fps = 0, &d)
tfs = (0..fps).map { |n|
mi = Magick::Image.new(x,y)
d.call(mi,n)
tf = Tempfile.new(["draw_gif",".gif"])
mi.write(tf.path)
tf
}
Magick::ImageList.new(*tfs.map(&:path)).tap { |mil|
mil.iterations = 10
mil.write(name)
tfs.each(&:close)
}
end
lifegame.rb
require "./lifegame.rb"
require "./rmagick_make_gif.rb"
lg = Lifegame.new(300,300)
lg.random { (rand(2) + rand(2) + rand(2)) / 3 }
make_gif("lifegame.gif",300,300,100) { |m,n|
lg.cells.each_with_index { |cy,iy|
cy.each_with_index { |cx,ix|
m.pixel_color(ix,iy,"black") if cx == 1
}
}
lg.apply
}
cells
一次元セルオートマトンもついでに。
ルール90です。
require "./cells.rb"
require "./rmagick_make_gif.rb"
cs = Cells.new
bs = []
make_gif("cells.gif", 200,100,100) { |m,n|
y = 0
bs.push(cs.dup)
bs.each { |cy|
x = 0
cy.cells.each { |cx|
m.pixel_color(x,y,"black") if cx == 1
x += 1
}
y += 1
}
cs.apply 90
}
end
ターミナルのテキスト表現のボリュームとは桁違いに多く出力できるので、
この例の場合はこちらを使う方が良いですね。