「RubyKaigiが終わったら真面目にやろう」とか言ってたくせに、中々やる暇無くて放置してたら大変に分かりやすい作り方講座が出てしまった上、弾さんまで乗ってきてしまって完全にタイミングを逃したfaultierですこんばんは。
悔しいので対抗してみる
うどんげが出たならてゐもいてもいいだろう、ということでてゐ。AAは上記の記事同様こちらを使わせてもらった。初春もいいなーと思ったんだけど表示してみたら大き過ぎて自分のターミナルで表示できなかったのでやめといた。コードはこんな感じ。
# tewi.rb eval$s=%w't=true;e="eval($s=join("<<34<<34<<",qw{$t=1;$s=~/"<<92<<"[[0-9,]+"<<92< <"]/;$n=eval($&);$e= "<<39<<"eval$s=%w"<<39<< ".chr(39)."<<39<<($s+( ($s.length>1756)?" ":"#"<<$ s.gsub(/[^0-9a-zA- Z]/, "")[0,(1755-$s.l ength)]));e[-312, 311]=""<<39<< ";$e.= ("<<39<<"#"< <39<<".substr( join("<<39<<39<< ",split(/[^0-9a-z A-Z]/,$s)),0,(200 9-length($s) ))).chr(39)."<< 39<<".join"<<39<<";@o = map{$t=!$t;split(// ,((!$t)?su bstr($e,0,$_,"< <39<<39<<"):chr(32)x$_) )}@$n;for(1..34){spli ce(@o,$_* 81,0,chr(10))} ;print(join("<<39<<39<< ",@o).chr(10 ) )}))";o=[ 101,10,24,4,40 ,3,8,4,18,3,4,6,33,2,13 ,3,6,10,1 2,3,30,2,1 7,14,17,2,27, 2,21,3,1,7,19 ,2 , 25,1,23,9, 21,2,23,2,23, 9,12,6,1, 4 ,23,1,23, 11,9,12,23,2, 13,4,2,2 1 ,1,14,23, 2,9,27,1,19 ,22,1,8 , 1 9 , 1,29,20, 3,7,9,1, 18,1,4 , 1 , 3 , 1,13,16 ,6,6,6, 1,9,1,8 ,1 , 1 0, 1,11, 1,4,14, 6,7,26, 2,1 1,1,4 ,1 ,4, 2,4 ,12,6,7 ,19,3,5, 5, 3,2,14,3 ,3,1 0,5 ,8,13 , 2,2,8, 2,4,3,3,15, 5,2 ,7 , 4,11 ,10,3, 4,2,4,1, 2,4, 1,6,14,12,4,1 3 , 6,1, 2,1,3,4,5,18,3,1,3 , 1 ,3,12,3, 12,1 3,5,1,2,4,15 ,1,1, 11 ,10,3,14,12,6,1 , 2,5,13,2 ,1 ,1,1,6,12,2,16 ,11,7, 8, 13,2,1,7,13,1 , 1 8,10,8,6,14 , 1,2,10,10,1,20,1 2,5,3,1 2,1,6,13,7,2, 1 9,13,26,14,7 , 2,16,16,11,1,13,14 ,8,2,14, 16,13,7,5,15,1 0, 3,8,10,1, 8 ,25,10,1,4,13,27,23, 12,4, 2,12,5,1,1,1 ,8,1,1 3,17,1 0 ,1,3,5,1,12,14,4,8, 4,10,2,13,25,2,3,9,4,2,1,3 ,15,1 3, 33,4,5,1,4,3,20, 8,182].map{ |i|t=!t;((!t) ?e.sl ice !(0,i):32.chr* i)}.join;1.up to(35 ){|i| o[(i* 81)-1,0] = 10.chr};puts(o)#ttrueeeva l sjoin 3434qwt1 s920992nevale39evalsw39 chr3 939s slength1 7 5 6 sgsub09azAZ01755s l ength e3123 1139e39 39su bstr jo #t1s09nevaleevalsw chr39tt rue eeva l sjoin3434qwt1s9 20992nevale39evalsw39 chr3939sslen gth17 56sg sub09azAZ01755slengt he31231139e3939substrjo in3939split09azAZs02009lengthschr3939join39omapttsplittsubstre03939chr32xnfor134 spliceo810chr10printjoin3939ochr10o10110244403841834633213361012330217141'.join
Gistにも置いてあります。はい。
Quineじゃない件
上のコードをコピペしてRubyに実行させると何やらコードを吐くので、それをさらにRubyに流し込んで実行させてやると…なんということでしょう!エラーを吐くではありませんか!Quineになってねぇじゃねーか、このド低能が!
# tewi.pl(tewi.rbの出力結果) eval($s=join("",qw{$t=1;$s=~/\[[0-9,]+\]/;$n=eval($&);$e='eval$s=%w'.chr(39).'t= true;e="eval($s=join( "<<34<<34<<",qw{$t=1;$s= ~/"<<92<<"[[0-9,]+"<< 92<<"]/;$n=eval($&) ;$e="<<3 9<<"eval$s=%w"<<39 <<". chr(39)."<<39<< ($s+(($s.length>17 56)?"":"#"<<$ s.gsub (/[^0-9a-zA- Z]/,"")[0,(17 55-$s.length)])); e[-312,311]=""<<3 9<<";$e.=("<<39<< "#"<<39<<". substr(join("<<3 9<<39<<",split(/[^0-9 a -zA-Z]/,$s)),0,(200 9-length( $s)))).chr(39)." <<39<<".join"<<39<<";@o =map{$t=!$t;split(//, ((!$t)?s ubstr($e,0,$_," <<39<<39<<"):chr(32)x$_ ))}@$n;for(1 . .34){spl ice(@o,$_*81,0, chr(10))};print(join("< <39<<39<< ",@o).chr (10))}))";o=[1 01,10,24,4,40 ,3 , 8,4,18,3, 4,6,33,2,13,3, 6,10,12,3 , 30,2,17, 14,17,2,27,2,2 1,3,1,7, 1 9,2,25,1 ,23,9,21,2,2 3,2,23, 9 , 1 2 ,6,1,4, 23,1,23,1 1,9,12 , 2 3 , 2 ,13,4, 2,21,1,1 4,23,2, 9, 2 7 ,1 ,19, 22,1,8,1 9,1,29, 20, 3,7,9 ,1 ,18 ,1 ,4,1,3,1 ,13,16,6 ,6 ,6,1,9,1 ,8,1 ,10 ,1,11 ,1,4,14 ,6,7,26,2,1 1,1 ,4 , 1,4, 2,4,12 ,6,7,19 ,3,5, 5,3,2,14,3,3, 1 0 ,5,8 ,13,2,2,8,2,4,3,3, 1 5 ,5,2,7, 4,11, 10,3,4,2,4,1 ,2,4, 1, 6,14,12,4,13,6, 1 ,2,1,3, 4,5 ,18,3,1,3,1,3, 12,3,1 2, 13,5,1,2,4,15 , 1 ,1,11,10,3 ,1 4,12,6,1,2,5,13, 2,1,1,1 ,6,12,2,16,11 , 7,8,13,2,1, 7, 13,1,18,10,8,6,14, 1,2,10,1 0,1,20,12,5,3, 12 ,1,6,13, 7, 2,19,13,26,14,7,2,16 ,16,1 1,1,13,14,8, 2,14,1 6,13, 7, 5,15,10,3,8,10,1,8, 25,10,1,4,13,27,23,12,4,2, 12,5 ,1, 1,1,8,1,13,17,10 ,1,3,5,1,12 ,14,4,8,4,10, 2,13 ,25, 2,3,9,4,2,1,3, 15,13,33,4,5, 1,4,3 ,20, 8,182] .map{|i| t =!t;((!t)?e.slice!(0,i):3 2 .chr *i)}.join ;1.upto(35){|i|o[(i*81) -1,0 ]=1 0.chr};pu t s ( o)#ttrueeevalsjoi n 3434q wt1s 920992ne vale 39ev al sw39chr3939ssleng th1756sg sub 09az A Z01755slengthe3 1231139e3939substrjo ';$e.=('#'.su bstr( join ('',split(/[^0-9a-zA -Z]/,$s)),0,(2009-leng th($s)))).chr(39).'.join';@o=map{$t=!$t;split(//,((!$t)?substr($e,0,$_,''):chr(3 2)x$_))}@$n;for(1..34){splice(@o,$_*81,0,chr(10))};print(join('',@o).chr(10))}))
ええはい。良く見てもらえると分かると思うけど、実はこのコードは自分自身を出力してない。何を出力してるかと言うと、Perlのコードを出力している。んで、そのPerlのコードは何をするかというと、最初のRubyのコードを出力する。つまり、最初のコードは「『このRubyのコードを出力するPerlのコード』を出力するRubyのコード」で、後のコードは「『このPerlのコードを出力するRubyのコード』を出力するPerl」のコードになっていて、お互いがお互いの自分自身を相手に出力させるという、「人は一人では生きて行けないんだ」というメッセージ性を持った難読コードなわけです。まぁ嘘です。RubyもPerlもやられちゃったので、そのまま真似してもつまらなかっただけです。こんな感じで遊んでみるといいよ!
$ cat tewi.rb | ruby | perl | ruby | perl | ruby
何をしたの?
実のところ別になんということはなくて、やってることは基本的にはうどんげQuineと一緒。配列リテラルとjoinとevalを使ったQuineはPerlでもRubyでも全く同じ要領でできるので、自分自身を吐く代わりに相手のコードを吐くように書き換えると簡単に行ったり来たりできるようになる。
# 任意に加工できるRubyコードを出力する、 # 任意に加工できるPerlコードを出力する、 # 任意に加工できるRubyコードの例 eval$s=%w'puts("eval(join("<<39<<39<<",qw{print("< <39<<"eval$s=%w"<< 39<<".chr(39)."<<39< <$s<<39<<".chr(39)."<<39<<".join"<<39< <")}))")'.join
あとは、二言語分のコードが一つのAAの中に入ることになるし、PerlとRubyだとリテラルがそっくりなのでデータ部は共有したいので生のデータを書きたい、となると流石に元のAAデータだと文字数の制限がキツいから、反転して白抜きのAAにした。ちなみに、てゐの方はうどんげのとはAAデータ持ち方は換えてる(元記事のロジックをPerlで実装するのが面倒だっただけ)。
あとはまぁ、出力時に尻尾に適当なゴミを付けて文字数調整してるんだけど、文字列リテラルの入れ子が簡単に崩れるので面倒臭いとかそんな程度。chr(39)濫用しまくり。あとドットがRubyのドットなのかPerlのドットなのか良くわかんなくなったりします。
まとめ
途中で「俺は一体何をやってるんだ」と思ったら多分負けなんだと思います。一度ベースができちゃうと後はデバッグと文字数の調整が面倒なだけで、割と簡単にできます。あと段々哲学的な気分になります。