SlideShare a Scribd company logo
Quine・難解プログラミングについて


 遠藤侑介
自己紹介: 遠藤侑介
• 会社員
  – 本発表は完全に趣味の内容です
• Ruby コミッタ
  – Ruby 2.0 リリースマネージャ (2013年リリース予定)
  – 本発表はこの内容でもありません
• esoteric programmer ← 今日のテーマ

  – Twitter: @mametter
  – Blog(日本語): http://d.hatena.ne.jp/ku-ma-me/
  – Blog(英語): http://mamememo.blogspot.com/


                                                 2
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].reverse
d,be="whydoes","crypto";:make.     |     %.mains..tr'eams',be.delete(d)


 • 参考: code golfer (14B)
                           #!../s/grb -eh

                                http://d.hatena.ne.jp/kurimura/20090929/1254257912

                                                                                 3
Esoteric Programming Language (esolang)
 • 読み書きしにくいように作られた言語
   – esoteric: 難解な、深遠な、秘伝的な、奥義に達した
   – ex) brainf**k, whitespace
 • 共通の特徴:奇妙な制約        +++++++++[>++++++++>++++++++++
                      +>+++++<<<]>.>++.+++++++..+++.
   – 使える文字・レイアウト      >-.------------.<++++++++.----
                      ----.+++.------.--------.>+.
   – 使える命令
                          Hello world in brainf**k
   – 変な意味論
 • Ruby も制限をすれば
   esolang になる
   – 使用文字の制限とか            Hello world in whitespace


                                                      4
今日の内容
1. 使用文字を制限して Ruby を書く (中)
2. Ruby で美しい Quine を書く (易)
3. esolang で Quine を書く (難)




                             5
1.使用文字を制限して Ruby を書く


                       6
数字だけで Ruby

require "1234567890"

316805813369061470447252554255354
816767578747985092956934801232229
450578663292118901228453190669621
8369564670777459615871118090530
 任意のプログラムが書けます



                                7
数字だけで Ruby
実装
• プログラムの数値化
• Ruby の黒魔術

• gem install 1234567890_ で公開中




                                    8
数字だけで Ruby
Gö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
数字だけで 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
数字だけで Ruby
Ruby の黒魔術
• コードに書かれただけの数字を引っぱり出す
  –   GC.disable
  –   at_exit
  –   ObjectSpace.each_object(Bignum)
  –   eval
• 無関係なBignumも拾えてしまう
  – シグネチャで判断する
  – チェックサムもつけとけばよかった


 Ruby 1.8 と 1.9 両方で動く
 JRuby でも動く(が –X+O オプションが必要)
                                            11
アンダースコアだけで Ruby

require "_"
____ _ _____ ____ __ ____ ____
__ ___ ____ __ __ _ ______ _____
___ _ _ ___ _____ ______ ____ _
_ ____ _ _ ____ _ ____ __ __ ___
_ ______ ___ ____ __ ______ ____
_ ____ ____ __ _ ____ _ _ ___
_____ _____ _ ______ ____ _
______ _____

                                   12
アンダースコアだけで Ruby
実装
• プログラムの数値化(「数値だけ」と同じ)
• ゲーデル数を 6 進表記し、各桁をアンダースコアの
  数で表す
 – 123      _ __ ___
• _ や __ はメソッド呼び出しなので普通に拾える
             _ __         _(__)
 – ただし、               は             なので、評価順に注意
             ___          ___
     • Ruby は Call-by-value なので

      無引数 __ 、引数あり _ 、無引数 ___ の順に呼ばれる

     • 引数の有無を見て _ __ ___ の順に直す                 13
Hello world with underscore only
なぜ6進数か?
• 生成されるコード長を短くするため
 – コードを数値化した値: M
 – n進数で表現した時の桁数: log ������ ������
                                          ������+3
 – 各桁は 1~n 文字のアンダースコア+空白: 平均                2
                   ������+3
 – 生成される平均コード長:         log ������ ������
                     2
 – ������ = 5 で最小
