RubyでうどんげQuine(とAA型Quineの作り方講座)

山手Quineid:ku-ma-meさんに敬意を表しつつ.

Quineって何なの

Quineとは実行すると自身のソースコードを出力するプログラムのこと.

クワイン (プログラミング) - Wikipedia

うどんげQuine

ソースコードがうどんげのAAになっているQuineコードを作ってみた.Gistはこちら

udonge_quine.rb

 eval$s                                           =%w'                          
  b=   "                                       BAhsKwG                          
   vfg  A                                  AAAAA   PAAA                         
    AIw AA                             AAA     gD8AAAA4                         
     AQA AA                           Ph    4AAAAcAMAA                          
    ICDf wA                           A   AOAGAADA8D8                           
   AAAD  wB                           g AAQPwfAAAA                              
   eAY   AA                           E D/AwAAA                                 
  DgGA    AB                          A fwAAAAA                                 
  8DAAA    QH                       8   AAA AAf                                 
   BgAABB    3A                  AAA   A PhhAAC                                 
    OfgAAA     A               D     wgwCA4G 8A                                 
       AAAA    g   If4f/4fAAAAA  AD+PuC+AgAAA                                   
         ACA+wXA 7gAAA       AAA wD4AA O A                                      
       DAA AAAOAB A           gA AHg AAA                                        
      AB wGAEB                       CP0AA                                      
     AAAe        I                       wNs4                                   
    nvD    wA   A       A          H    T EtaWO7                                
   woAA   AB   q4 m7    9p  y+ 5A  w   AAPyL //zV9wx                            
  w AAF   8   W5s C /W Q7 h  A A B/f   oa4m1 w0F A c                            
 A 7 Jw  A   cN/ 0zO Fw A GjfAXCrkv  w HhwbA n  Q  EAX 5v5                      
PyhwAC   U   I  gP98kT/A/4BzAIDzX i b+  f zyA2e DB    s9  f/+                   
cf/QJ 8  Bw O    cc  /78      DDqBDPr7 Pw  gP 3  f3B    g    Z5u                
D3Wv6A/  C9sLl5  gO    K   9C/ z/A ZA  c  CAC D   A wA    A 4   B8=             
  "; n=M  ars  h            al. load( b.  u npac  k(  "m"    )[0    ]);         
   e =" eval$ s=%           w"< <3 9 < < (  $  s  *3);o="";     j=-    1 ;0     
      .up to(  35               *80-1 ) {| i|  o<  <((n[i]==1)     ? e      [j+ 
        = 1  ]     :           32);o<<((  i%80= =   7  9)?10:"        ")};o[-10,
       6]=  ""<                <39  <<". join "  ;p  u   ts(o)#b="BAhsK   wGvf  
       gA  AA AA     APAA     AAIw  AA AAAg D 8AAAA4AQAAA  Ph4AAAAc   AMAAICDfwA
      A AOAGA  AD             A8D8A  AAD  wBg   AAQPwfAAAAeAYA AED       /Aw    
     A AAD    g  GAABA   fwAAA AA8DA  AA Q    H8AA      AAA fBgAABB3AAA     AAP 
     hh AAC  Of gA AA  ADw     gw CA4 G8AA A AA  g If4f/4f          AAAAA AD+P u
    C+ Ag  AAA AC  A+wX        A 7   gAAA AAAw D4A A      OADAAAAAOABAgAA       
    H  g  AAA      A            Bw     GAE                           BC'.join   

実行するとソースコードそのものが出力結果として出てくる.もちろんdiffを取ると完全に一致する.

$ ruby udonge_quine.rb
 eval$s                                           =%w'                          
  b=   "                                       BAhsKwG                          
   vfg  A                                  AAAAA   PAAA                         
    AIw AA                             AAA     gD8AAAA4                         
     AQA AA                           Ph    4AAAAcAMAA                          
    ICDf wA                           A   AOAGAADA8D8                           
   AAAD  wB                           g AAQPwfAAAA                              
   eAY   AA                           E D/AwAAA                                 
  DgGA    AB                          A fwAAAAA                                 
  8DAAA    QH                       8   AAA AAf                                 
   BgAABB    3A                  AAA   A PhhAAC                                 
    OfgAAA     A               D     wgwCA4G 8A                                 
       AAAA    g   If4f/4fAAAAA  AD+PuC+AgAAA                                   
         ACA+wXA 7gAAA       AAA wD4AA O A                                      
       DAA AAAOAB A           gA AHg AAA                                        
      AB wGAEB                       CP0AA                                      
     AAAe        I                       wNs4                                   
    nvD    wA   A       A          H    T EtaWO7                                
   woAA   AB   q4 m7    9p  y+ 5A  w   AAPyL //zV9wx                            
  w AAF   8   W5s C /W Q7 h  A A B/f   oa4m1 w0F A c                            
 A 7 Jw  A   cN/ 0zO Fw A GjfAXCrkv  w HhwbA n  Q  EAX 5v5                      
