Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Quine・難解プログラミングについて

11,581 views

Published on

第 379 回 PTT の発表で使った資料です。
http://www.ci.i.u-tokyo.ac.jp/~sasada/ptt/arc/379/

Published in: Entertainment & Humor
  • Be the first to comment

Quine・難解プログラミングについて

  1. 1. Quine・難解プログラミングについて 遠藤侑介
  2. 2. 自己紹介: 遠藤侑介• 会社員 – 本発表は完全に趣味の内容です• Ruby コミッタ – Ruby 2.0 リリースマネージャ (2013年リリース予定) – 本発表はこの内容でもありません• esoteric programmer ← 今日のテーマ – Twitter: @mametter – Blog(日本語): http://d.hatena.ne.jp/ku-ma-me/ – Blog(英語): http://mamememo.blogspot.com/ 2
  3. 3. Esoteric Programming • 普通の人 puts “Hello, world!” • Esoteric Programmer alias|send¥ ;$stdin=GC | "%p?"%def# FALSE.gets();(8 | 64).chr+232424. to_s(25)+", "+%w|w ! | *"orlc". next<<012|| (c).Yusuke end;"oh, 2009" | "stegano-X."[0,4].reversed,be="whydoes","crypto";:make. | %.mains..treams,be.delete(d) • 参考: code golfer (14B) #!../s/grb -eh http://d.hatena.ne.jp/kurimura/20090929/1254257912 3
  4. 4. Esoteric Programming Language (esolang) • 読み書きしにくいように作られた言語 – esoteric: 難解な、深遠な、秘伝的な、奥義に達した – ex) brainf**k, whitespace • 共通の特徴:奇妙な制約 +++++++++[>++++++++>++++++++++ +>+++++<<<]>.>++.+++++++..+++. – 使える文字・レイアウト >-.------------.<++++++++.---- ----.+++.------.--------.>+. – 使える命令 Hello world in brainf**k – 変な意味論 • Ruby も制限をすれば esolang になる – 使用文字の制限とか Hello world in whitespace 4
  5. 5. 今日の内容1. 使用文字を制限して Ruby を書く (中)2. Ruby で美しい Quine を書く (易)3. esolang で Quine を書く (難) 5
  6. 6. 1.使用文字を制限して Ruby を書く 6
  7. 7. 数字だけで Rubyrequire "1234567890"3168058133690614704472525542553548167675787479850929569348012322294505786632921189012284531906696218369564670777459615871118090530 任意のプログラムが書けます 7
  8. 8. 数字だけで Ruby実装• プログラムの数値化• Ruby の黒魔術• gem install 1234567890_ で公開中 8
  9. 9. 数字だけで RubyGödel 数によるコードの数値化• 任意の文字を自然数にエンコードする – in: ������1 , ������2 , ������3 , ������4 , ������5 , ������6 , ������7 , … – out: 2������1 × 3������2 × 5������3 × 7������4 × 11������5 × 13������6 × 17������7 × ⋯ – デコードは素因数分解• 実際には以下のようにしている – out: 2560 ������1 + 2561 ������2 + 2562 ������3 + 2563 ������4 + ⋯ – 0 ≤ ������������ < 256 とわかっているのでこれで十分 9
  10. 10. 数字だけで Rubyコードの数値化の実装• エンコード – num = str.unpack(“H*”)[0].hex • “abc”.unpack(“H*”) #=> [“616263”] • “616263”.hex #=> 0x616263 = 6382179• デコード – [num.to_s(16)].pack(“H*”) • 6382179.to_s(16) #=> “616263” • [“616263”].pack(“H*”) #=> “abc”• エンコード時にシグネチャをつけておく – (sig + str).unpack… – 理由は次ページ 10
  11. 11. 数字だけで RubyRuby の黒魔術• コードに書かれただけの数字を引っぱり出す – GC.disable – at_exit – ObjectSpace.each_object(Bignum) – eval• 無関係なBignumも拾えてしまう – シグネチャで判断する – チェックサムもつけとけばよかった Ruby 1.8 と 1.9 両方で動く JRuby でも動く(が –X+O オプションが必要) 11
  12. 12. アンダースコアだけで Rubyrequire "_"____ _ _____ ____ __ ____ ______ ___ ____ __ __ _ ______ ________ _ _ ___ _____ ______ ____ __ ____ _ _ ____ _ ____ __ __ ____ ______ ___ ____ __ ______ _____ ____ ____ __ _ ____ _ _ ________ _____ _ ______ ____ _______ _____ 12
  13. 13. アンダースコアだけで Ruby実装• プログラムの数値化(「数値だけ」と同じ)• ゲーデル数を 6 進表記し、各桁をアンダースコアの 数で表す – 123  _ __ ___• _ や __ はメソッド呼び出しなので普通に拾える _ __ _(__) – ただし、 は なので、評価順に注意 ___ ___ • Ruby は Call-by-value なので 無引数 __ 、引数あり _ 、無引数 ___ の順に呼ばれる • 引数の有無を見て _ __ ___ の順に直す 13
  14. 14. Hello world with underscore onlyなぜ6進数か?• 生成されるコード長を短くするため – コードを数値化した値: M – n進数で表現した時の桁数: log ������ ������ ������+3 – 各桁は 1~n 文字のアンダースコア+空白: 平均 2 ������+3 – 生成される平均コード長: log ������ ������ 2 – ������ = 5 で最小• ただし計算間違いして ������ = 6 で公開してしまった – gem install _ で公開中 14
  15. 15. class String def inspect concat begin dup ensure replace String nil concat concat concat concat size concat concat size concat concat size純粋にアルファベットだけで Ruby concat size concat begin size ensure replace String nil end end 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 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 15 concat begin size ensure replace String nil end end eval self end copyright MMX Yusuke Endoh p String nil
  16. 16. 純粋にアルファベットだけで Ruby第一段階: アルファベットと数字だけで Ruby• 浜地慎一郎さんのアイデア http://d.hatena.ne.jp/shinichiro_h/20081109 # p 1 に相当するコード• p String nil p(String(nil)) class String def inspect p(“”) concat 122 # ‘p’ puts(“”.inspect) concat 32 # ‘ ‘• “”.concat 122  “p” concat 49 # ‘1’• “p”.concat 32  “p “ eval self• “p “.concat 49 “p 1” exit end• eval self End eval “p 1” P String nil 16
  17. 17. 純粋にアルファベットだけで Ruby第二段階: アルファベットだけで数字を作る(1)• caller # 3 を作るコード – スタックトレースを Array def f1; caller; end として返すメソッド • [“t.rb:2:in `f2", def f2; f1; end • "t.rb:3:in `f3", def f3; f2; end • "t.rb:5:in `<main>‘”] – メソッド大量でかっこ悪い f3.size• for 文 – ary.each {|i|……} # . なしでメソッドを呼ぶ • の構文糖 • Rubyでは使われない class Array 構文として有名 alias each size – eachをsizeのエイリアス end にすると、for文でsize が呼べる p for i in f3 do end 17
  18. 18. 純粋にアルファベットだけで Ruby第二段階: アルファベットだけで数字を作る(2)• 長さ n の文字列を作る # 4 を作るコード “¥4”を作るコード class String concat begin – concat size:長さを+1 def inspect dup – concat self:長さを×2 concat size ensure – O(log(n)) で表現できる concat self replace ""• コード文字列を生成する部分と concat self concat size size concat self 衝突する end concat self – begin A ensure B end で end concat begin 回避 size • A を評価して B を評価して ensure A の評価結果を返す replace "" end end 18
  19. 19. 「1.使用文字を制限して Ruby を書く」のまとめ• Ruby は使用文字に結構強い• 未解決問題 – 小文字アルファベットだけ – 大文字だけ(不可能?) – 「記号だけ」は解決済み http://www.kurimura.com/rsencode/ 19
  20. 20. 2. Ruby で美しい Quine を書く 20
  21. 21. Quine とは• 自分自身を出力するプログラム eval s="putseval s=+s.inspect"• 実装の基本 – 手順 1. 自分自身を文字列として再構成する – 手順 2. その文字列を出力する• 手順 2 で整形をすると美しい Quine が書ける 21
  22. 22. 山手Quine • 実行すると隣の駅名になる • 29 駅で元に戻る • 起動速度重要 • JRuby is 10x slower than MRI (3.3sec vs. 33sec) 22
  23. 23. 山手Quine実装1. 自分自身を再構成する2. 次の駅の形に整形してから出力する3. 以上をアスキーアートの形で行う – フォントデータ(圧縮) – 駅名(圧縮) – 圧縮の展開 – Quine – 整形 – ゴミ 23
  24. 24. 山手Quineアスキーアートでプログラムを書く1. 空白とバックスラッシュなしでプログラムを書く2. eval %w( と ).join で囲む eval %w( ( pu3. 自由に整形できる ts “H• 注: %w() は文字列配列のリテラル i”• %w(foo bar) = [“foo”, “bar”] ).join##• 元の形を保持したい場合には、二重に eval する eval s=%q(eval %w( ... ).join) 24
  25. 25. 山手Quine圧縮• データサイズとデコーダサイズのトレードオフ デコーダ小 データ小 データ大 デコーダ大• 最適な圧縮方法はデータの大きさや使用文字によっ て変わる • 経験的な方法 データサイズ 方法 ~ 10 バイト 無圧縮で文字列リテラル ~ 100 バイト String#to_i(36) ~ 500 バイト Base64 もっと Zlib + pack 25
  26. 26. quineclock eval s=%w(0;y=""< <32;z="eval((;s=%w(#{s} )*));; %" <<43<<s; d="";" 0v vvnvn2 mj4kil 0v lvvul2 6l94ol 0v lv7vv" .scan (/ .{7}/ ){|n| 2. times {d.< <T ime. now. to_s.unpack(" C*") [11, 8].map{|i|("% 03b" .%7&n .to_i (32)> >3*i- =48).g sub(/. /){s>$ &?y*3: z.slic e!(0,3 )}}*y<<1 0}};puts (d.strip.chop<<43))*# #(c) Y.Endoh 2009 26
  27. 27. quineclock実装 eval s=%w(0;y=""< <32;z="eval((;s=%w(#{s} )*));; %" <<43<<s; d="";" 0v vvnvn2 mj4kil 0v lvvul2 Quine 部分 6l94ol .scan 0v (/ lv7vv" .{7}/ フォントデータ ){|n| {d.< 2. <T times ime. 現在時刻取得 now. to_s.unpack(" C*") デジタル時計の形に整える [11, 8].map{|i|("% 03b" .%7&n .to_i 出力 (32)> >3*i- =48).g sub(/. コピーライト /){s>$ &?y*3: z.slic e!(0,3 )}}*y<<1 0}};puts (d.strip.chop<<43))*# #(c) Y.Endoh 2009 27
  28. 28. quineclock基数変換によるフォント圧縮• 元データ (横 3 × 縦 5 × 文字数 11 = 165 バイト) ### ## ### ### # # ### ### ### ### ### # # # # # # # # # # # # # # # # # # ### ### ### ### ### # ### ### # # # # # # # # # # # # # # ### ### ### ### # ### ### # ### ###• 空白を 0 、# を 1 にして二進数に (165 バイト) 111 110 111 111 101 111 111 111 111 111 000 101 010 001 001 101 100 100 001 101 101 010 101 010 111 111 111 111 111 010 111 111 000 101 010 100 001 001 001 101 010 101 001 010 111 111 111 111 001 111 111 010 111 111 000• 10 進表示に (50 バイト) 1073733623, 2905756245, 1063256021, 2371130133, 1063231487• to_s(36) で36進数に (35 バイト) 0hr9u5z, 1c20fv9, 0hl19lh, 137pjpx, 0hl0qnz• 復元には “%b” % n や Integer#[] が便利 28
  29. 29. Qlobe: 回る地球の Quine v=0000;eval$s=%q~d=%!^Lcf<LK8, _@7gj*LJ=c5nM)Tp1g0%Xv.,S[<>YoP 4ZojjV)O>qIH1/n[|2yE[>:ieC "%.#% :::##" 97N-A&Kj_K_><wS5rtWk@*a+Y5 yH?b[F^e7C/56j|pmRe+:)B "##% ::##########" O98(Zh)Iof*nm.,$C5Nyt= PPu01Avw^<IiQ=5$D-y? "##: ###############" g6`YT+qLw9k^ch|K),tc 6ygIL8xI#LNz3v}T=4W "# #. .####:#######" lL27FZ0ij)7TQCI)P7u }RT5-iJbbG5P-DHB<. " ##### # :############" R,YvZ_rnv6ky-G+4U $*are@b4U351Q-ug5 " #######################" 00x8RR%`Om7VDp4M5 PFixrPvl&<p[]1IJ " ############:#### %#####" EGgDt8Lm#;bc4zS^ y]0`_PstfUxOC(q " .#############:##% .## ." /,}.YOIFj(k&q_V zcaAi?]^lCVYp!; " %% .################. #. " ;s="v=%04o;ev"% (;v=(v-($*+[45, ":####: :##############% : " ])[n=0].to_i;)% 360)+"al$s=%q#{ "%######. ######### " ;;"%c"%126+$s<< 126}";d.gsub!(/ "##########. #######% " |¥s|".*"/,"");; require"zlib"|| "########### :######. " ;d=d.unpack"C*" d.map{|c|n=(n|| ":#########: .######: . " )*90+(c-2)%91}; e=["%x"%n].pack " :#######% :###### #: " &&"H*";e=Zlib:: Inflate.inflate( " ######% .####% :: " &&e).unpack("b*" )[0];22.times{|y| " ####% %### " ;w=(Math.sqrt(1-( (y*2.0-21)/22)**(; " .###: .#% " ;2))*23).floor;(w* 2-1).times{|x|u=(e+ " %## " )[y*z=360,z]*2;u=u[ 90*x/w+v+90,90/w];s[( " #. " ;y*80)+120-w+x]=(""<< 32<<".:%#")[4*u.count(( " . " ;"0"))/u.size]}};;puts¥ s+";_ The Qlobe#{" "*18+ ( "# :#######" ;"Copyright(C).Yusuke End¥ oh, 2010")}";exit~;_ The Qlobe Copyright(C).Yusuke Endoh, 2010 29
  30. 30. Qlobe実装• 世界地図のデータを持っている • データ  zlib 圧縮  巨大な整数化  コード文字列化 • 後述• 出力前に地図データをデコード・レンダリングする• 地球の絵がコードに割り込んで来るのでかわす require“zlib”|| “地球部分" ;d=d.unpack"C*" Inflate.inflate( “地球部分" &&e).unpack("b*" 30
  31. 31. QlobeBignum のコード文字列化• 表示可能な文字だけでエンコードする• ただし、出現位置によって使えない文字がある – 文字列リテラルのデリミタとして使っている文字 • 普通の言語では “ (34) • 今回は ! と “ と ~ を使っている(33, 34, 126) – エスケープ文字 ¥ (92) – Ruby の場合、# (35) にも注意が必要 • “user id: #{ id }” と書ける • 今回の地図データではたまたま #{ の部分列が出現しなかった• 今回は 35 ~ 91、93 ~ 125 の 90 種類の文字を使う – 90 進表記にして、それぞれの桁を各文字に割り当てる • n ∈ {0 .. 89} に対して、 m = ((n+58)%91)+35 の文字を使う • デコード: (m - 2) % 91  n 31
  32. 32. 15quzzle Quine でパネル移動後の盤面が出てくる 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 32
  33. 33. tic-tac-toe (○×ゲーム) (たぶん)世界初、思考ルーチン組み込み対戦型 Quine 33
  34. 34. Quine Reversi 思考ルーチン組み込み、勝たないと Quine してくれない 34
  35. 35. QR code: Q(uine) R(uby) code 35
  36. 36. QR code: Q(uine) R(uby) code(解説)#!ruby# Q(uine)R(uby)code (C) Y.Endoh 2009eval s=%q(X=(0..7).map{|i|1<<i};W=116;m=(1..w=117).map{[]};B=999.times{|i|X<<(X[-4]^X[-5]^X[-6]^X[-8]);n=0x7f415d5d5d417f;i<64&&m[j=i/8][k=i%8]=m[W-j][k]=m[j][W-k]=n[i]};P=6.step 110,26;P.map{|j|P.map{|k|m[j][k]||25.times{|i|m[j-2+i/5][k-2+i%5]=-469441[i]}}};g=[1];m[109.times{|i|m[i][6]=m[6][i]||=1-i;i<15&&m[i.+i<6?0:i<8?1:102][8]=m[8][(i>8?14:i>7?15:W)-i]=26998[i];i<18&&m[i/3][x=i%3+106]=m[x][i/3]=102881[i];i<26&&g=(g+[0]).zip([0]+g.map{|x|X[i+X.index(x)]}).map{|x,y|x^y}}][8]=1;_,*G=g;n=c=12704;b=("404e4#{"%02x"*1252}0#{"ec11"*B}"%%(#!ruby# Q(uine)R(uby)code (C) Y.Endoh 2009¥neval s=%q(#{s})).unpack("C*")).scan /../D=[];E=([106]*8+[107]*4).map{|d|D<<y=b.shift(d).map(&:hex);z=y+G.map{0};y.map{r=X.index z.shift;r&&z=z.zip(G).map{|y,x|x ?y^X[r+X.index(x)]:y}};z};require"¥zlib";(D*B+E*B).map{|l|x=l.shift;x&&n=x+n*256};x=13688;d=[1,W];x.times{m[i=x/w][j=x%w]||=n[c-=1]^i+j+i*j%3+1;x-=y=d.shift;d<<y;0<=x&&x<w*w||x-=3+d[1]=-2-y ;x==6&&x=5};z,e="¥0","¥xff";t=(z+e*125)*16;s="IDAT"+Zlib::Deflate.deflate(t+m .map{|l|[z,e*4,l.map{|x|(e+z)[x&1,1]},e*4]*4}*""+t);print ["¥x89PNG¥r¥n¥x1a¥n",13,"IHDR",500,500,2,0,2752354551,s.size-4,s,Zlib.crc32(s),0,"IEND¥xAEB`¥x82"].pack"A*NA*NNCN3A*NNA*")shebangとコピーライト 原始多項式生成 QRコードの大きなマークの配置QRエンコード Quine部分 QRコードのデータ部分の配置 png生成 36
  37. 37. tkquine eval$s=%q(require"tk" r=Tk.root;r.withdraw x=y=22;s="eval$s=%q(#$s)" f=proc{c=s.slice! 0,1 (f[y+=x=22];next)if"¥n"==c w=TkToplevel.new(r){ withdraw geometry"18x18+#{x}+#{y}" overrideredirect true bind"Button",proc{exit} deiconify } l=TkLabel.new(w,:text=>c) l.pack;x+=22 Tk.after(10,f)if s!="" };f[];Tk.mainloop #(c)YusukeEndoh2010) 37
  38. 38. tkquine 38
  39. 39. tkquine 39
  40. 40. quine-web-servereval$e=%q(putsopen http://localhost:18463;requiresockets=TCPServer.new 18463;c=(/GET +¥/(¥d*)/i=~c.gets;c<<%(HTTP¥/1.0 200 OK¥nContent-Type:text/html¥n¥n)+(eval(%(#$1% 60>0?%(leval$e=%q(¥#$e)#)[#$1,1].sub(&,&amp;).sub(>,&gt;).sub(<,&lt;):<br># ;nil))||%(<title>quine web server</title>The source code of this web server is:<pre id=p>¥</pre><script type=text/javascript>a=i=0;f=function(){a!=0&&a.readyState<4||(a!=0&&(document.getElementById(p).in¥nerHTML+=a.responseText),i++<719&&(a=new XMLHttpRequest() ,a.open(GET,/+i,true),a.onreadystatechange=f,a.send(null)))};f()</script>));puts$_;c.shutdown;c.read;c.close)while¥c=s.accept ## quine-web-server.rb (c) Yusuke Endoh 2009 #)# 40
  41. 41. qng と qif と qvi 自分自身を出力する画像・動画 png gif qvi 41
  42. 42. QB: Q(uine ru)B(y) eval s||= %q(1;t= %w(s.gs ub!(/¥e.* ?m/,"");[ [ 0x26e885c a844a879e27 a,519,48, 5 , 9],[20182686,600,48,5,1],[4366,611,48 , 5 ,15],[432803624050570,533,0]].map { | r,m,*d|s[m+=r%74,0],r="¥e[#{d*";"}m", r /74while(r>0)};puts((z=32.chr)*5+"eval#{z *39}s||=¥n#{z*5}%q(#{(1+n=s.to_i)%3}#{s[1 ..- 1]})¥n¥n"+z*9*n+"5YOV44GvUnVieWlzdO OBq +OB quOBo+OBpuOBj+OCjOOBo+OBpuOAgeOBjeOBo eOC k+OB qOOBi umhmOOBhOOBl+OBn+ OBr+O BmuO BoOO CiO+8 nw ogIOWun+mam+OBr ui ogOiq nuS7 leanm OOBjO OBqeOBhuOBhOOBh uOCgu OBruO Bi+OA geiqrO aYjuOCkuecgeeVpeO Bl+OBn +OBke OCjOOB qeOAgi/lg5XjgajlpZHntITjgZfjgabjgIFSdWJ 5aXN04 4Gr44G q44Gj44Gm5qyy44GX44GE44KT44GgL+WQm+OBn+ OBoeOB r+OBhOOB pOOCguOBneOBhu O B oOOBreOAggrkup Lmj5vmgK fjgafjg 4/jg57jgovjgaj m sbrjgb7jgaPjga blkIzjg Zjlj43lv 5zjgpLjgZnjgovjgILoqLPjgYzliIbjgY vjgonjga rjgYTjgo g=".gsub(/¥e.*?m/,"").unpac k("m")[0 ].split( "/")[n]);exit)*"";; eval(t)) 42
  43. 43. Merry Quine-mas 2009 クリスマスソング演奏機能組み込み Quine 43
  44. 44. Merry Quine-mas 2010 クリスマスソング演奏機能組み込み Quine 44
  45. 45. Quine リレーこのプログラムは、このプログラム自身を出力するUnlambda プログラム、を出力する Whitespace プログラム、を出力する brainfuck プログラム、を出力するJava プログラム、を出力する C プログラム、を出力する Haskell プログラム、を出力する OCaml プログラム、を出力する Lua プログラム、を出力する Perl プログラム、を出力する Python プログラム、を出力する Rubyプログラム、です 45
  46. 46. Quine リレー $ ruby QuineRelay.rb > QuineRelay.py $ python QuineRelay.py > QuineRelay.pl $ perl QuineRelay.pl > QuineRelay.lua $ lua QuineRelay.lua > QuineRelay.ml $ ocaml QuineRelay.ml > QuineRelay.hs $ runghc QuineRelay.hs > QuineRelay.c $ gcc -Wall -o QuineRelay QuineRelay.c $ ./QuineRelay > QuineRelay.java $ javac QuineRelay.java $ java QuineRelay > QuineRelay.bf $ beef QuineRelay.bf > QuineRelay.ws $ wspace QuineRelay.ws > QuineRelay.unl $ unlambda QuineRelay.unl > QuineRelay2.rb $ diff QuineRelay.rb QuineRelay2.rb 46
  47. 47. RubyKaigi 2010 スタッフロール 47
  48. 48. 「2. Ruby で美しい Quine を書く」のまとめ • Ruby は文字配置制約+Quine に滅法強い • あやしい言語機能に感謝 • %w, %q • BEGIN • eval – 文字列整形も強い • String#rjust, split, gsub!, slice!, rstrip • to_i / to_s / Integer#[] • unpack / pack / zlib 48
  49. 49. 3. esolang で Quine を書く 49
  50. 50. esolang と Quine • esolang: わざと難解に作られたプログラミング言語 • 一番有名な esolang: Brainf*ck – 現在最短 Quine (404B) • http://d.hatena.ne.jp/KeisukeNakano/20070626/1182879045 – Brainf*ck 派生言語汎用 Quine 生成器 • http://d.hatena.ne.jp/ku-ma-me/20100322/p1 • esolang での Quine の書き方 – Ruby の eval のような便利なものはない場合が多い – よくあるアプローチ: A+B+C • コード A: 「コード B + Cを表現するデータ」をメモリに載せる • コード B: メモリデータをデコードし、再エンコードして出力する • コード C: メモリデータをデコードして出力する 50
  51. 51. Piet • 画像でプログラミングする esolang – ポインタが 2 次元に駆け回る – 色が異なる領域への移動が命令になっている • push は、移動前領域の大きさの数値を push する – 命令自体は普通のスタックマシン 色相\明度 変化なし 1段階変化 2段階変化 変化なし push pop 1段階変化 add subtract multiply 2段階変化 divide mod not 3段階変化 greater pointer switch Hello world 4段階変化 duplicate roll in (number) in Piet 5段階変化 in (char) out (number) cut (char) 51
  52. 52. Piet での Quine 52
  53. 53. Piet での Quine (上部拡大) 出力コードB: ビットマップを GIF ヘッダを 再エンコードして 出力する 出力する コード B + CコードC: ビットマップを コードA: 上の部分の無圧縮GIFで出力する ビットマップを スタックに載せる もう一回コード A を 実行する コード A 53
  54. 54. Grass • Wとwとvだけで関数適用を表現する関数型esolang Applications : WWWWWwwwwww WWWWWWwwwwwww ... WWWWwwww WW ... |<-5-><-6-->|<-6--><--7-->| | 4 4 | | | | | | | (5, 6) | (6, 7) | | (4, 4) | | apply | apply | | apply | • Grass の Quine 短縮の歴史 – 2008/09/10: 164MB (shinh 、たぶん世界初) – 2008/09/11: 9787B (mame) – 2008/09/14: 1525B (kikx) • http://d.hatena.ne.jp/kikx/20080914 • W を WWw 、w を Ww にエンコードして表現する 54
  55. 55. Grass で Quine (kikx さんによる) wwWWwWWWwWWWWWWwvwwWWwWWWwvwWWwwwWwwwwwwWWWwWWWWWwwwwWwwWWwWwwwwwww wwwwwvWwwwWWwwwvwwWWWWWWWWwwvWwwwWWwwwwwwwwwwWWWwwwwvwWwwwwWwwwwWww wwvwWWWwWWWWWwvwWWWWwWWWwvwWWWWWWWwWWWwvwWWWWWWwWWWWwvwWwwWwwwwwwWw wwwwwvwWwwwwwwwWWwwwWWWWWWwvwwwwWWWWwwWwwWwwwwwvwwvwwwwwWWWWwwwWwwW wwwWwwwwwwwwwWWWWWWWWWWWwwwwwwwWWWWWWWWWWwwwwwwwwwwWwwWwwwwwwwwwwwv wwwwWWWWWwwwwWwwwWWWwwwwwwwwWwwWwwwwwwwvwwwwWwwwWwwwWwwwwwwvwwWWWWw wwwWwwwwWwwwWWWWWwvwWWwWWWWWWWWWwvwWwWwWWwWWwWwWWwWWwWWwWwWWwWWwWWw WWwWWwWWwWwWWWwWwWwWWwWWwWwWWwWWwWWwWwWWWwWwWWwWWwWwWwWwWWwWwWwWwWw WwWwWWwWWwWWwWwWWwWWwWWwWWwWWwWwWwWwWwWWwWwWwWWwWWwWwWWwWwWwWwWwWwW wWwWwWwWwWwWwWWWwWWwWwWwWwWWwWWwWwWwWwWWWwWwWwWWwWWwWWwWWwWWwWWwWWw WWwWwWwWWWwWWwWwWwWwWWwWWwWwWwWwWwWwWwWwWwWwWwWWwWWwWWwWwWwWwWwWWWw WwWWwWwWwWwWwWWwWwWwWwWwWWwWwWwWwWwWWWwWwWWwWWwWWwWwWWwWWwWWwWWwWWw WwWWWwWwWWwWWwWWwWWwWwWWwWWwWWwWwWWWwWwWWwWWwWWwWWwWWwWWwWWwWwWWwWW wWWwWwWWWwWwWWwWWwWWwWWwWWwWWwWwWWwWWwWWwWWwWwWWWwWwWWwWwWwWWwWwWwW wWwWwWwWWwWwWwWwWwWwWwWWWwWwWWwWwWwWwWwWwWwWwWWwWWwWwWwWwWWwWWwWWwW WwWWwWWwWwWWWwWwWwWwWwWWwWWwWWwWWwWwWwWWwWwWwWWwWwWwWwWwWwWWWwWwWwW WWwWwWwWwWwWwWWwWWwWWwWWwWwWwWwWWwWwWwWWwWwWwWwWWwWwWwWwWwWwWwWwWwW wWWwWWwWWwWWwWWwWWwWWwWWwWWwWWwWWwWwWwWwWwWwWwWwWWwWWwWWwWWwWWwWWwW WwWWwWWwWWwWwWwWwWwWwWwWwWwWwWwWWwWwWwWWwWwWwWwWwWwWwWwWwWwWwWwWWWw WwWwWwWwWWwWWwWWwWWwWWwWwWwWwWwWWwWwWwWwWWwWWwWWwWwWwWwWwWwWwWwWwWW wWwWwWWwWwWwWwWwWwWwWwWWWwWwWwWwWwWWwWwWwWwWWwWwWwWwWWwWwWwWwWwWwWw WWWwWwWwWWwWWwWWwWWwWwWwWwWwWWwWwWwWwWwWWwWwWwWwWWwWWwWWwWWwWWwWwWW WwWwWWwWWwWwWWwWWwWWwWWwWWwWWwWWwWWwWWwWwWWWwWwvWWw 55
  56. 56. ModanShogi での Quine • 将棋の棋譜風の Quine*6 ▲1一龍 △2一龍 ▲1一龍 △2一龍 ▲1一龍 △2一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1二飛 *7 △2一龍 ▲1一龍 △1一龍 ▲1一龍 △2一龍 ▲2一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1二飛 *8 ▲2一龍 △1一龍 ▲2一龍 △1一龍 ▲2一龍 △2一龍 ▲1一龍 △1一龍 ▲1一龍△1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1二飛 *9 △2一龍 ▲1一龍 △2一龍 ▲1一龍 △2一龍 ▲2一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1二飛 *10 ▲2一龍 △1一龍 ▲1一龍 △1一龍 ▲2一龍 △2一龍 ▲1一龍△1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1二飛 *11 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲2一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1二飛 *12 ▲2一龍 △2一龍 ▲1一龍 △1一龍 ▲2一龍△2一龍 ▲1一龍 △2一龍 ▲2一龍 △1一龍 ▲2一龍 △1一龍 ▲1一龍 △2一龍 ▲1一龍 △1一龍▲1二飛 *13 △2一龍 ▲2一龍 △1一龍 ▲1一龍 △2一龍 ▲1一龍 △1一龍 ▲1一龍 △2一龍 ▲2一龍 △2一龍 ▲2一龍 △2一龍 ▲2一龍 △2一龍 ▲2一龍 △1二飛 *14 ▲1一龍 △1一龍 ▲1一龍△1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △2一龍 ▲2一龍 △2一龍 ▲1一龍 △1一龍▲2一龍 △1一龍 ▲1二飛 *15 △2一龍 ▲1一龍 △1一龍 ▲1一龍 △2一龍 ▲1一龍 △2一龍 ▲2一龍 △2一龍 ▲1一龍 △1一龍 ▲1一龍 △2一龍 ▲1一龍 △1一龍 ▲2一龍 △1二飛 *16 ▲1一龍△1一龍 ▲1一龍 △1一龍 ▲1一龍 △2一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1一龍 △1一龍▲1一龍 △1一龍 ▲1一龍 △1一龍 ▲1二飛 *17 △1一龍 ▲2一龍 △1一龍 ▲1一龍 △2一龍 ▲2一龍 △1一龍 ▲2一龍 △2一龍 ▲1一龍 △2一龍 ▲1一龍 △1一龍 ▲2一龍 △1一龍 ▲1一龍 △1二飛 *18 ▲1一龍 △2一龍 ▲2一龍 △1一龍 ▲2一龍 △1一龍 ▲1一龍 △1一龍 ▲2一龍 △2一龍(略) 56
  57. 57. 自己記述集合THIS IS “THE SELF-DESCRIPTION SET ������” WHERE������ = ������, ������ : ������ ∈ ℝ ∧ ������ ∈ ℝ ∧ ������ , ������ ∈ ℬ ∪ ������ℬ = ������, ������ + 1 : ������ ∈ ℐ 0, 240 ∧ ������ ∈ ℐ 0, 59 ∧ ������ ������, 240������ + ������, 2 = 1������ = ������, −������ − 1 : ������ ∈ ℐ 0, 240 ∧ ������ ∈ ℐ 0, 419 ∧ ������ ������, ������ = 1ℐ ������, ������ = ������ ∈ ℤ ∶ ������ ≤ ������ < ������ ������������ ������, ������ = ������ ������ 2ℱ, ������ ������, 4199 − 60 6 ������ − , 10 , 1048576 , 4������������������ ������, 6 + ������������������ ������, 4 , 2 4������ ������, ������, ������ = ������������������ ������������ −������ , ������ℱ = 731024063570851866511465264858993450227206304418681785374039������ = 1431487833696853176700157431078133300807345625216694848607028845592243617643316119085595555875582798798158387973177961695587578188817228313270884309874099454731913241985765682402 57
  58. 58. 自己記述集合自己記述集合を x-y 平面にプロット 58
  59. 59. 自己記述集合の解説• Quine の考え方と同じ – 上半分(第一象限)はコード B+C • ビットマップデータ ������ (コード������)をプロットする – 下半分(第四象限)はコード A • コード B+C を表すビットマップデータ ������ を定義する 59
  60. 60. 自己記述集合自己記述集合の解説(上半分)• ビットマップデータ ������ を������軸より上にプロットする• ������: 数式部分のビットマップデータを10進表記したもの• ℐ ������, ������ = ������ ∈ ℤ ∶ ������ ≤ ������ < ������ – 補助関数、 ������ から������の間の整数の集合• ������ ������, ������, ������ = ������������������ ������������ −������ , ������ – 補助関数、������ を ������ 進表記した時の下から ������ 番目の桁を取り出す ������, ������ + 1 : ������ ∈ ℐ 0, 240 ∧ ������ ∈ ℐ 0, 59 ∧• ℬ= ������ ������, 240������ + ������, 2 = 1 – 0 ≤ ������ < 240 かつ 0 ≤ ������ < 59 の範囲で、 – ������ ������, 240������ + ������, 2 = 1 を満たす ������ と ������ の値 60
  61. 61. 自己記述集合自己記述集合の解説(下半分)• データ ������ をフォントデータ ℱ で������軸より下にプロットする• ℱ: フォントデータを10進表記した数字(の半分) – フォントは横 4 ×縦 5 ピクセル(行間をあけるために4×6として扱う) ������ ������• ������ = ������ ������, 4199 − 60 − , 10 6 4 – (x/4, y/6) の位置に書くべき数字を 10 進でとりだす – 4199 は ������ の総桁数、60 は一行あたりに書く桁数• ������ = ������ 2ℱ, ������, 1048576 – その数字のフォントデータを取り出す(1048576 = 24×5 )• ������ ������, ������ = ������ ������, 4������������������ ������, 6 + ������������������ ������, 4 , 2 ������, −������ − 1 : ������ ∈ ℐ 0, 240 ∧ ������ ∈ ℐ 0, 419 ∧• ������ = ������ ������, ������ = 1 – そのフォントデータをビットマップ(2進)に直したもの 61
  62. 62. 自己記述集合自己記述集合の解説(全体)• ������ = ������, ������ : ������ ∈ ℝ ∧ ������ ∈ ℝ ∧ ������ , ������ ∈ ℬ ∪ ������ – ℬ か ������ のいずれかに含まれる 整数組 ������, ������ を実数平面にプ ロットする 62
  63. 63. 全体まとめ• Quine・難解プログラミングは面白い – Ruby も esolang 63

×