こちらの記事を元に自分で作ってみた時の記録です
ソースコード
eval$s=%w' b="BAhsK2Lgf4 D/D/7/8/9///j/B/9 /8P8H/3/w/wf/f/7/7/ ///+//P/ j/Af5/AOA PAPwAAM CHH3z4wY cffPjBh x98+MGHH /z/wf8/ /P+D/z/g nwMAAAA PAPgBAA8 AAADAPw D8A4A/AP gDgB8A+ AGAHwD4AeA/ AP4D4D8A /gMAAOD8A/7 /4P8f/v/D/z/88MMPP/z www8//PDDDz/88AMA APD/wP8//v//D/ 7/////f///8x8A /wPg/z/ 8/wP/P wA="; n=Mars hal.l oad(b. unpac k("m") [0]); x=20;y =74;e ="eval $s=%w "<<39< <($s* 3);o=" ";j=-1;0.upto(x *y){|i|o<<((n[i] ==1)?e[j+=1]:32) ;o<<((i%x==x-1) ?10:"")} ;o[ -10, 6]=""< <39< <".join" ;puts(o) ;#b="BA hsK2Lgf 4D/D/7 /8/9// /j/B/9 /8P8H/ 3/w/wf/f/ 7/7////+/ /P/j/Af5/ AOAPAPwAA MCH H3z4wYcf fPjBhx98+MGHH/z /wf8//P+D/z/gnwM AAAAPAPgBAA8AAADA PwD8A4A/APgDgB8A +AGAHw D4AeA/ AP4D4D 8A/gMA AOD8A/ 7/4P8f /v/D/z /88MMP P/zwww 8//PDD Dz/88A MAAPD/ wP8//v //D/7/ ////f///8x8A /wPg/z/8/wP/PwA= ";n=Marshal.load(b. unpack(" m")[0]) ;x=20;y=74;e="eval$s =%w"<<39<<($s*3);o= "";j=-1;0.upto(x*y ){|i|o<<( (n[i]==1)? e[j+=1]:32);o<<(( i%x==x-1)?10:"") };o[-10,'.join
キモいですね!
作り方
以下の手順に沿ってコードを書いていく
- QuineにしたいAAを用意
- AAをBase64文字列に変換
- 「Base64文字列からAAを表示する」ジェネレーターを作成
- 「AAジェネレータ自身のコードをAAにする」ジェネレーターを作成
- 「AAジェネレーターをAAのQuineにする」ジェネレータを作成
AAのコードを実行可能にして、さらにQuine化
1. QuineにしたいAAを用意
このサイトで文字列をAAにできるので、これを元に作成。おすすめのフォントはdoh
https://www.askapache.com/online-tools/figlet-ascii/
aa=<<EOS 00000111111111100000 00011111111111110000 01111111111111111100 11111111111111111110 11111111000111111111 11111110000011111111 11111110000011111111 11111110000011111111 11111110000011111111 11111110000011111111 11111110011111111111 11111111011111111111 11111111111111111111 01111111111111111100 00011111111111111000 00000111111111111110 00000000000001111111 00000000000000111111 00000000000000000000 00111110000111111000 00111110000111111000 00111110000111111000 00111110000111111000 00111110000111111000 00111110000111111000 00111110000111111000 00111111111111111000 00111111111111111100 00111111111111111100 00011111111111111100 00000111111110011100 00000000000000000000 00000000111100000000 00000001111110000000 00000000111100000000 00000000000000000000 00000011111111000000 00000011111111000000 00000001111111000000 00000001111111000000 00000001111110000000 00000001111110000000 00000001111110000000 00000001111110000000 00000111111111000000 00000111111111000000 00000111111111000000 00000111111111000000 00000000000000000000 01110011111111000000 01111111111111110000 01111111111111111000 01111111111111111100 00111111111111111100 00111111000011111100 00111111000011111100 00111111000011111100 00111111000011111100 00111111000011111100 00111111000011111100 00111111000011111100 00000000000000000000 00001111111111110000 00111111111111111100 01111111111111111111 11111111000001111111 11111111111111111111 11111111111111111110 11111111111111111100 11111111100000000000 11111111110000000000 01111111111111111100 00111111111111111100 00001111111111111100 EOS
解説
- このAAの
1
の部分に後ほどソースコードが入る - ソースコードの文字数は当然ながら、AAで表現できる文字数よりも少ない必要がある
- ソースコードにAAのデータも入るため、base64に変換して、格納可能にする
2. AAをBase64文字列に変換
普通に [Marshal.dump(bits)].pack("m")
を使って変換
bits = aa.gsub("\n", "").reverse.to_i(2) bin = [Marshal.dump(bits)].pack("m").gsub("\n", "") puts bin #=>BAhsK2Lgf4D/D/7/8/9///j/B/9/8P8H/3/w/wf/f/7/7////+//P/j/Af5/AOAPAPwAAMCHH3z4wYcffPjBhx98+MGHH/z/wf8//P+D/z/gnwMAAAAPAPgBAA8AAADAPwD8A4A/APgDgB8A+AGAHwD4AeA/AP4D4D8A/gMAAOD8A/7/4P8f/v/D/z/88MMPP/zwww8//PDDDz/88AMAAPD/wP8//v//D/7/////f///8x8A/wPg/z/8/wP/PwA=
作成したBase64文字列は次のコードで使用するのでコピーする
3. 「Base64文字列からAAを表示する」ジェネレーターを作成
ジェネレータの概要
- Base64文字列にしたデータをデコード
- デコードしたBase64文字列を元に、0ならば空白。1ならば '1' を出力
- もともとのAAのサイズを元に、一定数出力したら改行
コード
# ↓AAをBase64文字列にしたデータ b="BAhsK2Lgf4D/D/7/8/9///j/B/9/8P8H/3/w/wf/f/7/7////+//P/j/Af5/AOAPAPwAAMCHH3z4wYcffPjBhx98+MGHH/z/wf8//P+D/z/gnwMAAAAPAPgBAA8AAADAPwD8A4A/APgDgB8A+AGAHwD4AeA/AP4D4D8A/gMAAOD8A/7/4P8f/v/D/z/88MMPP/zwww8//PDDDz/88AMAAPD/wP8//v//D/7/////f///8x8A/wPg/z/8/wP/PwA=" # Base64文字列をデコード n=Marshal.load(b.unpack("m")[0]) # AAのサイズ x=20;y=74 # 出力結果が格納される変数 o="" # デコードしたBase64文字列を展開 # 0ならば空白。1ならば '1' を出力 # 後でQuine化するときに改行や空白は使えないので数値で表現 0.upto(x*y){|i| o<<((n[i]==1)?'1':32) # 32 は空白 o<<((i%x==x-1)?10:"") # 10 は改行 } puts(o)
実行結果
1111111111 1111111111111 11111111111111111 1111111111111111111 11111111 111111111 1111111 11111111 1111111 11111111 1111111 11111111 1111111 11111111 1111111 11111111 1111111 11111111111 11111111 11111111111 11111111111111111111 11111111111111111 11111111111111 11111111111111 1111111 111111 11111 111111 11111 111111 11111 111111 11111 111111 11111 111111 11111 111111 11111 111111 111111111111111 1111111111111111 1111111111111111 111111111111111 11111111 111 1111 111111 1111 11111111 11111111 1111111 1111111 111111 111111 111111 111111 111111111 111111111 111111111 111111111 111 11111111 111111111111111 1111111111111111 11111111111111111 1111111111111111 111111 111111 111111 111111 111111 111111 111111 111111 111111 111111 111111 111111 111111 111111 111111111111 1111111111111111 1111111111111111111 11111111 1111111 11111111111111111111 1111111111111111111 111111111111111111 111111111 1111111111 11111111111111111 1111111111111111 11111111111111
このAAジェネレータを元に、「AAジェネレータ自身のコードをAAにする」ジェネレーターを作成
ややこしくなってまいりました
4. 「AAジェネレータ自身のコードをAAにする」ジェネレーターを作成
概要
eval$s=%w'〜'.join
を使って、$s
をAAの材料にするジェネレータを作成する〜
の中にはAAジェネレータが入る
ソースコード
eval$s=%w'b="BAhsK2Lgf4D/D/7/8/9///j/B/9/8P8H/3/w/wf/f/7/7////+//P/j/Af5/AOAPAPwAAMCHH3z4wYcffPjBhx98+MGHH/z/wf8//P+D/z/gnwMAAAAPAPgBAA8AAADAPwD8A4A/APgDgB8A+AGAHwD4AeA/AP4D4D8A/gMAAOD8A/7/4P8f/v/D/z/88MMPP/zwww8//PDDDz/88AMAAPD/wP8//v//D/7/////f///8x8A/wPg/z/8/wP/PwA="; n=Marshal.load(b.unpack("m")[0]); x=20; y=74; e=$s*3; o=""; j=-1; 0.upto(x*y){|i|o<<((n[i]==1)?e[j+=1]:32);o<<((i%x==x-1)?10:"")}; puts(o); # '.join
解説
eval$s=%w'〜'.join
を使って、%$
(すなわちジェネレータのコード) をAAにしている%w'〜'.join
することで、AAに余分な改行や空白が入らないようにしている- 結果としてコードには、改行や空白や
'
をいれることはできない
e=$s*3;
で、AA化するソースコードが、AAの文字数より多くなるように水増ししている- 10行目の
#
により、2回目以降出力されるコードはコメント扱いになる
- 10行目の
0.upto(x*y){|i|o<<((n[i]==1)?e[j+=1]:32);o<<((i%x==x-1)?10:"")};
にて、e
に格納されたソースコードをAAに流し込んでいる
実行結果
b="BAhsK2L gf4D/D/7/8/9/ //j/B/9/8P8H/3/w/ wf/f/7/7////+//P/j/ Af5/AOAP APwAAMCHH 3z4wYcf fPjBhx98 +MGHH/z /wf8//P+ D/z/gnw MAAAAPAP gBAA8AA ADAPwD8A 4A/APgD gB8A+AGA HwD4AeA /AP4D4D8A/g MAAOD8A/ 7/4P8f/v/D/ z/88MMPP/zwww8//PDDD z/88AMAAPD/wP8//v //D/7/////f/// 8x8A/wPg/z/8/w P/PwA=" ;n=Mar shal. load(b .unpa ck("m" )[0]) ;x=20; y=74; e=$s*3 ;o="" ;j=-1; 0.upt o(x*y) {|i|o <<((n[ i]==1)?e[j+=1]: 32);o<<((i%x==x- 1)?10:"")};puts( o)b="BAhsK2Lgf4 D/D/7/8/ 9// /j/B /9/8P8 H/3/ w/wf/f/7 /7////+/ /P/j/Af 5/AOAPA PwAAMC HH3z4w YcffPj Bhx98+ MGHH/z/wf 8//P+D/z/ gnwMAAAAP APgBAA8AA ADA PwD8A4A/ APgDgB8A+AGAHwD 4AeA/AP4D4D8A/gM AAOD8A/7/4P8f/v/D /z/88MMPP/zwww8/ /PDDDz /88AMA APD/wP 8//v// D/7/// //f/// 8x8A/w Pg/z/8 /wP/Pw A=";n= Marsha l.load (b.unp ack("m ")[0]);x=20; y=74;e=$s*3;o="" ;j=-1;0.upto(x*y){| i|o<<((n [i]==1) ?e[j+=1]:32);o<<((i% x==x-1)?10:"")};put s(o)b="BAhsK2Lgf4D /D/7/8/9/ //j/B/9/8P 8H/3/w/wf/f/7/7// //+//P/j/Af5/AOA PAPwAAMCHH3z4w
ここからジェネレータさらに加工して、上記AAを実行できるようにする
5. 「AAジェネレーターをAAのQuineにする」ジェネレータを作成
Syntax Error
回避のために、上記のコードを文字列として結合して、eval する処理を追加する- さらに、それをQuine化する
ベースとなるQuine
eval$s=%w'o="eval$s=%w"<<39<<$s<<39<<".join";puts(o)'.join
39
は、'
。%w'〜'
の中で'
を使用するために数値を使用
このQuineは、o="...
の前に任意のコードを埋めることができる
例
eval$s=%w'a="aaa";o="eval$s=%w"<<39<<$s<<39<<".join";puts(o)'.join
それを利用して以下のように、AAを作成するコードをQuineに埋め込む
ソースコード
eval$s=%w'b="BAhsK2Lgf4D/D/7/8/9///j/B/9/8P8H/3/w/wf/f/7/7////+//P/j/Af5/AOAPAPwAAMCHH3z4wYcffPjBhx98+MGHH/z/wf8//P+D/z/gnwMAAAAPAPgBAA8AAADAPwD8A4A/APgDgB8A+AGAHwD4AeA/AP4D4D8A/gMAAOD8A/7/4P8f/v/D/z/88MMPP/zwww8//PDDDz/88AMAAPD/wP8//v//D/7/////f///8x8A/wPg/z/8/wP/PwA="; n=Marshal.load(b.unpack("m")[0]); x=20; y=74; e="eval$s=%w"<<39<<($s*3); o=""; j=-1; 0.upto(x*y){|i|o<<((n[i]==1)?e[j+=1]:32);o<<((i%x==x-1)?10:"")}; o[-10,6]=""<<39<<".join"; puts(o); # '.join
解説
e="eval$s=%w"<<39<<($s*3);
が、Quineの先頭部分o[-10,6]=""<<39<<".join";
で、AAで出力されるコードの末尾を'.join
に置き換えて、Quineの末尾にしている
実行結果
eval$s=%w' b="BAhsK2Lgf4 D/D/7/8/9///j/B/9 /8P8H/3/w/wf/f/7/7/ ///+//P/ j/Af5/AOA PAPwAAM CHH3z4wY cffPjBh x98+MGHH /z/wf8/ /P+D/z/g nwMAAAA PAPgBAA8 AAADAPw D8A4A/AP gDgB8A+ AGAHwD4AeA/ AP4D4D8A /gMAAOD8A/7 /4P8f/v/D/z/88MMPP/z www8//PDDDz/88AMA APD/wP8//v//D/ 7/////f///8x8A /wPg/z/ 8/wP/P wA="; n=Mars hal.l oad(b. unpac k("m") [0]); x=20;y =74;e ="eval $s=%w "<<39< <($s* 3);o=" ";j=-1;0.upto(x *y){|i|o<<((n[i] ==1)?e[j+=1]:32) ;o<<((i%x==x-1) ?10:"")} ;o[ -10, 6]=""< <39< <".join" ;puts(o) ;#b="BA hsK2Lgf 4D/D/7 /8/9// /j/B/9 /8P8H/ 3/w/wf/f/ 7/7////+/ /P/j/Af5/ AOAPAPwAA MCH H3z4wYcf fPjBhx98+MGHH/z /wf8//P+D/z/gnwM AAAAPAPgBAA8AAADA PwD8A4A/APgDgB8A +AGAHw D4AeA/ AP4D4D 8A/gMA AOD8A/ 7/4P8f /v/D/z /88MMP P/zwww 8//PDD Dz/88A MAAPD/ wP8//v //D/7/ ////f///8x8A /wPg/z/8/wP/PwA= ";n=Marshal.load(b. unpack(" m")[0]) ;x=20;y=74;e="eval$s =%w"<<39<<($s*3);o= "";j=-1;0.upto(x*y ){|i|o<<( (n[i]==1)? e[j+=1]:32);o<<(( i%x==x-1)?10:"") };o[-10,'.join
これで完成!!
ポイント
「AAのデータとアスキーアートジェネレーターをAAのQuineにする」ジェネレータを作って、AAのQuineを作成している
- AAをBase64にしてコードに埋め込んでいる
- AAの文字数とソースコードの文字数の不一致を何とかするために、コードの末尾をコメントにしてコードを3倍にしたものをAAに使用している
- そのため、末尾の5文字はコメントのハズなので、
'.join
で置換しても問題がない
- そのため、末尾の5文字はコメントのハズなので、
- 基本となる Quine は
eval$s=%w'puts"eval$s=%w"<<39<<$s<<39<<".join"'.join
eval$s='〜'.join
というコードのために、'
と空白文字が使用できない
感想
evalを使ったQuineは脳が裏返る感じがする