PyhwAC   U   I  gP98kT/A/4BzAIDzX i b+  f zyA2e DB    s9  f/+                   
cf/QJ 8  Bw O    cc  /78      DDqBDPr7 Pw  gP 3  f3B    g    Z5u                
D3Wv6A/  C9sLl5  gO    K   9C/ z/A ZA  c  CAC D   A wA    A 4   B8=             
  "; n=M  ars  h            al. load( b.  u npac  k(  "m"    )[0    ]);         
   e =" eval$ s=%           w"< <3 9 < < (  $  s  *3);o="";     j=-    1 ;0     
      .up to(  35               *80-1 ) {| i|  o<  <((n[i]==1)     ? e      [j+ 
        = 1  ]     :           32);o<<((  i%80= =   7  9)?10:"        ")};o[-10,
       6]=  ""<                <39  <<". join "  ;p  u   ts(o)#b="BAhsK   wGvf  
       gA  AA AA     APAA     AAIw  AA AAAg D 8AAAA4AQAAA  Ph4AAAAc   AMAAICDfwA
      A AOAGA  AD             A8D8A  AAD  wBg   AAQPwfAAAAeAYA AED       /Aw    
     A AAD    g  GAABA   fwAAA AA8DA  AA Q    H8AA      AAA fBgAABB3AAA     AAP 
     hh AAC  Of gA AA  ADw     gw CA4 G8AA A AA  g If4f/4f          AAAAA AD+P u
    C+ Ag  AAA AC  A+wX        A 7   gAAA AAAw D4A A      OADAAAAAOABAgAA       
    H  g  AAA      A            Bw     GAE                           BC'.join   

何故作ったの

忘れた.

作成手順

↑のようなAA型Quineの作成手順について.

  • 基本
    • eval
    • %w記法
  • 準備
    • AAの準備
    • 01化
    • 数値化
    • バイト列化&Base64エンコード
  • Quineコードの記述
    • 情報部
    • デコード部
    • Quine部
    • 出力部
    • テスト実行
    • 完成

基本

まずQuineを書くための基本から.id:ku-ma-meさんのRuby会議2010での発表スライド(の後半)を読んでおくといいかも.

eval

evalを使うと以下のような感じでQuineのコードを書くことができる.

eval s="puts'eval s='+s.inspect"

出力結果

eval s="puts'eval s='+s.inspect"

sを$sにすればevalとsの間にスペースを入れなくても書ける.evalの引数を括弧でくくるよりも楽.

eval$s="puts'eval$s='+$s.inspect"
%w記法

%w記法を使うと文字列配列のリテラルを記述することができる.

p %w'foo bar' #=> ["foo", "bar"]

%w''の他に%w(),%w{},%w||,%w!!などでくくることもできる.

これとeval,Array#joinを組み合わせるとコードの好きな位置にスペースを入れることができるようになる.

eval %w'
pu
  ts
    "h
      i"
'.join##

この性質を用いるとQuineコードをAAの形で記述することができる.ただし,evalされるプログラムコード自体はスペースとバックスラッシュ記法は使えないという制約がある.

準備

AA型Quineコードを書くための準備について.

AAの準備

まずQuineコードの形となるAAを準備する.

