D言語くんのAAになっているD言語で書かれたquine

#D言語くんのAAになっているD言語で書かれたquine

1. D言語でただのquine書いて
1. D言語くんのAA書いて
1. フォーマッタ書いて
1. 合成しただけ

## 普通のquineを書く

まず,標準出力に自分自身が現れて欲しいので,

```d
const(char[])s="import std.stdio;void main(){writeln(s);}";mixin(s);
```

みたいなのを書く.出力↓

```
import std.stdio;void main(){writeln(s);}
```

惜しい.でもちょっと変えればquineになることにすぐに気づく.

改良後

```d
const(char[])s=q"{import std.stdio;void main(){writeln(`const(char[])s=q"{`~s~`}";mixin(s);`);}}";mixin(s);
```

`writeln(s)`のsに`const(char[])s=q"`っていう文字列と`}";mixin(s);`っていう文字列をくっつけた.
この文字列中にはダブルクオート(")が入っているのでネストできるq"{}"という生文字列リテラルを使う.
これでquineが出来た.

## D言語くんのAA

描くだけ.結構文字数が必要だとわかっているので大きめにする.

```
                                 ###                            
                      ######    #######                         
                  ############ #########                        
                 ########################                       
                #########################                       
                #########################                       
                ###########################                     
              ########################### ##                    
             ##  #######################   ##                   
            ##    ###########  ########     ##                  
           ##      ########                  ##                 
          ##                                  ##                
         ##                                    ##               
        ##                                      ##              
       ##                                        ##             
      ##                                          ##            
     ##                                            ##           
    ##                   #########                  ##          
   ##         ###########         ########           ##         
  ##      ####                            ###         ##        
 ##   ####   #     ########       #####      ##        ##       
  ## #       #    #        #     #     #       #      ##        
   ###        #  #      #####   #    #####      #    ##         
     ###      #  #     ##########   #######      #  ##          
      ###     #  #    ########  #   #######       ###           
      # ##     # #    ###########  ########       ##            
       # ##    #  #   #######   #  #########       #            
       #  ##   #   #########     # ####### #       #            
       #       #         #        #######   #       #           
       #        #        #               #  #       #           
        #       #        #               #  #       #           
        #       #        #               #  #        #          
        #       #        #               #  #        #          
        #       #        #               #  #        #          
        #      #        #                # #         #          
       #       #        #               #  #         #          
       #       #        #               # #          #          
       #       #        #              ## #         #           
       #       #       #            ###  #          #           
       #      #        #         ###   ##          #            
      #       #       #         #######           #             
      #       #       ##########                 #              
      #       #                                ##               
     #       #                             #####                
     #       #                         ####   #                 
     #     ##                ##########      #                  
     #  #####################              ##                   
     ###                          ##   ####                     
    #               ##           ######                         
   ###             ##   #########   ##                          
      ##################             ##                         
                 ##                   ##                        
                ##                     ##                       
               ##                       ##                      
              ##                         ##                     
               ##                       ##                      
                ##                     ##                       
                 ##                   ##                        
                  ##                 ##       #####             
         #####     ##                ##  ###########            
        #########  ##                ################           
        #############               ###############             
         ############                ############               
           #########                  #####                     
```

## フォーマッタを書く

文字列を受け取ってこの形に出力するコードを書く.この画像をそのままデータとして持つと,quineは(コード+データ)の形にしなければならないのにデータだけですでにquineコードの容量をオーバーしてしまうので,なんとか圧縮する方法を考える.

このAAは56x64なので,スペースを0,#を1としてint[]rの配列変数に格納する.
文字列変数の名前をsとするとフォーマッタは

```d
int c=0;
foreach(i,n;r)n?write(s[c++]):write(" "),(i+1)%56||writeln("");
```

と書ける.
実際にrに[0,…,0,1,…,1]や,[0,1,0,1,…]などと入れて確かめるとうまくいくことがわかる.
さて,肝心の圧縮だが,Dの標準ライブラリにzlibがあるので,これを使えばうまく圧縮できるのではないだろうか.
圧縮されているデータをuncompressしたものがint[]rとなれば良いので,とりあえず`writeln(compress(r,9).length)`とする.
324バイトの配列になったので大幅に圧縮できたが,中身はただのバイト列なので,印字可能文字にするためbase64エンコードをする.
`writeln(Base64.encode(compress(r,9)).length)`とすると432文字とある.
上のAAの#の文字数は843文字なので半分以上base64に持って行かれることになるが,まあ残り400文字あればquineできるだろう.

ちなみに,Base64エンコードした文字列は以下になる.
`eNq9l9sSgyAMRLP//9Od1nLZ3HFqfVAGcwiGDUSR/AIg7Qufa7XQZr7mq3WC0RD3sL9zKZlRCfh+FTsLQVqxy5jmGICjO/4eF+yIwrHpydBYddWr7PqiJ8uzXLmFbdZBeKvlIMfW3OFJPpXoeazBXg/PwdZe5AVOk3lbjf0+n8PZZgr2Au1SKVlxKoEY3KcL4rZEMnshxWeuiRQ5qIU2klZ7gFUAczLDwHZz75WAU31QenGN9KKpUXmJcocPcN5E/8yFmMCL9Zm7M85btZKDP03DwewQrrskLPYMa7lzNrNELcnhDEnToXWs9DDrv+ZUBvJOibi8iEVUVyzuuEUo6tDaIzU6cOCd2a2CR4pPu1midMCiljrEKrCoFX/u7/b3PVQruqqNy1pVPwdlVZZPTukUV/xFdsWbUf4XUb3irhfw7ANM`

## これらを合成する

最初のquineの

```d
const(char[])s=q"{import std.stdio;void main(){writeln(`const(char[])s=q"{`~s~`}";mixin(s);`);}}";mixin(s);
```

writelnの部分をフォーマッタに変更すれば,いい感じになる.
ここで注意するのが,実際にmixinに渡される文字列はAAの形をしているので,適当にスペース,改行を取り除き,`int c`など,スペースが必要な場所は`@`を` `に置換することで対応する.
translateという関数が有ったのでこれを使い,sの中身もAAの形の一部なので,

```d
char[]t=removechars(`///import@std.///string;const(char[])s=q"{`~s~`}";;;;mixin(translate(s,makeTrans([64],[32]),[32,10]));////`,[32,10]);`
```

としてスペース,改行を取り除いた後,char[]tに代入し,実際にフォーマッタに渡される文字列はこれを使うようにする.
また,生文字列以外の部分,例えば,最初の`import std.string;`や最後の`mixin()`は識別子が分断されると構文エラーになってしまうので,ちょこちょこ適当な文字を入れてうまく識別子がそのままになるよう工夫する.


```d
import std.string;const(char[])s=q"{
import@std.zlib,std.base64,std.stdio,std.string;
void@main(){
    byte[]u=cast(byte[])Base64.decode("eNq9l9sSgyAMRLP//9Od1nLZ3HFqfVAGcwiGDUSR/AIg7Qufa7XQZr7mq3WC0RD3sL9zKZlRCfh+FTsLQVqxy5jmGICjO/4eF+yIwrHpydBYddWr7PqiJ8uzXLmFbdZBeKvlIMfW3OFJPpXoeazBXg/PwdZe5AVOk3lbjf0+n8PZZgr2Au1SKVlxKoEY3KcL4rZEMnshxWeuiRQ5qIU2klZ7gFUAczLDwHZz75WAU31QenGN9KKpUXmJcocPcN5E/8yFmMCL9Zm7M85btZKDP03DwewQrrskLPYMa7lzNrNELcnhDEnToXWs9DDrv+ZUBvJOibi8iEVUVyzuuEUo6tDaIzU6cOCd2a2CR4pPu1midMCiljrEKrCoFX/u7/b3PVQruqqNy1pVPwdlVZZPTukUV/xFdsWbUf4XUb3irhfw7ANM").uncompress,r;
    char[]t=removechars(`///import@std.///string;const(char[])s=q"{`~s~`}";;;;mixin(translate(s,makeTrans([64],[32]),[32,10]));////`,[32,10]);
    int@c;
    foreach(i,n;u)write(n?t[c++]:'@'),(i+1)%56||"".writeln;
}
}";
mixin(translate(s,makeTrans([64],[32]),[32,10]));
```

これを実行すると

```d
                                ///                     
                     import    std.///                  
                 string;const (char[])s                 
                =q"{import@std.zlib,std.                
               base64,std.stdio,std.stri                
               ng;void@main(){byte[]u=ca                
               st(byte[])Base64.decode("eN              
             q9l9sSgyAMRLP//9Od1nLZ3HFqf VA             
            Gc  wiGDUSR/AIg7Qufa7XQZr7m   q3            
           WC    0RD3sL9zKZl  RCfh+FTs     LQ           
          Vq      xy5jmGIC                  jO          
         /4                                  eF         
        +y                                    Iw        
       rH                                      py       
      dB                                        Yd      
     dW                                          r7     
    Pq                                            iJ    
   8u                   zXLmFbdZB                  eK   
  vl         IMfW3OFJPpX         oeazBXg/           Pw  
 dZ      e5AV                            Ok3         lb 
jf   0+n8   P     ZZgr2Au1       SKVlx      Ko        EY
 3K c       L    4        r     Z     E       M      ns 
  hxW        e  u      iRQ5q   I    U2klZ      7    gF  
    UAc      z  L     DwHZz75WAU   31QenGN      9  KK   
     pUX     m  J    cocPcN5E  /   8yFmMCL       9Zm    
     7 M8     5 b    tZKDP03Dwew  QrrskLPY       Ma     
      7 lz    N  r   NELcnhD   E  nToXWs9DD       r     
      v  +Z   U   BvJOibi8i     E VUVyzuu E       U     
      o       6         t        DaIzU6c   O       C    
      d        2        a               2  C       R    
       4       p        P               u  1       m    
       i       d        M               C  i        l   
       j       r        E               K  r        C   
       o       F        X               /  u        7   
       /      b        3                P V         Q   
      r       u        q               q  N         y   
      1       p        V               P w          d   
      l       V        Z              ZP T         u    
      k       U       V            /xF  d          s    
      W      b        U         f4X   Ub          3     
     i       r       h         fw7ANM"           )      
     .       u       ncompress,                 r       
     ;       c                                ha        
    r       [                             ]t=re         
    m       o                         vech   a          
    r     s(                `///import      @           
    s  td.///string;const(ch              ar            
    [])                          s=   q"{`              
   ~               s~           `}";;;                  
  ;mi             xi   n(transla   te                   
     (s,makeTrans([64],             [3                  
                2]                   ),                 
               [3                     2,                
              10                       ])               
             );                         //              
              //                       `,               
               [3                     2,                
                10                   ])                 
                 ;i                 nt       @c;fo      
        reach     (i                ,n  ;u)write(n?     
       t[c++]:'@  ')                ,(i+1)%56||"".wr    
       iteln;}}";;;;               mixin(translate      
        (s,makeTrans                ([64],[32]),        
          [32,10]))                  ;////              
```

となり,確かにD言語くんのAAのquineとなっている.

これを作るにあたり,[あなたの知らない超絶技巧プログラミングの世界](https://gihyo.jp/book/2015/978-4-7741-7643-7)を参考にしました.皆さん買いましょう.