こちらの記事を元に自分で作ってみた時の記録です
mickey24.hatenablog.com
ソースコード
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回目以降出力されるコードはコメント扱いになる
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
で置換しても問題がない
- 基本となる Quine は
eval$s=%w'puts"eval$s=%w"<<39<<$s<<39<<".join"'.join
eval$s='〜'.join
というコードのために、'
と空白文字が使用できない
感想
evalを使ったQuineは脳が裏返る感じがする