%!PS
 /;{def                                           }def
  /?   {                                       moveto}
   ;/+  {                                  exec}   ;/={
    pop };                             /!{     lineto};
     /*{ }+                           {{    closepath}
    +{88 8}                           =   sethsbcolor
   fill  };                           { systemdict
   }/@   {}                           + {exch};
  /&{{    8}                          = repeat}
  ;/#{;    54                       ;   684 ;};
   +/Seed    /-                  {.8   ; 20};/|
    {{clip     }               +     newpath 11
       neg}    ;   /U/D/O/N/G/E  /_{{realtime
         }ifelse srand       9{U =}&}; - #
       504 ;{rand 2           31 exp div
      }; known                       {Seed
     }_/"        {                       mul}
    ;/-    {;   0       G          }    ; /'{add
   };/l   /u   /n /a    /t  /i /c  2   /_{2{ rlineto
  } };{   U   240 " 60 2. "  ' D div   ;{U}+ 360 " ;
 1 U .3  "   sub ;}& /: { closepath  | 6{?}+ 0  6  !}; /#{
rotate   E   E  scale};/u{u}+{.3( ) =}  + sub(8 )=    ;{  0.6
()=}+ -  O{ {    /y  {}=      }+{@}+{; }+  /z y  i{'    c    "}+
sin{-}+  D{dup{  n}    +   '{a "() =}  +  sin z   ' {2    ' 4   div
  }+ 360  "/x  {            };{ gsave }+  @ y/o{  &{  #}+    -10    5{?
   4 5} +{!}+ 10{           0}+ !} ; N 2 N  @  {  translate     }o{    4 -5
      !}+ -10  -5               !{:}+ 0 -6 !{  11  neg}+{-6}{}     = +      !{u
        1 l  *     0           6.}exec{?  11.0} +   6  lineto{        11.0%(c)omoikane
       6.0  neg                }{}  exec +{!} +  /o  {   t{1.0{l}+}exec   *};%     ++2008
       /d  {@ };     true     -6.(  0. )cvi @ lineto{o}+{  (90.)cvi   sin{1.0}+}
      { (ZUN)  {+             /quit  cvx  def   }forall}ifelse 8{8       div
     x dup    x  10.{"   -8.}+ '{dup  }+ x    6.{?      0}+ -12{{10}+}+     6.0
     {_ &}+  -6 {! }+  t{u     }+ sub (8)= " u{  ' 1}+{l}+          *}for -8.5 3.5{?
    }+ 3{  3.5 }+  {!}+        7 0   {!}+ -8.5 0.0 !      0{0}+{1}+{*}+()       grestore
    =  }  for      8            =}     for                           showpage

うどんげのAAはここから拝借させていただいた.このPSコード自体もなかなかすごい….

01化

AAの文字がある箇所を1,空白を0に置換する.気分で右側と上下を少し削った.35行80列.

01111110000000000000000000000000000000000000000000111100000000000000000000000000
00110001000000000000000000000000000000000000000111111100000000000000000000000000
00011100100000000000000000000000000000000001111100011110000000000000000000000000
00001110110000000000000000000000000000011100000111111110000000000000000000000000
00000111011000000000000000000000000000110000111111111100000000000000000000000000
00001111011000000000000000000000000000100011111111111000000000000000000000000000
00011110011000000000000000000000000000101111111111000000000000000000000000000000
00011100011000000000000000000000000000101111111000000000000000000000000000000000
00111100001100000000000000000000000000101111111000000000000000000000000000000000
00111110000110000000000000000000000010001110111000000000000000000000000000000000
00011111100001100000000000000000011100010111111000000000000000000000000000000000
00001111110000010000000000000001000001111111011000000000000000000000000000000000
00000001111000010001111111111110011111111111100000000000000000000000000000000000
00000000011111110111110000000111011111010100000000000000000000000000000000000000
00000001110111111010000000000011011101110000000000000000000000000000000000000000
00000011011111000000000000000000000001111100000000000000000000000000000000000000
00000111100000000100000000000000000000000111100000000000000000000000000000000000
00001110000110001000000010000000000100001011111100000000000000000000000000000000
00011110001100011011000011001101100100011111011111110000000000000000000000000000
00101110001000111010110110100101011100011111011101010000000000000000000000000000
01010110010001110111011010111111111001011111010010011101110000000000000000000000
11111100010001001111111111111111101011001011111011000011001110000000000000000000
11111010011010000110011100000011111111011001101001110000100001110000000000000000
11111110011111100110000100011101110110010011101000101100001010001110000000000000
00110111001110010000000000001110111110110010111100110011100001110000111000000000
00010110111110111000000000001110110101010100100100111111111000001110000101100000
00000011101110011000000000000000111110101101100110011111111111000001010000001110
00000000101001000001000000000001111111110011111010001001111111000000001111111111
00000001110011100000000000000001110011110111101001100100011111111111111000111100
00000001100110110000011110000011110011011110101111111111100111111110001111111111
00000010111110011000000000000011111001110011100011111111111111011100000001110000
00000101110000100111110001111101111100110100001111000000111011111111111000001110
00000110111001101101100111000001101110111101011001011111110000000000111110111101
00001101100111011001111000000001010001111011110111010000001111111111111110000000
00001001001110000001000000000000110000011100000000000000000000000000011111111000

これから作るQuineコードの制約として,Quineコードの最初に来る「eval」「$s」「=」が同じ行に入らなければならない.これらが違う行に配置されると,Rubyにおける改行は基本的にひとつの命令文の終わりを表すため動作が変わってしまう.また,%w'...'の外側にある「eval」「$s」「join」の単語内にスペースが入ってはならない(例:「ev al」はNG).そのため,最初に出現する1は4つ以上連続していなければならない等の制約がある.

数値化

01列をreverseし,整数に変換したものをAAの構造データとして保持する.

aa = <<EOM
01111110000000000000000000000000000000000000000000111100000000000000000000000000
00110001000000000000000000000000000000000000000111111100000000000000000000000000
00011100100000000000000000000000000000000001111100011110000000000000000000000000
00001110110000000000000000000000000000011100000111111110000000000000000000000000
00000111011000000000000000000000000000110000111111111100000000000000000000000000
00001111011000000000000000000000000000100011111111111000000000000000000000000000
00011110011000000000000000000000000000101111111111000000000000000000000000000000
00011100011000000000000000000000000000101111111000000000000000000000000000000000
00111100001100000000000000000000000000101111111000000000000000000000000000000000
00111110000110000000000000000000000010001110111000000000000000000000000000000000
00011111100001100000000000000000011100010111111000000000000000000000000000000000
00001111110000010000000000000001000001111111011000000000000000000000000000000000
00000001111000010001111111111110011111111111100000000000000000000000000000000000
00000000011111110111110000000111011111010100000000000000000000000000000000000000
00000001110111111010000000000011011101110000000000000000000000000000000000000000
00000011011111000000000000000000000001111100000000000000000000000000000000000000
00000111100000000100000000000000000000000111100000000000000000000000000000000000
00001110000110001000000010000000000100001011111100000000000000000000000000000000
00011110001100011011000011001101100100011111011111110000000000000000000000000000
00101110001000111010110110100101011100011111011101010000000000000000000000000000
01010110010001110111011010111111111001011111010010011101110000000000000000000000
11111100010001001111111111111111101011001011111011000011001110000000000000000000
11111010011010000110011100000011111111011001101001110000100001110000000000000000
11111110011111100110000100011101110110010011101000101100001010001110000000000000
00110111001110010000000000001110111110110010111100110011100001110000111000000000
00010110111110111000000000001110110101010100100100111111111000001110000101100000
00000011101110011000000000000000111110101101100110011111111111000001010000001110
00000000101001000001000000000001111111110011111010001001111111000000001111111111
00000001110011100000000000000001110011110111101001100100011111111111111000111100
00000001100110110000011110000011110011011110101111111111100111111110001111111111
00000010111110011000000000000011111001110011100011111111111111011100000001110000
00000101110000100111110001111101111100110100001111000000111011111111111000001110
00000110111001101101100111000001101110111101011001011111110000000000111110111101
00001101100111011001111000000001010001111011110111010000001111111111111110000000
00001001001110000001000000000000110000011100000000000000000000000000011111111000
EOM

bits = aa.gsub("\n", "").reverse.to_i(2)
puts bits #=> 95323084571042981455908562287732654335370207885205790277895949018625462321936757522192461693257062717604876976855397180359255109452532877564977320997120465254774177392269831302897587707623626891554977047012758104971419193700835257996211649473233162332672018667802021472945079636417501879623229522425383373079574422369358642114289293819489258109505142392827855610056680675474300811285836116178409870569217868574432144396781814176186356599245380442415281866079233074827820545027337597729551631589690793162455239271064873110679074676497800913092640338822906383269455715450991907019837374283153441839563847281905991649884648340182401619165618468732472312350351630916162494506579266127821216955407588295913410400504478808361619017250332456529580530111168182682032819244031801485123581597193462000039023598952626670368651689463125401098480326279294

このデータから以下のようなループを使えばAAの構造を復元することができる.

0.upto(35*80-1) do |i|
  print bits[i] == 1 ? 1 : " ";
  print "\n" if i % 80 == 79
end

出力結果

 111111                                           1111                          
  11   1                                       1111111                          
   111  1                                  11111   1111                         
    111 11                             111     11111111                         
     111 11                           11    1111111111                          
    1111 11                           1   11111111111                           
   1111  11                           1 1111111111                              
   111   11                           1 1111111                                 
  1111    11                          1 1111111                                 
  11111    11                       1   111 111                                 
   111111    11                  111   1 111111                                 
    111111     1               1     1111111 11                                 
       1111    1   111111111111  111111111111                                   
         1111111 11111       111 11111 1 1                                      
       111 111111 1           11 111 111                                        
      11 11111                       11111                                      
     1111        1                       1111                                   
    111    11   1       1          1    1 111111                                
   1111   11   11 11    11  11 11  1   11111 1111111                            
  1 111   1   111 1 11 11 1  1 1 111   11111 111 1 1                            
 1 1 11  1   111 111 11 1 111111111  1 11111 1  1  111 111                      
111111   1   1  11111111111111111 1 11  1 11111 11    11  111                   
11111 1  11 1    11  111      11111111 11  11 1  111    1    111                
1111111  111111  11    1   111 111 11  1  111 1   1 11    1 1   111             
  11 111  111  1            111 11111 11  1 1111  11  111    111    111         
   1 11 11111 111           111 11 1 1 1 1  1  1  111111111     111    1 11     
      111 111  11               11111 1 11 11  11  11111111111     1 1      111 
        1 1  1     1           111111111  11111 1   1  1111111        1111111111
       111  111                111  1111 1111 1  11  1   11111111111111   1111  
       11  11 11     1111     1111  11 1111 1 11111111111  11111111   1111111111
      1 11111  11             11111  111  111   11111111111111 111       111    
     1 111    1  11111   11111 11111  11 1    1111      111 11111111111     111 
     11 111  11 11 11  111     11 111 1111 1 11  1 1111111          11111 1111 1
    11 11  111 11  1111        1 1   1111 1111 111 1      111111111111111       
    1  1  111      1            11     111                           11111111   
バイト列化&Base64エンコード

AA型Quineコードを書くための前提として,「Quineのソースコードで使える最大文字数 == AA中の文字の数」という制約がある.

# AA構造データを整数文字列で表した時の長さ
puts bits.to_s.length #=> 911

# AA中の文字の数
puts aa.count('1')  #=> 842

今回はAAの構造データをそのまま整数でQuineコード中に入れようとすると長すぎてうまくいかない.そこで,構造データをMarshal.dumpでバイト列化(シリアライズ)し,Array#packでBase64エンコード(バイト列を印字可能な文字で表現)して整数を表すことにする.

bin = [Marshal.dump(bits)].pack("m").gsub("\n", "")
puts bin #=> BAhsKwGvfgAAAAAAPAAAAIwAAAAAgD8AAAA4AQAAAPh4AAAAcAMAAICDfwAAAOAGAADA8D8AAADwBgAAQPwfAAAAeAYAAED/AwAAADgGAABAfwAAAAA8DAAAQH8AAAAAfBgAABB3AAAAAPhhAACOfgAAAADwgwCA4G8AAAAAgIf4f/4fAAAAAAD+PuC+AgAAAACA+wXA7gAAAAAAwD4AAOADAAAAAOABAgAAHgAAAABwGAEBCP0AAAAAeIwNs4nvDwAAAHTEtaWO7woAAABq4m79py+5AwAAPyL//zV9wxwAAF8W5sC/WQ7hAAB/foa4m1w0FAcA7JwAcN/0zOFwAGjfAXCrkvwHhwbAnQEAX5v5PyhwACUIgP98kT/A/4BzAIDzXib+fzyA2eDBs9f/+cf/QJ8BwOcc/78DDqBDPr7PwgP3f3BgZ5uD3Wv6A/C9sLl5gOK9C/z/AZAcCACDAwAA4B8=
puts bin.length #=> 476

これでQuineコードで処理部に費やせる文字数が増える.

Marshal.dumpやArray#packについては以下を参照.

Quineコードの記述

準備が整ったのでQuineコードを書き始めよう.ここから先は命令文中でスペースとバックスラッシュ記法を一切使わずに書いていく.また,シングルクォート「'」は最後にコード全体を%w''でくくるために使うので,これもQuineコード中に書かないようにする.

情報部

AA構造データのBase64文字列を直書き.

b="BAhsKwGvfgAAAAAAPAAAAIwAAAAAgD8AAAA4AQAAAPh4AAAAcAMAAICDfwAAAOAGAADA8D8AAADwBgAAQPwfAAAAeAYAAED/AwAAADgGAABAfwAAAAA8DAAAQH8AAAAAfBgAABB3AAAAAPhhAACOfgAAAADwgwCA4G8AAAAAgIf4f/4fAAAAAAD+PuC+AgAAAACA+wXA7gAAAAAAwD4AAOADAAAAAOABAgAAHgAAAABwGAEBCP0AAAAAeIwNs4nvDwAAAHTEtaWO7woAAABq4m79py+5AwAAPyL//zV9wxwAAF8W5sC/WQ7hAAB/foa4m1w0FAcA7JwAcN/0zOFwAGjfAXCrkvwHhwbAnQEAX5v5PyhwACUIgP98kT/A/4BzAIDzXib+fzyA2eDBs9f/+cf/QJ8BwOcc/78DDqBDPr7PwgP3f3BgZ5uD3Wv6A/C9sLl5gOK9C/z/AZAcCACDAwAA4B8="
デコード部

Base64文字列をデコードしてバイナリ文字列を取得し,Marshal.loadでデシリアライズして実際の数値を得る.

n=Marshal.load(b.unpack("m")[0])
Quine部

出力用の文字列を作る.

e="eval$s=%w"<<39<<($s*3)

eにQuineプログラムの出力文字列を代入している.39はシングルクォート「'」のASCIIコード.「'」は後でQuineコード全体をくくるのに使うので,コード中で直接使うことはできない.グローバル変数$sはまだ用意していないが,これに「eval$s=%w'」と「'.join」を除くQuineコード全体が入っているものと見立ててプログラムを書いていく.$sのコードは何度か循環させておく.

出力部

出力文字列の整形を行い,出力する.

o=""
j=-1
0.upto(35*80-1){|i|
  o<<((n[i]==1)?e[j+=1]:32)
  o<<((i%80==79)?10:"")
}

o[-10,6]=""<<39<<".join"
puts(o)

ループで変数oに空白や出力文字をひとつずつ追加していく.10,32はそれぞれ改行,スペースのASCIIコード.出力文字列の最後が「'.join」になるように調節している.最後にoをputsで出力している.

テスト実行

ここまでのコードがちゃんと動くかどうか試してみる.

# $sにソースコードに見立てたダミーの文字列を入れておく
# 長さはQuineコード全体のバイト数程度にし,末尾に#を入れる
$s = "A" * 700 + "#"

# 情報部
b="BAhsKwGvfgAAAAAAPAAAAIwAAAAAgD8AAAA4AQAAAPh4AAAAcAMAAICDfwAAAOAGAADA8D8AAADwBgAAQPwfAAAAeAYAAED/AwAAADgGAABAfwAAAAA8DAAAQH8AAAAAfBgAABB3AAAAAPhhAACOfgAAAADwgwCA4G8AAAAAgIf4f/4fAAAAAAD+PuC+AgAAAACA+wXA7gAAAAAAwD4AAOADAAAAAOABAgAAHgAAAABwGAEBCP0AAAAAeIwNs4nvDwAAAHTEtaWO7woAAABq4m79py+5AwAAPyL//zV9wxwAAF8W5sC/WQ7hAAB/foa4m1w0FAcA7JwAcN/0zOFwAGjfAXCrkvwHhwbAnQEAX5v5PyhwACUIgP98kT/A/4BzAIDzXib+fzyA2eDBs9f/+cf/QJ8BwOcc/78DDqBDPr7PwgP3f3BgZ5uD3Wv6A/C9sLl5gOK9C/z/AZAcCACDAwAA4B8="

# デコード部
n=Marshal.load(b.unpack("m")[0])

# Quine部
e="eval$s=%w"<<39<<($s*3)

# 出力部
o=""
j=-1
0.upto(35*80-1){|i|
  o<<((n[i]==1)?e[j+=1]:32)
  o<<((i%80==79)?10:"")
}

o[-10,6]=""<<39<<".join"
puts(o)

出力結果.

 eval$s                                           =%w'                          
  AA   A                                       AAAAAAA                          
   AAA  A                                  AAAAA   AAAA                         
    AAA AA                             AAA     AAAAAAAA                         
     AAA AA                           AA    AAAAAAAAAA                          
    AAAA AA                           A   AAAAAAAAAAA                           
   AAAA  AA                           A AAAAAAAAAA                              
   AAA   AA                           A AAAAAAA                                 
  AAAA    AA                          A AAAAAAA                                 
  AAAAA    AA                       A   AAA AAA                                 
   AAAAAA    AA                  AAA   A AAAAAA                                 
    AAAAAA     A               A     AAAAAAA AA                                 
       AAAA    A   AAAAAAAAAAAA  AAAAAAAAAAAA                                   
         AAAAAAA AAAAA       AAA AAAAA A A                                      
       AAA AAAAAA A           AA AAA AAA                                        
      AA AAAAA                       AAAAA                                      
     AAAA        A                       AAAA                                   
    AAA    AA   A       A          A    A AAAAAA                                
   AAAA   AA   AA AA    AA  AA AA  A   AAAAA AAAAAAA                            
  A AAA   A   AAA A AA AA A  A A AAA   AAAAA AAA A A                            
 A A AA  A   AAA AAA AA A AAAAAAAAA  A AAAAA A  A  AAA AAA                      
AAAAAA   A   A  AAAAAAAAAAAAAAAAA A AA  A AAAAA AA    AA  AAA                   
AAAAA A  AA A    AA  AAA      AAAAAAAA AA  AA A  AAA    A    AAA                
AAAAAAA  AAAAAA  AA    A   AAA AAA AA  A  AAA A   A AA    A A   AAA             
  AA AAA  AAA  A            AAA AAAAA AA  A AAAA  AA  AAA    AAA    AAA         
   A AA AAAAA AAA           AAA AA A A A A  A  A  AAAAAAAAA     AAA    A AA     
      AAA AAA  AA               AAAAA A AA AA  AA  AAAAAAAAAAA     A A      AAA 
        A A  A     A           AAAAAAAAA  AAAAA A   A  AAAAAAA        AAAAAAAAAA
       AAA  AAA                AAA  AAAA AAAA A  AA  A   AAAAAAAAAAAAAA   AAAA  
       AA  AA AA     AAAA     AAAA  AA AAAA A AAAAAAAAAAA  AAAAA#AA   AAAAAAAAAA
      A AAAAA  AA             AAAAA  AAA  AAA   AAAAAAAAAAAAAA AAA       AAA    
     A AAA    A  AAAAA   AAAAA AAAAA  AA A    AAAA      AAA AAAAAAAAAAA     AAA 
     AA AAA  AA AA AA  AAA     AA AAA AAAA A AA  A AAAAAAA          AAAAA AAAA A
    AA AA  AAA AA  AAAA        A A   AAAA AAAA AAA A      AAAAAAAAAAAAAAA       
    A  A  AAA      A            AA     AAA                           AA'.join   

よさげ.AAの形がちゃんと出てくる.

そして完成へ

仕上げ.

  1. コードを1行に並べる.各命令をセミコロンで区切り,スペースは使わないようにする
  2. 最後の「puts(o)」の後にコメント用の「#」を追加する
  3. コード全体を「eval$s=%w'」と「'.join」でくくる
eval$s=%w'b="BAhsKwGvfgAAAAAAPAAAAIwAAAAAgD8AAAA4AQAAAPh4AAAAcAMAAICDfwAAAOAGAADA8D8AAADwBgAAQPwfAAAAeAYAAED/AwAAADgGAABAfwAAAAA8DAAAQH8AAAAAfBgAABB3AAAAAPhhAACOfgAAAADwgwCA4G8AAAAAgIf4f/4fAAAAAAD+PuC+AgAAAACA+wXA7gAAAAAAwD4AAOADAAAAAOABAgAAHgAAAABwGAEBCP0AAAAAeIwNs4nvDwAAAHTEtaWO7woAAABq4m79py+5AwAAPyL//zV9wxwAAF8W5sC/WQ7hAAB/foa4m1w0FAcA7JwAcN/0zOFwAGjfAXCrkvwHhwbAnQEAX5v5PyhwACUIgP98kT/A/4BzAIDzXib+fzyA2eDBs9f/+cf/QJ8BwOcc/78DDqBDPr7PwgP3f3BgZ5uD3Wv6A/C9sLl5gOK9C/z/AZAcCACDAwAA4B8=";n=Marshal.load(b.unpack("m")[0]);e="eval$s=%w"<<39<<($s*3);o="";j=-1;0.upto(35*80-1){|i|o<<((n[i]==1)?e[j+=1]:32);o<<((i%80==79)?10:"")};o[-10,6]=""<<39<<".join";puts(o)#'.join

↑を実行すればうどんげQuineコードの出来上がり.

 eval$s                                           =%w'                          
  b=   "                                       BAhsKwG                          
   vfg  A                                  AAAAA   PAAA                         
    AIw AA                             AAA     gD8AAAA4                         
     AQA AA                           Ph    4AAAAcAMAA                          
    ICDf wA                           A   AOAGAADA8D8                           
   AAAD  wB                           g AAQPwfAAAA                              
   eAY   AA                           E D/AwAAA                                 
  DgGA    AB                          A fwAAAAA                                 
  8DAAA    QH                       8   AAA AAf                                 
   BgAABB    3A                  AAA   A PhhAAC                                 
    OfgAAA     A               D     wgwCA4G 8A                                 
       AAAA    g   If4f/4fAAAAA  AD+PuC+AgAAA                                   
         ACA+wXA 7gAAA       AAA wD4AA O A                                      
       DAA AAAOAB A           gA AHg AAA                                        
      AB wGAEB                       CP0AA                                      
     AAAe        I                       wNs4                                   
    nvD    wA   A       A          H    T EtaWO7                                
   woAA   AB   q4 m7    9p  y+ 5A  w   AAPyL //zV9wx                            
  w AAF   8   W5s C /W Q7 h  A A B/f   oa4m1 w0F A c                            
 A 7 Jw  A   cN/ 0zO Fw A GjfAXCrkv  w HhwbA n  Q  EAX 5v5                      
PyhwAC   U   I  gP98kT/A/4BzAIDzX i b+  f zyA2e DB    s9  f/+                   
cf/QJ 8  Bw O    cc  /78      DDqBDPr7 Pw  gP 3  f3B    g    Z5u                
D3Wv6A/  C9sLl5  gO    K   9C/ z/A ZA  c  CAC D   A wA    A 4   B8=             
  "; n=M  ars  h            al. load( b.  u npac  k(  "m"    )[0    ]);         
   e =" eval$ s=%           w"< <3 9 < < (  $  s  *3);o="";     j=-    1 ;0     
      .up to(  35               *80-1 ) {| i|  o<  <((n[i]==1)     ? e      [j+ 
        = 1  ]     :           32);o<<((  i%80= =   7  9)?10:"        ")};o[-10,
       6]=  ""<                <39  <<". join "  ;p  u   ts(o)#b="BAhsK   wGvf  
       gA  AA AA     APAA     AAIw  AA AAAg D 8AAAA4AQAAA  Ph4AAAAc   AMAAICDfwA
      A AOAGA  AD             A8D8A  AAD  wBg   AAQPwfAAAAeAYA AED       /Aw    
     A AAD    g  GAABA   fwAAA AA8DA  AA Q    H8AA      AAA fBgAABB3AAA     AAP 
     hh AAC  Of gA AA  ADw     gw CA4 G8AA A AA  g If4f/4f          AAAAA AD+P u
    C+ Ag  AAA AC  A+wX        A 7   gAAA AAAw D4A A      OADAAAAAOABAgAA       
    H  g  AAA      A            Bw     GAE                           BC'.join   

かわいい.

以上

まっさらな状態からいきなりこのようなQuineコードを書くのは無理だけど,スクリプトを書いてじっくり構築していけば案外簡単に作れるのだなぁと思った(1時間くらいで作れた).

追記 2010/09/16 10:55

寝て起きたら404にうどんげのAAが載っててびびった.

モジュール自体がQuine…だと….