Best of show - abuse of libc

最優秀賞 - libcの悪用

受賞者:Nicholas Carlini

引用元:https://www.ioccc.org/2020/carlini/prog.c

審査員・作者による説明:https://www.ioccc.org/2020/carlini/index.html

動作

○×ゲーム。

$ gcc -o prog prog.c

$ ./prog

...(大量の空白やゴミ文字)...

 | |
-----
 | |
-----
 | |
P1>

左上から各マスに1~9まで番号が振られている。 3を指定する例。

P1>3

...(大量の空白やゴミ文字)...

 | |X
-----
 | |
-----
 | |
P2>

AIは搭載されていないので、同様に手入力していく。 不可能な手を打つか、勝敗が決定するか、全マスが埋まったら終了する。

O| |X
-----
 |O|X
-----
 | |X
P1 WINS

解説

main関数がprintf()の繰り返しだけになっている。 マクロでごまかしているなどではなく、実際にこのようになっている。

int main() {
    while(*d) printf(fmt, arg);
}

ポイントは、%nというマイナーなprintf()フォーマット指定子。 コード形状もそれを表現している。 これはポインタを引数に受け取り、printf()がここまでに書いた文字数をそのポインタに書き込む。 %hhnとすればchar型へのポインタとして扱ってくれるので、実質256の剰余も計算できる。 さらに%2$hnのような引数位置の指定もあわせることで、できることが増える。 hint.textには2進演算の考え方がわかりやすく書いてある。 もちろん、効率的に実行するにはそれ以上の工夫が必要となるとのこと。

なお、入力はscanf()で行っている。 最初は空文字列でscanf()することで何も読み込まず、2度目からはprintf()によってscanf()のフォーマット文を有効にすることで、位置の入力を受け取るようになる。