Skip to content

Commit

Permalink
Publish spoilers for IOCCC 1989
Browse files Browse the repository at this point in the history
  • Loading branch information
mame committed Jan 23, 2021
1 parent 1845e32 commit 1960861
Show file tree
Hide file tree
Showing 52 changed files with 1,543 additions and 3 deletions.
80 changes: 80 additions & 0 deletions 1989/fubar.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
id: 1989/fubar
year: 1989
order: 1
patch: true
authors: "Jay_Vosburgh"
orig_url: "https://www.ioccc.org/1989/fubar.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1989/fubar.hint"
title: "IOCCC 1989: Best self-modifying program"
award_ja: "最高の自己書き換えプログラム"
---

## 動作

階乗の計算。

動かし方にクセがある。

```
$ cp fubar.c ouroboros.c
$ chmod +x ouroboros.c
$ ./ouroboros.c 10
...
10 factorial = 3628800
```

## 解説

このコードはC言語とシェルスクリプトのかんたんなpolyglotになっている。
シェルスクリプトがやっている処理をわかりやすく書き下すと、次のような処理となる。

```
$ cp fubar.c ouroboros.c
$ cc -o x ouroboros.c && cat ouroboros.c | ./x 5 > x1 && mv x1 ouroboros.c
$ cc -o x ouroboros.c && cat ouroboros.c | ./x 5 > x1 && mv x1 ouroboros.c
$ cc -o x ouroboros.c && cat ouroboros.c | ./x 5 > x1 && mv x1 ouroboros.c
$ cc -o x ouroboros.c && cat ouroboros.c | ./x 5 > x1 && mv x1 ouroboros.c
$ cc -o x ouroboros.c && cat ouroboros.c | ./x 5 > x1 && mv x1 ouroboros.c
$ cc -o x ouroboros.c && cat ouroboros.c | ./x 5 > x1 && mv x1 ouroboros.c
5 factorial = 120
```

つまり、自分をコンパイルし、自分を読み込んであらたなコードを作る、ということを繰り返す。

初期コードのouroboros.cの先頭には、

```
#define QQ 1
#define TT 1
```

と書かれている。
これをビルドし、ouroboros.cを標準入力に流し込みながら`./x 5`と実行すると、ほとんど同じコードが出力されるが、上の箇所が下のように変わっている。

```
#define QQ 2
#define TT 2
```

これをouroboros.cとして上書き保存し、同じ処理を行うと、次のようになっている。

```
#define QQ 3
#define TT 6
```

`QQ`が繰り返し回数、`TT`がここまでの階乗の値であることがわかる。
これを繰り返して、'QQ'がコマンドライン引数の数字に到達すると、標準エラー出力に`5 factorial = 120`と出力して停止する。

実行可能なプログラムを繰り返し出力する初の作品。
元ソースコードを標準入力に与えているので厳密な意味でのQuineではないが、コードをもてあそぶ体験の原型がある。
polyglot自体は[[[1985/applin]]]({{ site.baseurl }}{% link 1985/applin.md %})で既出だが、繰り返しの処理を自動化するシェルスクリプトをpolyglotとして盛り込んでいるところはポイント高い。
さらに、`cc ouroboros.c -o x`の文字列がC言語プログラムとして解釈されているところも(単なるマクロ置換ではあるが)面白い。

現代の環境で動かすために、2点の変更を行っている。

* メーラの都合で折り返されていた行をあらかじめ結合した(`ex`コマンドのスクリプトが付属していたがうまく動かなかった)。
* `PATH`にカレントディレクトリが含まれている前提だったので、`./x`とした。
19 changes: 19 additions & 0 deletions 1989/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
year: 1989
title: "IOCCC 1989の解説"
layout: contest
---
## 全体の印象

単純なプログラムをむやみやたらに難読化するという時代は終わり、プログラムの挙動のおもしろさや難読化方法の創意工夫で競い合う傾向が急激に強まった。

言語処理系をテーマとする作品や、テトリスのように挙動の複雑さで勝負する作品が増えた。
個人的には、プログラム自体を処理対象として扱い、新たなプログラムを出力する「コード遊び」の作品が増えたのが嬉しい。
[[[1989/fubar]]]({{ site.baseurl }}{% link 1989/fubar.md %})はプログラムを実行するとプログラムが現れ、繰り返しコンパイルが体験できる作品。
なかでも[[[1989/westley]]]({{ site.baseurl }}{% link 1989/westley.md %})は、あまり有名でないが恐ろしいレベルの超絶技巧。

