数学ガールの秘密ノート第104回の縁取りについて適当に実装しましたが( http://qiita.com/cielavenir/items/2598ecd6d7edb9900cc1 )、フィルタ関数が受け取るものが画像全体であるという制限がありました。
これを、秘密ノートに書いてあるとおり、1行ずつ読ませるようにしたい。
ここで問題になるのが、filter_downです。これは行を1個読み飛ばす処理が必要となります。
RubyのEnumeratorは値を出力することしかできず、単純なFiberだと親と子の間に値を1個しか溜めておくことができません。
その点、Golangのchanは、値を複数溜めておくことが可能です。
chanの「<-」演算子はちょうど秘密ノートに書いてある「送信」「受信」の概念にピッタリあてはまるということもあります。
https://twitter.com/cielavenir/status/561054114960769024
https://twitter.com/hyuki/status/561054600145293312
Golangでごりごり書けたとして、関数型のようにきれいに書ける気がしないので、この機能をRuby上に実装し、chan gemとしてリリースすることにしました。
https://github.com/cielavenir/ruby-chan
これを用いると、数学ガールの秘密ノート第104回の縁取りはこのように格好良く実装できます。
まず最初に、echo/filter_right/filter_left/filter_up/filter_downフィルタに1行ずつデータを送ります。
続いて、全てのフィルタが準備出来ている間、「filter_right/filter_left/filter_up/filter_downから1行ずつ取ってきてビット積を取り、反転して、echoから1行取ってきたものとビット積を取る」処理を行います。
# !/usr/bin/ruby
require 'chan'
filter_right=Chan.new{|ch|
loop{
ch<<(ch.receive>>1)&0xffff
}
}
filter_left=Chan.new{|ch|
loop{
ch<<(ch.receive<<1)&0xffff
}
}
filter_up=Chan.new{|ch|
ch<<0
loop{
ch<<ch.receive
}
}
filter_down=Chan.new{|ch|
ch.receive
15.times{
ch<<ch.receive
}
ch<<0
}
echo=Chan.new{|ch|
loop{
ch<<ch.receive
}
}
puts Chan.new{|ch|
list=[echo,filter_right,filter_left,filter_up,filter_down]
loop{
n=ch.receive.to_i(2)
list.each{|ch|ch<<n}
while list.all?(&:next?)
ch<<'%016b'%[echo.receive&([filter_right,filter_left,filter_up,filter_down].map(&:receive).reduce(:&)^0xffff)]
end
}
}.gen_enum(DATA.to_enum).to_a
__END__
0000000000000000
0000000000000000
0011111111111100
0011111111111100
0011111111111100
0011100000000000
0011100000000000
0011111111100000
0011111111100000
0011111111100000
0011100000000000
0011100000000000
0011100000000000
0011100000000000
0000000000000000
0000000000000000