遠藤さんの「ちょっと」にちょっと迫ってみたいと思ってQuineを手元のエディタで編集しようとしてみたんだけどちょっとも迫れませんでした…。.split.joinあたりで見た目を自由にできてるのかなあって気はするんだけど、またそのうち…
Rubyの全バージョンで動くQuine
https://mametter.hatenablog.com/entry/2023/02/25/232514
fにはたぶんバージョンを表現するためのフォントが格納されている。fは284要素の整数の最小34最大126の整数の配列。それぞれの整数が7ビットの情報を持つとすると、合計で1988ビットの情報がある。Quineを実行すると表示されるそれぞれの文字は11桁9行で、バージョン番号に使われる文字が0から9までの数字とピリオド、アンダースコア、ハイフンとaからdくらいまでのアルファベットとする(vにeを代入してquineを実行するとNoMethodErrorとなる)と合計17種、1683ビットになる。さて、どういうエンコーディングになっているのだろう。2進数にして並べるだけじゃ文字は見えてこない…と悩んでるあたりで https://github.com/mame/all-ruby-quine/tree/main/src の存在に気づいたよね。それはそうだ。遠藤さんはquineを生成するコードを駆使している。次はこのあたりのコードを読ませていただこうwktk
おっさんにも読めるコードが https://github.com/mame/all-ruby-quine/tree/main/src/prototypes にある感じのようだ。遠藤さんはこれらのコードが全てのバージョンのRubyで期待どおり動くことを確かめたのかな?
一番楽しそうなファイルから確認してみる。
$ cat quine.rb
eval(s="print('eval(s='+34.chr+s+34.chr+')'+10.chr)")
$ cmp <(ruby quine.rb) quine.rb; echo $?
0
おー!Quineだ。
左のevalに渡されるのはsに""で囲まれた文字列を代入するコードで、代入の結果がeval()の引数になるので、
print('eval(s='+34.chr+s+34.chr+')'+10.chr)
がevalによって実行される。
というわけでevalによって実行されるのは上記のprint()で、print()に渡される引数はシングルクォーテーションで囲まれた文字列とコード片。34.chrはダブルクォーテーション、10.chrは\n。この文字列を僕にわかりやすく書き直すと、
eval(s="#{s}")\n
となる(ダブルクォーテーションのエスケープは省略してある)。#[s}に代入されるのは上でevalによって実行されると書いた、print(…)の文字列。代入してみるね。
eval(s="print('eval(s='+34.chr+s+34.chr+')'+10.chr)")\n
うおーすごい。元のコードと一緒になった!
@usa はい!そのうち買うんですけど、答えを見ちゃう前に少し自分でもがいておいてみたいな、と思ってます。溺れないように気をつけなくちゃ…