Skip to content

Commit

Permalink
Publish spoilers for IOCCC 1990
Browse files Browse the repository at this point in the history
  • Loading branch information
mame committed Jan 30, 2021
1 parent 6ce2c6e commit 56291d1
Show file tree
Hide file tree
Showing 53 changed files with 2,360 additions and 0 deletions.
68 changes: 68 additions & 0 deletions 1990/baruch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
id: 1990/baruch
year: 1990
order: 1
authors:
- "Doron_Osovlanski"
- "Baruch_Nissenbaum"
orig_url: "https://www.ioccc.org/1990/baruch.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1990/baruch.hint"
title: "IOCCC 1990: Best Small Program"
award_ja: "最高の小さいプログラム"
linewrap: true
---

## 動作

Nクイーンのソルバ。

```
$ gcc -o baruch baruch.c
$ echo 4 | ./baruch
Q #
# #Q
Q# #
# Q
#Q#
Q #
# Q
#Q#
$ echo 7 | ./baruch
Q# # #
# Q # #
# #Q#
# # # Q
Q # #
# #Q# #
# # Q
Q# # #
# #Q# #
# # #Q
# Q # #
# # Q
#Q# # #
# #Q#
Q# # #
# # Q #
Q # #
# # #Q#
#Q# #
# # # Q
# Q #
...
```

## 解説

200バイトちょっとの短いコードでNクイーンの解を列挙する。
`main`の中に`for`文がひとつあるだけのコードになっていて、このループがすべての処理でうまく使いこなされているのだと思う。
詳細は未解析。
51 changes: 51 additions & 0 deletions 1990/cmills.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
id: 1990/cmills
year: 1990
order: 2
patch: true
authors: "Christopher_Mills"
orig_url: "https://www.ioccc.org/1990/cmills.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1990/cmills.hint"
title: "IOCCC 1990: Best Game"
award_ja: "最高のゲーム"
linewrap: true
---

## 動作

ブラックジャック。ダブルダウン、スプリット、インシュランスなど、いろいろ本格的。

```
$ gcc -DM=500 -DN=52 -DX="srand((int)time(0L))" -DV=void -o cmills cmills.c
$ ./cmills
Shuffle...
Total $1000. Wager?500
Dealer: Q? Player: 37
Double?y
Dealer: Q8 Player: 37K
Total $2000. Wager?500
Dealer: Q? Player: 56
Double?n
Hit?y
Dealer: Q? Player: 56J
Hit?n
Dealer: Q7 Player: 56J
Total $2500. Wager?500
Dealer: A? Player: 6A
Insurance?y
Double?n
Hit?y
Dealer: A? Player: 6AK
Hit?y
Dealer: A3Q6 Player: 6AK8
Total $1750. Wager?
...
```

## 解説

C89が制定された新時代らしく、ANSI-compliantがうたわれている。
難読化としては、短い識別子を使い、インデントを破壊した程度ではないかと思うが、詳しくは見ていない。

文字列リテラルを破壊しているので修正が必要。
62 changes: 62 additions & 0 deletions 1990/dds.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
---
id: 1990/dds
year: 1990
order: 3
patch: true
authors: "Diomidis_Spinellis"
orig_url: "https://www.ioccc.org/1990/dds.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1990/dds.hint"
title: "IOCCC 1990: Best Language Tool"
award_ja: "最高の言語ツール"
---

## 動作

