Most shifty

もっともずる賢い

受賞者:Don Yang

引用元:https://www.ioccc.org/2018/yang/prog.c

審査員・作者による説明:https://www.ioccc.org/2018/yang/hint.html

動作

テキストを左回転するツール。

次の例で示す。

$ cat tmp.txt
AAAAA
 BBBB
  CCC
   DD
    E

実行のたびに左回転していく。

$ gcc -o left prog.c

$ ./left < tmp.txt
ABCDE
ABCD
ABC
AB
A

$ ./left < tmp.txt | ./left
E
DD
CCC
BBBB
AAAAA

$ ./left < tmp.txt | ./left | ./left
    A
   BA
  CBA
 DCBA
EDCBA

$ ./left < tmp.txt | ./left | ./left | ./left
AAAAA
 BBBB
  CCC
   DD
    E

もとのソースコードを左回転させる。

$ cat prog.c | ./left
#include<stdio.h>//%i//;/*]u;i""""""""e##
#include<stdlib.h>//nuii~~,[pnofbmo2>exdi
int*n,u,k,o,X,x,//|*t)NUKO?qutvtxfh*/ften
p,d,q=1;char*O;int// )1(=q/*t ju!tt<1=efc
main(){O=NULL;if(0!=q////n[1sN"/jt!s,tril
-q){puts("Yuuri");//=///////,(}"t/bfvunnu
}else{while(EOF/////     /////;,!"su,e ed
!=(o=getchar())///          ////c,fv)ji e
){if(!x){if(d+//              //""!sopnN<
2>p&&!(n=(int//                //Sxo./t(s
*)realloc(n,///                 /"p!:i Ut
sizeof(int)///                  //s14?q,d
*(p=p?p*2:2//                    /u<@\;Ki
*1024)))){//                     /i~o1c,o
return-1;}//                      "".3hO.
n[d++]=k;//                       /,:ja)h
}x=0;if(//                        /"2or >
o-10){if//                        //@u*m/
(k>=u&&1//                         /v!na/
&&!(O=(//                          /=o,i}
char*)///                          "1-un;
realloc//                           @v[(0
(O,u=u//                            q<6)+
?u*2:8//                       /   "vj]{n
*8))){//                      /////!uo[fr
return//                      /////Idu1ou
-1;}O[//                      //.[[vi!4rt
k++]=o//                      //[#[nbn0(e
;x=k-n//                      //pu~bsb]nr
[d-1];//                      //#^)o\j==}
if(x>X//                      //akptxo{K;
)X=x;}//                     //[]oh!2)";)
}n[d]=//                     //_)uub9*H*"
k;for(//                     //]:n]s)|jno
o=0;o<X//                    //|/aTf6xs;k
;o+=1,///                    /vUU#f!_im-u
putchar//                   //vSOhFt)jt-N
(0xa)){//                   //\TK`:dom(*"
for(u=d//                   //OAO#jb,f!n/
;u-->0;)//                 //[JMYiQs3)M+*
putchar(//                 //=UURb[z*)b+]
o>=n[u+1//                 //=OU\du/\ot)a
]-n[u]?///                 //=HH^#h"5>u;9
32:O[o+n//                 //=SS^^f,2h!U8
[u]]);}}///                //]/\,]h"&fU(1
return+0;//                ///////]J2upKc
}//nu[u[,//                 ///////o3dv)f
#if 0//h[//                       /f4is;f
*//*[/[ah//                       /e*b"rc
//]]g4i#o//                       /j+s,e[
0xX/n6ul#//                      //c1)"t]
7;[/h=ndu//                    ///!m;*$u8
;x/(k]ob]//                  ////C^f1*jr1
/ /fT+#e//                  ///[vC^!;?on0
/tri]+^#//                  //[i[C^u21d+2
>na{/up]//                  //8hjO^i;*m0)
hih)/[#//                   //zp#I^j.vv;c
. c()]_//                   //b#u>[""""}(
of n+n]//                   //_J^-o/////[
ieci+[//                    //]~]>]/////.
ddiand//     @@@            //]]u*/tni};0
tetm;)//    @   @          //ften enifed#
spa n;//    @   @          //*IUN//nruter
<ytx>5//    @   @          ////};)"otihC"
/ts;42//     @@@           //(stup-01-l=I
*;;]20//            2     ///s//{esle}}};
i01101//           51     //tt//01-I=l;)
un=01<0//                //u/u//I(rahctup
n i4;u==//               //*/p.NU//{)23-I
*t,x0;no)//             //n/{;//||l(fi{))
/n_0=0=();//           //N*)e+//)(rahcteg
ei,[nxu=(40///        //NU/]s+//=I(=!FOE(
d o](0(!r214////    ////**skl]//elihw{)q(
un,5r=rFa0-2+o////////un//t[e0//fi{)(niam
lrk2ouoOh1o0+=<k////-k[*!,ud}[NU//tni;l,I
ce,1f(fEc<=1n]k:0n;(-[]/=1p(;]//tni;q tni
ntu1{r;;tu+<[u=n:()rkd1]/////0& t enifed#
ix,[)o24e&und[k?0!0o;)01*****[iun//nretxe
#endif//g&)??],n,:=f ;//>h.oidts<edulcni#

この出力は、テキストを右回転するソースコードになっている。

$ cat prog.c | ./left > right.c

$ gcc -o right right.c

$ ./right < tmp.txt
    A
   BA
  CBA
 DCBA
EDCBA

元のコードを2回左回転させると、メッセージが出てくる。

$ cat prog.c | ./left | ./left > msg0.c

$ gcc -o msg0 msg0.c

$ ./msg0
Girls' Last Tour

元のコードを3回左回転(=1回右回転)させると、行頭のスペースを消す(シフトする)コマンドになる。

$ cat prog.c | ./right > shift.c

$ gcc -o shift shift.c

$ ./shift < tmp.txt
AAAAA
BBBB
CCC
DD
E

元のコードには周囲に欠けている部分が2箇所ある。 これはシフトによってずらすことができる。 ずらすだけでは動作は変わらないが、ずらしてから左右に回転させることでメッセージが出るようになる。

$ cat prog.c | ./shift | ./left > msg1.c

$ gcc -o msg1 msg1.c

$ ./msg1
Yuuri

$ cat prog.c | ./shift | ./right > msg2.c

$ gcc -o msg2 msg2.c

$ ./msg2
Chito

欠けている箇所は2箇所あるので、回転とシフトを賢く繰り返すことで、合計10個のメッセージが出てくるようになっている。 続きは解説の最後に。

解説

コード形状は少女終末旅行に出てくるキャラクター、ヌコ。 メッセージも少女終末旅行にちなんだものになっている。 “Girls’ Last Tour”は「少女終末旅行」の英語、”Yuuri”と”Chito”は登場人物のユーリとチト。

おおよそ、4つの角に4つのコードが配置されている。 それぞれのコードの左上のコードが有効になり、右上は一行コメントで無効化、左下と右下は/* */または#if 0 ... #endifで無効化する、というのが基本的なテクニック(ただし一部のコード断片はその原則を外れていている)。 欠けた部分をシフトされている判定はさらに巧妙で、コメントで無効化される縁のあたりでコードが1文字だけ割り込んだり消えたりすることで実現している模様。

同作者のコード遊びが遺憾なく発揮されており、[[2011/akari]]以来の大作と言える。 同作者の常として、CRC32の埋め込み(最下行)とspoiler.htmlの添付がなされている。

賞名の”shifty”は「ずる賢い」という意味だが、シフト処理にかけている。


回転とシフトを組み合わせてメッセージを探すのは、木製のパズルの箱(秘密箱?)を意識しているとのこと。

すべてのメッセージを洗い出すには、ヌコを逆さまにした状態で、口の位置にある125の3つの数字から2つを並べる組み合わせの6通りを列挙すればよい。 以下、Makefileに書いてある手順ですべてのメッセージを出す。

$ cat prog.c | ./right | ./shift | ./left > msg3.c

$ gcc -o msg3 msg3.c

$ ./msg3
Nuko

ヌコはprog.cに書かれているキャラクターの名前。 prog.cとmsg3.cの切り替えが実に巧妙。

$ cat prog.c | ./shift | ./right | ./shift | ./right > msg4.c

$ gcc -o msg4 msg4.c

$ ./msg4
... Humans are scary.

ヌコのセリフ「人間は怖い」

$ cat msg4.c | ./shift | ./right | ./shift | ./left > msg5.c

$ gcc -o msg5 msg5.c

$ ./msg5
Inedible things are worthless.

ヌコのセリフ「食えないものに価値はねえ」

$ cat msg5.c | ./right | ./right | ./shift | ./right | ./shift | ./right > msg6.c

$ gcc -o msg6 msg6.c

$ ./msg6
nui

ヌコの鳴き声「ぬい」

$ cat msg6.c | ./shift | ./right | ./shift | ./left > msg7.c

$ gcc -o msg7 msg7.c

$ ./msg7
#include<stdio.h>
int n,u;int main(){while((n=getchar())>0)u=.0+u+(n-93?n-91?u<0?putchar((5^(n+2))%123)*0:0:1:-1);return 0;}

最後のメッセージを出すためのプログラム。

$ cat msg7.c | ./right | ./right | ./shift | ./right | ./shift | ./right > msg8.c

$ gcc -o msg8 msg8.c

$ ./msg8
Raw is best.

これはちょっとわからなかった。 「生きるのは最高だったよね」の誤訳?

$ ./msg7 > msg9.c

$ gcc -o msg9 msg9.c

$ ./msg9 < prog.c
Should we turn back for today?
I wonder if we can go further tomorrow.

オープニングテーマ『動く、動く』の歌詞の冒頭、「今日はもう引き返そうかな 明日はもっと行けるかな」。