この大会から全作品のhintファイルに作者のコメントが掲載されるようになった。

なお、この年はC言語の最初の標準規格が作られた年である(C89、通称ANSI C)。
ただし、規格は年末に確定し、出版は翌年であるため、IOCCC 1989ではまだC89は登場しない。
これらのプログラムがC規格策定前から存在したと思うと、ある意味感慨深い。
36 changes: 36 additions & 0 deletions 1989/jar.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
id: 1989/jar.1
year: 1989
order: 2
authors: "Jari_Arkko"
orig_url: "https://www.ioccc.org/1989/jar.1.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1989/jar.1.hint"
title: "IOCCC 1989: Strangest abuse of the rules"
award_ja: "もっとも奇妙なルール悪用"
---

## 動作

コンパイルしたオブジェクトファイルの中にHello worldが見えるというもの。

```
$ gcc -c -o jar.1.o jar.1.c
$ cat jar.1.o
ELF......
Hello world.
GCC: (Ubuntu 9.3.0-10ubuntu2) 9.3.GNU.......
```

## 解説

作者の意図としては、`cc -c -o /dev/tty jar.1.c`とコンパイルすることで、コンパイル結果を直接TTYに書き出させることだったらしい。
しかし現代ではこれは動かなくなっていたので残念。

作者のもともとのソースコード([jar.1.orig.c](https://www.ioccc.org/1989/jar.1.orig.c))は`char*He="llo world.\n";`となっていた。
おそらく、当時のオブジェクトファイルのヘッダ部分やシンボル情報などに`He`が含まれていて、それとつながって表示されていたのではないかと思う。
考古学もとむ。

翌年からルールに「実行可能な通常のファイルになること」が追加された。

同じ年に同じ人が複数入賞した初の事例。
ただしもう1つの[[[1989/jar.2]]]({{ site.baseurl }}{% link 1989/jar.2.md %})は3人の共作で、この作品と同じ人が筆頭作者となっている。
65 changes: 65 additions & 0 deletions 1989/jar.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
id: 1989/jar.2
year: 1989
order: 10
patch: true
authors:
- "Jari_Arkko"
- "Ora_Lassila"
- "Esko_Nuutila"
orig_url: "https://www.ioccc.org/1989/jar.2.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1989/jar.2.hint"
title: "IOCCC 1989: Best of show"
award_ja: "最優秀賞"
---

## 動作

Lispインタプリタ。

```
$ gcc -o jar.2 jar.2.c
$ echo "(+ 1 1") | ./jar.2
$ cat fib.lisp
(defun fib (n)
(if (< n 2)
1
(+ (fib (- n 2)) (fib (- n 1)))))
(fib 10)
$ cat fib.lisp | ./jar.2
89.000000
```

## 解説

初の言語処理系作品。1465バイトに次の機能が盛り込まれているとのこと。

```
+ - * < ()
car cdr cons defun equal
function if lambda quote t
```

jar.2.hintにかんたんなサンプルコードがいくつか掲載されている。
エラーチェックは非常に甘く、たとえば最初のカッコの前にスペースがあったら動かないとのこと。

形状の意味は特に解説されておらず不明だが、カッコを表現しているだろうか(下のほうがよくわからないが)。
上下に挟まれた行のアルファベットだけ拾い読みすると`O B F U S C A T E D L i s p`になっている。

```
,O;}B(F)U S(C(A(T(E)?D:_)));}L(i,s)p
```

作者のコメントによると、「Lispはコンスセルを基本データとするが、このプログラムは`char*`を基本とする」と書かれている。
つまり単なるベタメモリということで、基本的にはただのジョークだと思うけれど、実際、組み込み関数のテーブルは`{関数名,関数ポインタをchar*にキャストしたもの}`の列となっている(構造体を宣言する必要がなくなるのでコードが小さくなる効果はあると思う)。

オリジナルのソースコードは、グローバル変数の配列が連続領域に確保されていることを前提としている。
`p r[4][2]={...};``p not[99][2]={...};`とう定義に対して`r[13]``not[9]`をアクセスする。
このようにした理由はわからない(特に小さくなるわけでも、レイアウトしやすくなるわけでもないと思うし、`not`は直接アクセスされていない)。
単に難読化のためだろうか。
このせいで現代のコンパイラで最適化オプション付きでビルドするとsegfaultになって動かないので、ひとつの定義とするように修正をおこなった。

[[[1989/jar.1]]]({{ site.baseurl }}{% link 1989/jar.1.md %})と合わせ、同じ年に同じ作者の作品が複数入賞した初の事例。
54 changes: 54 additions & 0 deletions 1989/ovdluhe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
id: 1989/ovdluhe
year: 1989
order: 3
patch: true
authors: "Oskar_von_der_Luehe"
orig_url: "https://www.ioccc.org/1989/ovdluhe.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1989/ovdluhe.hint"
title: "IOCCC 1989: Most humorous output"
award_ja: "もっともユーモラスな出力"
---

## 動作

与えられたテキストを参考に、適当な文字列を生成していく。

```
$ gcc -o ovdluhe ovdluhe.c
$ ./ovdluhe < /usr/share/dict/american-english-small
's
Catholic's
Catholicism
Americans
April's
American
Asians
F
F's
Frence
absconding
abunday's
Tuesday's
Christmases
Thursday
Wednesday's
Frence
abbeys
...
```

## 解説

「猿がタイプライターを無限に叩き続ければ、いつか必ず任意のテキスト(たとえばシェイクスピアの作品でも)を打ち出す」という[無限の猿定理](https://ja.wikipedia.org/wiki/%E7%84%A1%E9%99%90%E3%81%AE%E7%8C%BF%E5%AE%9A%E7%90%86)に着想を得た作品。
最近出力した4文字分だけの記憶を持ち、元のテキストの中でその4文字の直後に現れる確率が高い文字をランダムに選んで出力する、というのを繰り返す。

難読化は、識別子がape(猿)っぽい文字列ばかりという程度だと思う。
興味深い挙動というネタで勝利した作品。

次の3点を修正した。

* `#define D define`して`#D`するコードを展開。
* `typedef char ape`とした上で`unsigned ape`とするのはダメなようなので`unsigned char`に置き換え。
* `*(ep-A)= *(ep++);`は未定義動作(副作用完了点の前に変更と読み出しがある)ので`*(ep-A)= *(ep),ep++;`に修正。
54 changes: 54 additions & 0 deletions 1989/paul.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
id: 1989/paul
year: 1989
order: 4
authors: "Paul_E._Black"
orig_url: "https://www.ioccc.org/1989/paul.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1989/paul.hint"
title: "IOCCC 1989: Most complex algorithm"
award_ja: "もっとも複雑なアルゴリズム"
linewarp: true
---

## 動作

2進数でフィボナッチ数を列挙していく。

```
$ gcc -m32 -o paul paul.c
$ ./paul
1
10
11
101
1000
1101
10101
100010
110111
1011001
10010000
11101001
101111001
1001100010
1111011011
11000111101
101000011000
1000001010101
1101001101101
10101011000010
100010100101111
...
```

## 解説

チューリングマシンのシミュレータ。
詳細未解読だが、3文字1組で状態遷移の規則を表現しているらしい(遷移元状態、遷移先状態、遷移条件やヘッダ移動や出力など)。
デフォルトのチューリングマシンが組み込まれていて、それがフィボナッチ列挙になっている。

独自のVMやシミュレータによる難読化の先駆けか。
1994年のguidelineから、この方式の難読化はもっとクリエイティブになること(面白い挙動をするとか)が期待されるようになっている。

ポインタを`int`に変換しているので、`-m32`が必要。
38 changes: 38 additions & 0 deletions 1989/robison.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
id: 1989/robison
year: 1989
order: 5
patch: true
authors: "Arch_D_Robison"
orig_url: "https://www.ioccc.org/1989/robison.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1989/robison.hint"
title: "IOCCC 1989: Best minimal use of C"
award_ja: "Cの最高の最小限の使い方"
---

## 動作

極小のAPLインタプリタ。2進数の足し算、引き算、掛け算ができる。

```
$ gcc -o robison robison.c
$ echo "101 x 111 - 100" | ./robison
1111
```

APLではこれは5 x (7 - 4) = 15を表すとのこと。

```
$ echo "(101 x 111) - 100" | ./robison
11111
```

これは(5 x 7) - 4 = 31になっている。

## 解説

[[[1988/robison]]]({{ site.baseurl }}{% link 1988/robison.md %})に続き、C言語の利用構文を制限して書かれている(作者はこれをC\-\-と言っている)。
robison.hintに書かれた作者コメントによると、関数呼び出し、間接参照、配列代入、コンマ、`sizeof`だけを使用して多倍長2進数計算を実現しているとのこと。

マクロ定義中の`D/**/f``D##f`などに置き換える変更が必要だった。
31 changes: 31 additions & 0 deletions 1989/roemer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
id: 1989/roemer
year: 1989
order: 6
patch: true
authors: "Roemer_B._Lievaart"
orig_url: "https://www.ioccc.org/1989/roemer.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1989/roemer.hint"
title: "IOCCC 1989: Best layout"
award_ja: "最高のレイアウト"
---

## 動作

[ネイピア数e](https://ja.wikipedia.org/wiki/%E3%83%8D%E3%82%A4%E3%83%94%E3%82%A2%E6%95%B0)を3141バイトほど出力する。

{: .wrap }
```
$ gcc -o roemer roemer.c
$ ./roemer
2.7182818284590452353602874713526624977572470936999595749669676277240766303535475945713821785251664274274663919320030599218174135966290435729003342952605956307381323286279434907632338298807531952510190115738341879307021540891499348841675092447614606680822648001684774118537423454424371075390777449920695517027618386062613313845830007520449338265602976067371132007093287091274437470472306969772093101416928368190255151086574637721112523897844250569536967707854499699679468644549059879316368892300987931277361782154249992295763514822082698951936680331825288693984964651058209392398294887933203625094431173012381970684161403970198376793206832823764648042953118023287825098194558153017567173613320698112509961818815930416903515988885193458072738667385894228792284998920868058257492796104841984443634632449684875602336248270419786232090021609902353043699418491463140934317381436405462531520961836908887070167683964243781405927145635490613031072085103837505101157477041718986106873969655212671546889570350354021234078498193343210681701210056278802351930332247450158539047304199577770935036604169973297250886876966403555707162268447162560798826517871341951246652010305921236677194325278675398558944896970964097545918569563802363701621120477427228364896134225164450781824423529486363721417402388934412479635743702637552944483379980161254922785092577825620926226483262779333865664816277251640191059004916449982893150566047258027786318641551956532442586982946959308019152987211725563475463964479101459040905862984967912874068705048958586717479854667757573205681288459205413340539220001137863009455606881667400169842055804033637953764520304024322566135278369511778838638744396625322498506549958862342818997077332761717839280349465014345588970719425863987727547109629537415211151368350627526023264847287039207643100595841166120545297030236472549296669381151373227536450988890313602057248176585118063036442812314965507047510254465011727211555194866850800368532281831521960037356252794495158284188294787610852639813955990067376482922443752871846245780361929819713991475644882626039033814418232625150974827987779964373089970388867782271383605772978824125611907176639465070633045279546618550966661856647097113444740160704626215680717481877844371436988218559670959102596862002353718588748569652200050311734392073211390803293634479727355955277349071783793421637012050054513263835440001863239914907054797780566978533580489669062951194324730995876552368128590413832411607226029983305353708761389396391779574540161372236187893652605381558415871869255386061647798340254351284396129460352913325942794904337299085731580290958631382683291477116396337092400316894586360606458459251269946557248391865642097526850823075442545993769170419777800853627309417101634349076964237222943523661255725088147792231519747780605696725380171807763603462459278778465850656050780844211529697521890874019660906651803516501792504619501366585436632712549639908549144200014574760819302212066024330096412704894390397177195180699086998606636583232278709376502260149291011517177635944602023249300280401867723910288097866605651183260043688508817157238669842242201024950551881694803221002515373
```

## 解説

πの形状で、識別子も`_31415`のようなものばかりになっているが、eを計算するというフェイント。

桁数が3141(小数点含む、改行文字を含めたら3142バイト)というのも芸が細かい。

文字列リテラルを破壊しているので、`strdup`か何かが必要。しかしこの作品はレイアウトも重要なので、なるべく崩さないように修正した。
Loading

0 comments on commit 1960861

Please sign in to comment.