• ただし計算間違いして ������ = 6 で公開してしまった
 – gem install _ で公開中




                                                 14
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
純粋にアルファベットだけで 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
純粋にアルファベットだけで 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
純粋にアルファベットだけで 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
「1.使用文字を制限して Ruby を書く」のまとめ
• Ruby は使用文字に結構強い

• 未解決問題
  – 小文字アルファベットだけ
  – 大文字だけ(不可能?)

  – 「記号だけ」は解決済み http://www.kurimura.com/rsencode/




                                                    19
2. Ruby で美しい Quine を書く


                         20
Quine とは
• 自分自身を出力するプログラム
    eval s="puts'eval s='+s.inspect"

• 実装の基本
  – 手順 1. 自分自身を文字列として再構成する
  – 手順 2. その文字列を出力する

• 手順 2 で整形をすると美しい Quine が書ける




                                       21
山手Quine




          • 実行すると隣の駅名になる
          • 29 駅で元に戻る
          • 起動速度重要
           • JRuby is 10x slower than MRI
             (3.3sec vs. 33sec)



                                            22
山手Quine
実装
1. 自分自身を再構成する
2. 次の駅の形に整形してから出力する
3. 以上をアスキーアートの形で行う
 – フォントデータ(圧縮)
 – 駅名(圧縮)
 – 圧縮の展開
 – Quine
 – 整形
 – ゴミ



                           23