[BASIC](https://ja.wikipedia.org/wiki/BASIC)インタプリタ。付属するLANDER.BASを起動する例。

```
$ gcc -o dds dds.c
$ ./dds
Ok
OLD LANDER.BAS
Ok
RUN
You aboard the Lunar Lander about to leave the spacecraft.
Ready for detachment
-- COUNTDOWN --
10
9
8
7
6
5
4
3
2
1
0
You have left the spacecraft.
Try to land with velocity less than 5 m/sec.
Meter readings
--------------
Fuel (gal):
500
Velocity (m/sec):
70
Height (m):
1000
How much fuel will you use?
```

## 解説

言語処理系の作品。
これまでの同系統の作品と比べると、多くのコマンドや演算子がサポートされていて、丁寧に作られている。
難読化としては、ブロック上にしただけで特筆することはないと思う。

サンプルコードである[LANDER.BAS](https://github.com/ioccc-src/winner/blob/main/1990/LANDER.BAS)[Lunar Lander(月面着陸ゲーム)](https://en.wikipedia.org/wiki/Lunar_Lander_%28video_game_genre%29)
ターン毎に現在の燃料の残量、対地速度、高さが表示され、燃料の使用量を調整して地上に軟着陸することを目指す、レトロなテキストベースゲーム(1969年からあるらしい)。
この記事はネタバレ解説なので単純な攻略法を書くと、燃料をまったく使わずに落ちていき、墜落の直前で全量を噴射するとクリアできる。

`&&`の後に`void`を返す関数(`free()`)を書けなくなっていたので、そこだけ修正が必要。
37 changes: 37 additions & 0 deletions 1990/dg.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
id: 1990/dg
year: 1990
order: 4
patch: true
authors: "David_Goodenough"
orig_url: "https://www.ioccc.org/1990/dg.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1990/dg.hint"
title: "IOCCC 1990: Best Abuse of the C Preprocessor"
award_ja: "Cプリプロセッサの最高の悪用"
---

## 動作

ROT13エンコーダ。

```
$ gcc -o dg dg.c
$ echo Hello | ./dg
Uryyb
```

## 解説

トークンを1つだけ追加するマクロを大量に定義し、それらを組み合わせるだけでプログラムを構成している。
単純だがおもしろい。

```
#define aqu(x) x'
#define bqu(x) 'x
aqu(bpu(A))
```

によって`'A'`を作り出す、というのは動かないので、これは`'A'`に置き換えた(このことはdg.hintにも書かれている)。
また、`#define d define`のトリックも動かないので書き下した。
17 changes: 17 additions & 0 deletions 1990/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
year: 1990
title: "IOCCC 1990の解説"
layout: contest
---
## 全体の印象

プログラムの挙動のおもしろさを目指すものと、難読化の創意工夫を目指すもので二極化してきたように見える。

前者の系統の作品は難読化自体は目新しくなく、短い変数名でインデントをつぶした程度のものが多いが、[[[1990/tbr]]]({{ site.baseurl }}{% link 1990/tbr.md %})はコード形状で遊び始めていて、今後のIOCCCの方向性を示している。
後者の「難読化の創意工夫」の系統の作品は、まだ1つのアイデアで押し通す一点突破ものが多い。

個人的な好みでは、[[[1990/westley]]]({{ site.baseurl }}{% link 1990/westley.md %})の超絶技巧と、[[[1990/theorem]]]({{ site.baseurl }}{% link 1990/theorem.md %})のコード遊びが飛び抜けていると思う。

この回はC89(ANSI C)規格化後初のIOCCCであり、ANSI Cに捧ぐコンテストとなっている。
が、直接的にC89にからめた作品は[[[1990/scjones]]]({{ site.baseurl }}{% link 1990/scjones.md %})だけか。
付属のMakefileでコンパイルする場合、`make`時に`USE=ansi``USE=common`をつけないといけなくなっている。
104 changes: 104 additions & 0 deletions 1990/jaw.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
---
id: 1990/jaw
year: 1990
order: 5
authors:
- "James_A._Woods"
- "Karl_F._Fox"
- "Paul_Eggert"
orig_url: "https://www.ioccc.org/1990/jaw.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1990/jaw.hint"
title: "IOCCC 1990: Best Entropy-reducer"
award_ja: "最高のエントロピー削減器"
---

## 動作

一言で言えば、テキスト化された自己解凍アーカイブのためのCコード。
ここでは最終的な動作だけを示し、詳しい説明は解説に回す。

添付されている[shark.sh](https://github.com/ioccc-src/winner/blob/main/1990/shark.sh)(jaw.cが埋め込まれている)を使うと自己解凍アーカイブができる。
実行には[compressコマンド](https://ja.wikipedia.org/wiki/UNIX_Compress)とbtoaコマンド(後述)が必要。

```
$ PATH=.:$PATH sh shark.sh jaw.* > archive
```

これを別ディレクトリで解凍する。

```
$ mkdir test
$ cd test
$ sh ../archive
...
```

元と同じファイルが生成されていることが確認できる。

```
$ ls
jaw.c jaw.hint
$ diff -s jaw.c ../jaw.c
Files jaw.c and ../jaw.c are identical
$ diff -s jaw.hint ../jaw.hint
Files jaw.hint and ../jaw.hint are identical
```

## 解説

当時の通信環境では、通信速度が遅いのでデータ圧縮することが必須だった。
一方で、プロトコルの都合により、テキスト形式にすることも必要だった。
そのため、データを送信する人は圧縮したうえでバイナリ→テキスト変換を行い、受信側はその逆の手順を行っていた(メールの添付ファイルは現代でもBase64によるバイナリ・テキスト変換を行っているが、メールのクライアントが勝手に処理するので意識することは少ない)。
ここで問題になるのは、受信側が適切なツール群を持っていない場合、デコードができないということだった。

この作品はこの問題を解決するために作られた。
このプログラムは、atobの機能と、zcatの機能を備える。
atobは[btoa](https://en.wikipedia.org/wiki/Ascii85#btoa_version)というバイナリ→テキスト変換の結果を逆変換する機能、zcatはcompressで圧縮されたデータを解凍する機能。
これらを使うことで、テキスト→バイナリ変換かつ解凍を行える。

このプログラムのバイナリは`atob`という名前で起動されたとき(`argv[0]``'a'`のとき)、atobモードで動く。

```
$ echo Hello | ./btoa
xbtoa Begin
87cURD[HIE
xbtoa End N 6 6 E 48 S 206 R 5520
$ echo Hello | ./btoa | ruby -e 'exec(["./atob", "atob"])'
Hello
```

バイナリが`a`で始まらない場合、このプログラムはzcatモードで動く。

```
$ echo Hello | compress | ./zcat
Hello
```

shark.shで作られた自己解凍アーカイブはjaw.cを埋め込んでいる(1100バイト程度とのこと)ので、受信側はあらかじめatobやzcatを用意しておく必要はない。
アーカイブを実行するとこのCコードをコンパイルしてatobとzcatを作り、それらを使ってデータを展開できる。
ただし受信側にCコンパイラやtarコマンドは必要。

このツールはひょっとしたら半分くらいまじめに実利用を狙っていたのかもしれない。
実用性が難読化(ショートコーディング)に依存しているなど、開発の経緯がjaw.hintに書かれている。
不幸にも現代ではcompressもbtoaも陳腐化しており、起動するのも苦労した。
btoaはUbuntuにパッケージがなかったので、いろいろ調べながらRubyで雑に書いたbtoaを置いておく。

```
#!/usr/bin/env ruby
puts "xbtoa Begin"
data = $<.read
n, e, s, r = data.bytesize, 0, 0, 0
(-n % 4).times { data << 0 }
data.bytes do |b|
e, s, r = e ^ b, (s + b + 1) & 0xffffffff, (r * 2 + r[31] + b) & 0xffffffff
end
data.unpack("N*").flat_map do |v|
v == 0 ? [?z.ord] : (0..4).map {|i| v / 85**(4 - i) % 85 + 33 }
end.pack("C*").scan(/.{1,78}/) { puts $& }
puts "xbtoa End N %d %x E %x S %x R %x" % [n, n, e, s, r]
```
54 changes: 54 additions & 0 deletions 1990/pjr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
id: 1990/pjr
year: 1990
order: 6
authors: "Peter_J_Ruczynski"
orig_url: "https://www.ioccc.org/1990/pjr.c"
hint_url: "https://github.com/ioccc-src/winner/blob/main/1990/pjr.hint"
title: "IOCCC 1990: Most Unusual Data Structure"
award_ja: "もっとも異常なデータ構造"
---

## 動作

固定メッセージを出力するだけ。

```
$ gcc -o pjr pjr.c
$ ./pjr
the quick brown fox jumped over the lazy dog
```

## 解説

`X=g().s().v().S().j().f().r().x().p().`...というメソッドチェーンのようなコード。
1関数が1文字を出力する。
`.a()``z``.b()``y``.c()``x`というように、abc順を反転した文字を出すとのこと。

実現するためには構造体を使えばよい。大まかには次のような構造になっている。

```
// 関数プロトタイプ宣言
struct F a();
struct F b();
struct F c();
...
// 肝となる構造体
struct F {
struct F (*a)(), (*b)(), (*c)(), ...;
} X = { a, b, c, ... };
// 関数定義(かならずXを返す)
struct F a() { printf("a"); return X; }
struct F b() { printf("b"); return X; }
struct F c() { printf("c"); return X; }
...
main(){
X = a().b().c()...;
}
```

一発ネタの難読化でシンプルにまとめられている。
Loading

0 comments on commit 56291d1

Please sign in to comment.