2. Who am I?
• Yusuke Endoh 遠藤侑介
– twitter: @mametter
– hatena: http://d.hatena.ne.jp/ku-ma-me/ in Japanese
– blogger: http://mamememo.blogspot.com/ in English
• A committer for Ruby and RubySpec
– 1.9.2 assistant release manager
• An esoteric programmer
2
4. Esoteric Programming Language (esolang)
• 読み書きしにくいように作られた言語
obfuscated, confusing and unreadable programming language
– esoteric: 難解な、深遠な、秘伝的な、奥義に達した
– ex) brainf**k +++++++++[>++++++++>++++++++++
+>+++++<<<]>.>++.+++++++..+++.
>-.------------.<++++++++.----
----.+++.------.--------.>+.
• 共通の特徴:奇妙な制約 Hello world in brainf**k
common feature: bizarre constraint
– 使える文字 bizarre kind of character used
– 使える命令 bizarre instruction set
– 命令順序や文字配置 bizarre execution order and placement
4
5. Theme: Enjoy esolang with Ruby!
• 制約を課せば Ruby も esolang として楽しめる
Ruby with constraint can be an esolang
– 1. 使用文字制約に勝つ ( ○○文字だけで Ruby を書けるか?)
beat “character constraints” (Can you write Ruby with __ character-only?)
– 2. 文字配置制約に勝つ (アスキーアート Quine)
beat “shape constraints” (ASCII-art Quine)
• 見所 Highlights
• ゲーデル数 Gödel numbering
– むだに深淵な背景理論 • コルモゴロフ複雑性 Kolmogorov complexity
esoteric theory • チューリング完全性 Turing completeness
– 勝つためなら何でもする • Ruby の黒魔術 Ruby’s black magic
• コードゴルフ code golf
dirty hack • 文法や意味論の悪用 abuse of syntax/semantics
5
7. Hello world with Number only
require "1234567890"
316805813369061470447252554255354
816767578747985092956934801232229
450578663292118901228453190669621
8369564670777459615871118090530
任意のプログラムが書けます
you can write not only “Hello, world!” but also any program
7
8. Hello world with number only
実装 internal
• ゲーデル数化 Encoding: Gödel numbering
• Ruby の黒魔術 Ruby’s black magic
• you can install: gem install 1234567890_
8
10. Hello world with number only
黒魔術 Ruby’s black magic
• コードに書かれただけの数字の参照を引っぱり出す
How to gain number written in code directly
– GC.disable
– at_exit
– ObjectSpace.each_object(Bignum)
– eval
1.8 と 1.9 両方で動く both 1.8 and 1.9 can run this
JRuby でも動く(が –X+O オプションが必要)
JRuby can also run this, but needs -X+O option; uncool
10
12. Hello world with underscore only
実装 internal
• プログラムのゲーデル数化 (“number only” と同じ)
also uses Gödel numbering
• ゲーデル数の 6 進数表記をアンダースコアで表す
represent each base-6 digit of Gödel number as length of underscores
• Ruby の有名黒魔術: method_missing
Ruby’s famous black magic: method_missing
• you can install: gem install _
12
14. class String
def inspect
concat begin dup ensure replace String nil
concat concat concat concat size
concat concat size
concat concat size
concat size
concat begin size ensure replace String nil end end
Hello world with purely Alphabet only
concat begin dup ensure replace String nil
concat concat concat concat concat concat size
concat size
concat begin size ensure replace String nil end end
concat begin dup ensure replace String nil
concat concat size
concat concat concat concat size
concat concat concat size
concat begin size ensure replace String nil end end
concat begin dup ensure replace String nil
concat concat size
concat concat concat size
concat concat size
class String
concat
concat
concat
begin
concat concat
dup ensure replace String
concat
concat
size
concat begin size ensure replace String nil end end
concat nil
size
size
concat concat concat concat size
def inspect
concat
concat
concat
concat
begin
concat
dup ensure replace String
concat
concat
concat
size
concat begin size ensure replace String nil end end
nil
size
size
concat concat size
concat begin dup ensure replace String nil
concat
concat
concat
concat
concat
size
size
size
concat begin size ensure replace String nil end end
concat begin dup ensure replace String nil
concat concat size
concat concat concat concat size
concat
concat
concat
concat
concat
concat
concat
concat
concat
concat
size
size
size
size
size
concat begin size ensure replace String nil end end
concat concat size
concat begin dup ensure replace String
concat concat concat concat concat concat size
nil
concat begin size ensure replace String nil end end
concat
concat
begin dup ensure replace String
concat concat
nil
size
concat concat size
concat concat size
concat
concat
concat
begin
concat concat
dup ensure replace String
concat
concat
concat
size
concat begin size ensure replace String nil end end
concat nil
size
size
concat concat size
concat size
concat
concat
concat
concat begin
concat
concat
dup ensure replace String
size
size
size
concat begin size ensure replace String nil end end
nil
concat concat size
concat begin size ensure replace String nil end end
concat
concat
concat
concat
concat
concat
concat
concat
size
size
size
concat begin size ensure replace String nil end end
concat begin dup ensure replace String nil
concat concat size
concat begin dup ensure replace String nil
concat
concat
concat
concat
concat
concat
concat
concat
size
size
size
concat begin size ensure replace String nil end end
concat begin dup ensure replace String nil
concat concat size
concat concat concat concat concat concat size concat
concat
concat
concat
concat
concat concat
concat
size
size
size
concat begin size ensure replace String nil end end
concat begin dup ensure replace String nil
concat concat concat concat size
concat size
concat
concat
concat
concat concat concat
dup ensure replace String
concat concat
concat
concat
size
concat begin size ensure replace String nil end end
concat begin nil
size
size
concat concat size
concat begin size ensure replace String nil end end
concat
begin dup ensure replace String
concat concat concat concat concat concat size
size
concat begin size ensure replace String nil end end
concat nil
concat begin size ensure replace String nil end end
concat begin dup ensure replace String nil
concat concat size
• require がない
concat concat size
concat concat concat concat size
concat concat size
concat size
concat begin size ensure replace String nil end end
concat begin dup ensure replace String nil
concat concat size
concat concat size
there is no “require”
concat concat concat size
concat concat concat size
concat begin size ensure replace String nil end end
concat begin dup ensure replace String nil
concat concat size
concat concat size
concat concat concat size
concat concat concat size
concat size
concat begin size ensure replace String nil end end
concat begin dup ensure replace String nil
concat concat size
concat concat size
concat concat concat concat concat size
exit end
14
concat begin size ensure replace String nil end end
eval self
end
copyright MMX Yusuke Endoh p String nil
15. Hello world with purely alphabet only
実装 internal
• 自分で読んでください
no time to explain; please read code by yourself
– http://d.hatena.ne.jp/ku-ma-me/20100709/p1
– You can read it because it is purely written in Ruby that you know!
• shinh さんのアイデアがベース
based on shinh’s idea (Shin’ichiro Hamaji)
– アルファベットと数字だけ
Pure Ruby with Alphabet and Number only
– http://d.hatena.ne.jp/shinichiro_h/20081109#1226217059
15
16. 対「文字制約」まとめ
summary of anti-character constraints
• Ruby は使用文字制約に結構強い
Ruby beats character constraints
• おまけ: 1.8 と 1.9 は意外に互換である
1.9 is more compatible with 1.8 than you think
• 未解決問題 open problem
– 小文字アルファベットだけ lower-case alphabet only
– 大文字だけ(不可能?) upper-case only (impossible?)
– 「記号だけ」は解決済み FYI: “punctuation only” was resolved
http://www.kurimura.com/rsencode/
16
18. Quine とは What’s Quine?
• 自分自身を出力するプログラム a program that outputs itself
eval s="puts'eval s='+s.inspect"
• 実装の基本 implementation basis
– 手順 1. 自分自身を文字列として再構成する
Step 1. construct a string that is itself
– 手順 2. その文字列を出力する
Step 2. print it
• 出力前に整形すると変な Quine ができる
we can write “artistic” Quine by shaping it before printing
18
19. 山手Quine Yamanote Quine
• 実行すると隣の駅名になる
This program transforms the next station
name of Japanese Yamanote Loop Rail line
• 29 駅で元に戻る
we need invoke ruby 29 times (stations) once
– 起動速度重要
invoking speed matters
– JRuby is 10x slower than MRI
(3.3sec vs. 33sec)
19
20. Yamanote Quine
実装 internal
1. 自分自身を再構成する
Step 1. construct a string that is itself
2. 次の駅の形に整形してから出力する
Step 2. print it after shaping it as the next station name
3. 以上をアスキーアートの形で行う
Step 3. write the program in ascii art
– フォントデータ(圧縮) font data (compessed)
– 駅名(圧縮) station names (compessed)
– 圧縮の展開 decompressing
– Quine
– 整形 shaping
– ゴミ padding
20
21. Yamanote Quine
アスキーアートでプログラムを書く
How to write “shaped” Ruby program
1. 空白とバックスラッシュなしでプログラムを書く
write your program with no space and backslash
2. eval %w と ).join で囲む enclose it
((
3. 自由に整形できる eval %w(
you can shape it as you like
pu
ts
• 注: %w() は文字列配列のリテラル “H
NOTE: %w() is a literal for Array
i”
• %w(foo bar) = [“foo”, “bar”]
).join##
21
22. Yamanote Quine
圧縮 compression
• データサイズとデコーダサイズのトレードオフ
trade off between compressed data size and its decoder size
デコーダ小 shorter decoder データ小 shorter data
データ大 longer data デコーダ大 longer decoder
• 最適な圧縮方法はデータの規模によって変わる
best decoder depends on data size
data size (about) decoder
~ 10 bytes No compression
• コルモゴロフ複雑性とか
feel Kolmogorov complexity ~ 100 bytes String#to_i(36)
– see Wikipedia ~ 500 bytes Base64
More Zlib + pack
22
23. 15quzzle
Quine でパネル移動後の盤面が出てくる
This prints new board that space was moved to specified direction
eval$s=%w[b=0 x40e1359a76cb d8f2;i=(m=0.. 15).find{|i|1
>b&m=15<<4*i} ;t=m|n=m<<4*o =("AdABrBlBAu A"=~/(.)#{ARG
V*''}¥1/||04| |0)-4;(n<1||n >1<<64||[255< <12]&[t>>040|
|___________2 |__________15 |___________8 |__________13
|0,t>>16,t]!= [])?t=0:i+=o; ;s="eval$s=%% w[b=0x%016x"%
(b^=t.&b|m&b> >o*4)+$s.gsub (/(¥|_+¥d+)+/ ,'')[/;.*/]+"
]*''||0"<<92| |1;z=s=s.scan (/.{13}/);3.t imes{|j|s[(i|
|__________11 |__________12 |___________6 |___________7
|0)/4*8+i+j*4 ,0]=m=(z=32.c hr)*13};c=b;4 .times{puts((
0..3.times{pu ts((s.slice!( 0,4)*z).rstri p)}).map{j=c%
16;c/=16;;(0| |0)<(j)?"|"+j .to_s.rjust(1 2,"_"):m}*(z|
|__________10 |___________9 |___________5 |___________3
|0),z)};b==0x fedcba9876543 21&&("%b"%"1t
v7c1th0wylel7 3ba35knw3t".t o_i(36)).tr("
01",".#").sca n(/.{25}/){pu ts$&}]*''||0¥
|___________1 |__________14 |___________4
23
27. qng と qif
画像自身を出力する画像
images that draws a program that prints the image itself
png
gif
27
28. Quine relay
# ruby
l=92.chr;eval s="s=s.dump[r=1..-
2].gsub(/("+l*4+"){4,}(?!¥")/){|t|'¥"+l*%d+¥"'%(t.size/2)};5.times{s=s.dump[r]};puts¥"#
python¥¥nprint(¥¥¥"# perl¥¥¥¥nprint(¥¥¥¥¥¥¥"# lua"+l*4+"nprint("+l*7+"¥"(* ocaml
*)"+l*8+"nprint_endline"+l*15+"¥"-- haskell"+l*16+"nimport Data.List;import Data.Bits;import
Data.Char;main=putStrLn("+l*31+"¥"/* C */"+l*32+"n#include<stdio.h>"+l*32+"nint
main(void){char*s[501]={"+l*31+"¥"++intercalate"+l*31+"¥","+l*31+"¥"(c(tail(init(show("+l*31+"¥
"/* Java */"+l*32+"npublic class QuineRelay{public static void
main(String[]a){String[]s={"+l*31+"¥"++intercalate"+l*31+"¥","+l*31+"¥"(c("+l*31+"¥"brainfuck"+
l*64+"n++++++++[>++++<-]+++++++++>>++++++++++"+l*31+"¥"++(concat(snd(mapAccumL h
2("+l*31+"¥"110"+l*31+"¥"++g(length )++"+l*31+"¥"22111211100111112021111102011112120012"+l*31+"
¥"++concatMap("+l*32+"c->let d=ord c in if
d<11then"+l*31+"¥"21002"+l*31+"¥"else"+l*31+"¥"111"+l*31+"¥"++g++"+l*31+"¥"22102"+l*31+"¥")s++"
+l*31+"¥"21002111010120211222211211101000120211021120221102111000110120211202"+l*31+"¥"))))))++
"+l*31+"¥","+l*63+"¥""+l*64+"n"+l*63+"¥"};int
i=0;for(;i<94;i++)System.out.print(s[i]);}}"+l*31+"¥")))))++"+l*31+"¥",0};int
i=0;for(;s[i];i++)printf("+l*63+"¥"%s"+l*63+"¥",s[i]);puts("+l*63+"¥""+l*63+"¥");return
0;}"+l*31+"¥");c s=map("+l*32+"s-
>"+l*31+"¥""+l*63+"¥""+l*31+"¥"++s++"+l*31+"¥""+l*63+"¥""+l*31+"¥")(unfoldr t s);t[]=Nothing;t
s=Just(splitAt(if length s>w&&s!!w=='"+l*31+"¥"'then 501else w)s);w=500;f 0=Nothing;f
x=Just((if x`mod`2>0then '0'else '1'),x`div`2);g x= reverse (unfoldr f x);h p c=let d=ord c-
48in(d,replicate(abs(p-d))(if d<p then '<'else '>')++"+l*31+"¥"."+l*31+"¥");s="+l*31+"¥"#
ruby"+l*32+"n"+l*31+"¥"++"+l*31+"¥"l=92.chr;eval
s=¥"+(z=l*31)+¥"¥¥¥"¥"+s+z+¥"¥¥¥""+l*31+"¥"++"+l*31+"¥""+l*32+"n"+l*31+"¥""+l*15+"¥""+l*7+"¥")"
+l*4+"n¥¥¥¥¥¥¥")¥¥¥")¥"########### (c) Yusuke Endoh, 2009 ###########¥n"
28
29. Quine relay
• このプログラムは、このプログラム自身を出力する
Unlambda プログラム、を出力する Whitespace プログラ
ム、を出力する brainfuck プログラム、を出力する Java
プログラム、を出力する C プログラム、を出力する
Haskell プログラム、を出力する OCaml プログラム、を出
力する Lua プログラム、を出力する Perl プログラム、を出
力する Python プログラム、を出力する Ruby プログラム、
です
• This is a Ruby program that outputs a Python program
that outputs a Perl program that outputs a Lua program
that outputs a OCaml program that outputs a Haskell
program that outputs a C program that outputs a Java
program that outputs a brainfuck program that outputs a
Whitespace program that outputs a Unlambda program
that outputs the program itself.
29
30. 対「文字配置制約」まとめ
summary of anti-shape constraints
• Ruby は文字配置制約+Quine に滅法強い
Ruby beats shape constraints and Quine
– あやしい言語機能に感謝 thanks to weird language features
• %w, %q
• BEGIN
• eval
– 文字列整形も強い also useful methods for string shaping
• String#rjust, split, gsub!, slice!, rstrip
• to_i / to_s / Integer#[]
• unpack / pack / zlib
30
31. 結論 conclusion
• Why don’t you enjoy esolang with Ruby?
– むだに深淵な背景理論 esoteric theory
– 勝つためなら何でもする dirty hack
• 教訓 lessons
– 1.8 と 1.9 は意外と互換
1.9 is more compatible with 1.8 than you think
– 起動速度重要
invoking speed matters for esoteric programming; JRuby is too slow
31
32. 最後に aside
• 来年 RubyKaigi 併設で IORCC やりたい
I hope IORCC to be held in conjunction with the next RubyKaigi
– International Obfuscated Ruby Code Contest
__END__
32
33. 実行に 5 分かかる Quine
Quine that takes five minutes
33