山手Quine
アスキーアートでプログラムを書く
1. 空白とバックスラッシュなしでプログラムを書く
2. eval %w( と ).join で囲む eval %w(
       (                 pu
3. 自由に整形できる
                                         ts
                                              “H
• 注: %w() は文字列配列のリテラル
                                             i”
•   %w(foo bar)   =   [“foo”, “bar”]   ).join##

• 元の形を保持したい場合には、二重に eval する
        eval s=%q(eval %w( ... ).join)

                                                   24
山手Quine
圧縮
• データサイズとデコーダサイズのトレードオフ
      デコーダ小      データ小
      データ大      デコーダ大
• 最適な圧縮方法はデータの大きさや使用文字によっ
  て変わる
 • 経験的な方法
      データサイズ      方法
      ~ 10 バイト    無圧縮で文字列リテラル
      ~ 100 バイト   String#to_i(36)
      ~ 500 バイト   Base64
      もっと         Zlib + pack


                                         25
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
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
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
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
Qlobe
実装
• 世界地図のデータを持っている
 • データ  zlib 圧縮  巨大な整数化  コード文字列化
 • 後述
• 出力前に地図データをデコード・レンダリングする
• 地球の絵がコードに割り込んで来るのでかわす
 require“zlib”||    “地球部分"   ;d=d.unpack"C*"

 Inflate.inflate(    “地球部分"     &&e).unpack("b*"




                                                   30
Qlobe
Bignum のコード文字列化
• 表示可能な文字だけでエンコードする
• ただし、出現位置によって使えない文字がある
  – 文字列リテラルのデリミタとして使っている文字
    • 普通の言語では “ (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
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
tic-tac-toe (○×ゲーム)
 (たぶん)世界初、思考ルーチン組み込み対戦型 Quine




                            33
Quine Reversi
 思考ルーチン組み込み、勝たないと Quine してくれない




                            34
QR code: Q(uine) R(uby) code




                               35
QR code: Q(uine) R(uby) code(解説)
#!ruby
# Q(uine)R(uby)code (C) Y.Endoh 2009
eval 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
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
tkquine




          38
tkquine




          39
quine-web-server
eval$e=%q(puts'open http://localhost:18463';require'socket'
s=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
qng と qif と qvi
 自分自身を出力する画像・動画



      png




       gif



       qvi
                  41
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
Merry Quine-mas 2009
 クリスマスソング演奏機能組み込み Quine




                          43
Merry Quine-mas 2010
 クリスマスソング演奏機能組み込み Quine




                          44
Quine リレー
このプログラムは、このプログラム自身を出力する
Unlambda プログラム、を出力する Whitespace プログ
ラム、を出力する brainfuck プログラム、を出力する
Java プログラム、を出力する C プログラム、を出力す
る Haskell プログラム、を出力する OCaml プログラム、
を出力する Lua プログラム、を出力する Perl プログラ
ム、を出力する Python プログラム、を出力する Ruby
プログラム、です




                                 45
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
RubyKaigi 2010 スタッフロール




                         47
「2. Ruby で美しい Quine を書く」のまとめ
 • Ruby は文字配置制約+Quine に滅法強い
 • あやしい言語機能に感謝
    • %w, %q
    • BEGIN
    • eval
  – 文字列整形も強い
    • String#rjust, split, gsub!, slice!, rstrip
    • to_i / to_s / Integer#[]
    • unpack / pack / zlib




                                                   48
3. esolang で Quine を書く


                         49
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
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
Piet での Quine




                52
Piet での Quine (上部拡大)
                              出力


コードB: ビットマップを    GIF ヘッダを
 再エンコードして         出力する
   出力する
    コード B + C




コードC: ビットマップを
                コードA: 上の部分の
無圧縮GIFで出力する
                  ビットマップを
                 スタックに載せる

                もう一回コード A を
                   実行する
       コード A
                                   53
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
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
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
自己記述集合
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
������ =
  1431487833696853176700157431078133300807345625216694848607
028845592243617643316119085595555875582798798158387973177961
695587578188817228313270884309874099454731913241985765682402     57
自己記述集合
自己記述集合を x-y 平面にプロット




                      58
自己記述集合の解説
• Quine の考え方と同じ
 – 上半分(第一象限)はコード B+C
   • ビットマップデータ ������ (コード������)をプロットする
 – 下半分(第四象限)はコード A
   • コード B+C を表すビットマップデータ ������ を定義する




                                     59
自己記述集合
自己記述集合の解説(上半分)
• ビットマップデータ ������ を������軸より上にプロットする

• ������: 数式部分のビットマップデータを10進表記したもの
• ℐ ������, ������ = ������ ∈ ℤ ∶ ������ ≤ ������ < ������
    – 補助関数、 ������ から������の間の整数の集合
• ������ ������, ������, ������ = ������������������ ������������ −������ , ������
    – 補助関数、������ を ������ 進表記した時の下から ������ 番目の桁を取り出す
         ������, ������ + 1 : ������ ∈ ℐ 0, 240 ∧ ������ ∈ ℐ 0, 59 ∧
• ℬ=
                   ������ ������, 240������ + ������, 2 = 1
   – 0 ≤ ������ < 240 かつ 0 ≤ ������ < 59 の範囲で、
   – ������ ������, 240������ + ������, 2 = 1 を満たす ������ と ������ の値


                                                       60
自己記述集合
自己記述集合の解説(下半分)
• データ ������ をフォントデータ ℱ で������軸より下にプロットする
• ℱ: フォントデータを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
全体まとめ
• Quine・難解プログラミングは面白い
 – Ruby も esolang




                        63

More Related Content

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

  • 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. 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].reverse d,be="whydoes","crypto";:make. | %.mains..tr'eams',be.delete(d) • 参考: code golfer (14B) #!../s/grb -eh http://d.hatena.ne.jp/kurimura/20090929/1254257912 3
  • 4. Esoteric Programming Language (esolang) • 読み書きしにくいように作られた言語 – esoteric: 難解な、深遠な、秘伝的な、奥義に達した – ex) brainf**k, whitespace • 共通の特徴:奇妙な制約 +++++++++[>++++++++>++++++++++ +>+++++<<<]>.>++.+++++++..+++. – 使える文字・レイアウト >-.------------.<++++++++.---- ----.+++.------.--------.>+. – 使える命令 Hello world in brainf**k – 変な意味論 • Ruby も制限をすれば esolang になる – 使用文字の制限とか Hello world in whitespace 4
  • 5. 今日の内容 1. 使用文字を制限して Ruby を書く (中) 2. Ruby で美しい Quine を書く (易) 3. esolang で Quine を書く (難) 5
  • 8. 数字だけで Ruby 実装 • プログラムの数値化 • Ruby の黒魔術 • gem install 1234567890_ で公開中 8
  • 9. 数字だけで Ruby Gö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. 数字だけで 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. 数字だけで Ruby Ruby の黒魔術 • コードに書かれただけの数字を引っぱり出す – GC.disable – at_exit – ObjectSpace.each_object(Bignum) – eval • 無関係なBignumも拾えてしまう – シグネチャで判断する – チェックサムもつけとけばよかった  Ruby 1.8 と 1.9 両方で動く  JRuby でも動く(が –X+O オプションが必要) 11
  • 12. アンダースコアだけで Ruby require "_" ____ _ _____ ____ __ ____ ____ __ ___ ____ __ __ _ ______ _____ ___ _ _ ___ _____ ______ ____ _ _ ____ _ _ ____ _ ____ __ __ ___ _ ______ ___ ____ __ ______ ____ _ ____ ____ __ _ ____ _ _ ___ _____ _____ _ ______ ____ _ ______ _____ 12
  • 13. アンダースコアだけで Ruby 実装 • プログラムの数値化(「数値だけ」と同じ) • ゲーデル数を 6 進表記し、各桁をアンダースコアの 数で表す – 123  _ __ ___ • _ や __ はメソッド呼び出しなので普通に拾える _ __ _(__) – ただし、 は なので、評価順に注意 ___ ___ • Ruby は Call-by-value なので 無引数 __ 、引数あり _ 、無引数 ___ の順に呼ばれる • 引数の有無を見て _ __ ___ の順に直す 13
  • 14. Hello world with underscore only なぜ6進数か? • 生成されるコード長を短くするため – コードを数値化した値: M – n進数で表現した時の桁数: log ������ ������ ������+3 – 各桁は 1~n 文字のアンダースコア+空白: 平均 2 ������+3 – 生成される平均コード長: log ������ ������ 2 – ������ = 5 で最小 • ただし計算間違いして ������ = 6 で公開してしまった – gem install _ で公開中 14
  • 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. 純粋にアルファベットだけで 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. 純粋にアルファベットだけで 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. 純粋にアルファベットだけで 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. 「1.使用文字を制限して Ruby を書く」のまとめ • Ruby は使用文字に結構強い • 未解決問題 – 小文字アルファベットだけ – 大文字だけ(不可能?) – 「記号だけ」は解決済み http://www.kurimura.com/rsencode/ 19
  • 20. 2. Ruby で美しい Quine を書く 20
  • 21. Quine とは • 自分自身を出力するプログラム eval s="puts'eval s='+s.inspect" • 実装の基本 – 手順 1. 自分自身を文字列として再構成する – 手順 2. その文字列を出力する • 手順 2 で整形をすると美しい Quine が書ける 21
  • 22. 山手Quine • 実行すると隣の駅名になる • 29 駅で元に戻る • 起動速度重要 • JRuby is 10x slower than MRI (3.3sec vs. 33sec) 22
  • 23. 山手Quine 実装 1. 自分自身を再構成する 2. 次の駅の形に整形してから出力する 3. 以上をアスキーアートの形で行う – フォントデータ(圧縮) – 駅名(圧縮) – 圧縮の展開 – Quine – 整形 – ゴミ 23
  • 24. 山手Quine アスキーアートでプログラムを書く 1. 空白とバックスラッシュなしでプログラムを書く 2. eval %w( と ).join で囲む eval %w( ( pu 3. 自由に整形できる ts “H • 注: %w() は文字列配列のリテラル i” • %w(foo bar) = [“foo”, “bar”] ).join## • 元の形を保持したい場合には、二重に eval する eval s=%q(eval %w( ... ).join) 24
  • 25. 山手Quine 圧縮 • データサイズとデコーダサイズのトレードオフ デコーダ小 データ小 データ大 デコーダ大 • 最適な圧縮方法はデータの大きさや使用文字によっ て変わる • 経験的な方法 データサイズ 方法 ~ 10 バイト 無圧縮で文字列リテラル ~ 100 バイト String#to_i(36) ~ 500 バイト Base64 もっと Zlib + pack 25
  • 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. 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. 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. 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. Qlobe 実装 • 世界地図のデータを持っている • データ  zlib 圧縮  巨大な整数化  コード文字列化 • 後述 • 出力前に地図データをデコード・レンダリングする • 地球の絵がコードに割り込んで来るのでかわす require“zlib”|| “地球部分" ;d=d.unpack"C*" Inflate.inflate( “地球部分" &&e).unpack("b*" 30
  • 31. Qlobe Bignum のコード文字列化 • 表示可能な文字だけでエンコードする • ただし、出現位置によって使えない文字がある – 文字列リテラルのデリミタとして使っている文字 • 普通の言語では “ (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. 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
  • 35. QR code: Q(uine) R(uby) code 35
  • 36. QR code: Q(uine) R(uby) code(解説) #!ruby # Q(uine)R(uby)code (C) Y.Endoh 2009 eval 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. 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. tkquine 38
  • 39. tkquine 39
  • 40. quine-web-server eval$e=%q(puts'open http://localhost:18463';require'socket' s=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. qng と qif と qvi 自分自身を出力する画像・動画 png gif qvi 41
  • 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. Merry Quine-mas 2009 クリスマスソング演奏機能組み込み Quine 43
  • 44. Merry Quine-mas 2010 クリスマスソング演奏機能組み込み Quine 44
  • 45. Quine リレー このプログラムは、このプログラム自身を出力する Unlambda プログラム、を出力する Whitespace プログ ラム、を出力する brainfuck プログラム、を出力する Java プログラム、を出力する C プログラム、を出力す る Haskell プログラム、を出力する OCaml プログラム、 を出力する Lua プログラム、を出力する Perl プログラ ム、を出力する Python プログラム、を出力する Ruby プログラム、です 45
  • 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
  • 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. 3. esolang で Quine を書く 49
  • 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. 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
  • 53. Piet での Quine (上部拡大) 出力 コードB: ビットマップを GIF ヘッダを 再エンコードして 出力する 出力する コード B + C コードC: ビットマップを コードA: 上の部分の 無圧縮GIFで出力する ビットマップを スタックに載せる もう一回コード A を 実行する コード A 53
  • 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. 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. 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. 自己記述集合 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 ������ = 1431487833696853176700157431078133300807345625216694848607 028845592243617643316119085595555875582798798158387973177961 695587578188817228313270884309874099454731913241985765682402 57
  • 59. 自己記述集合の解説 • Quine の考え方と同じ – 上半分(第一象限)はコード B+C • ビットマップデータ ������ (コード������)をプロットする – 下半分(第四象限)はコード A • コード B+C を表すビットマップデータ ������ を定義する 59
  • 60. 自己記述集合 自己記述集合の解説(上半分) • ビットマップデータ ������ を������軸より上にプロットする • ������: 数式部分のビットマップデータを10進表記したもの • ℐ ������, ������ = ������ ∈ ℤ ∶ ������ ≤ ������ < ������ – 補助関数、 ������ から������の間の整数の集合 • ������ ������, ������, ������ = ������������������ ������������ −������ , ������ – 補助関数、������ を ������ 進表記した時の下から ������ 番目の桁を取り出す ������, ������ + 1 : ������ ∈ ℐ 0, 240 ∧ ������ ∈ ℐ 0, 59 ∧ • ℬ= ������ ������, 240������ + ������, 2 = 1 – 0 ≤ ������ < 240 かつ 0 ≤ ������ < 59 の範囲で、 – ������ ������, 240������ + ������, 2 = 1 を満たす ������ と ������ の値 60
  • 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