236B ライフゲーム
SDL なんちゃら に行ったところ goruby/SDL とかいう声が囁かれていたのでその場でライフゲームとか書きました。
rq'sdl' S.i(S) s=S::Screen.op(640,480,32,S::SWSURFACE) E=S::Event a=Array.ne(W=3072){rd 2} lp{a=(1..W).m{|i|s.fR(i%64*10,i/64*10,10,10,a[i-1]*255) v=(0..9).ij{|w,j|w+a[(i+~-j/3*64+j%3-66)%W]} v==3||v-a[i-1]==3?1:0} s.fp E.p.cl==E::K&&x}
まぁゴルフとしてはまだまだ縮むんですが私が言いたいことは世の中のライフゲームのルールの説明は(少なくともプログラマにとっては)非常にいけてないと思うということです。
Wikipedia なんかを見ると、
http://ja.wikipedia.org/wiki/%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B2%E3%83%BC%E3%83%A0
誕生 死んでいるセルの周囲に3つの生きているセルがあれば次の世代では生きる(誕生する)。 維持 生きているセルの周囲に2つか3つの生きているセルがあれば次の世代でも生き残る。 死亡 上以外の場合には次の世代では死ぬ。
などと書いてあるのですが、周囲のセルの合計を取るってコードは
for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { if (i == 0 && j == 0) continue; sum += ... } }
とかそんなのになって、このループの中の if 文がすごく嫌いなのです。
でもまぁ元の定義の「周囲」を「周囲を含めた3*3の空間」とかに書き変えてみると以下のようになるわけです。
誕生 死んでいるセルの周囲を含めた3*3の空間に3つの生きているセルがあれば次の世代では生きる(誕生する)。 維持 生きているセルの周囲を含めた3*3の空間に3つか4つの生きているセルがあれば次の世代でも生き残る。 死亡 上以外の場合には次の世代では死ぬ。
と、日本語は冗長な感じになったんですが、これであればアルゴリズムとしてはさっきの if が消えて短くなるわけです。当たり前に見えるんだけど、実際に どう書く.org のライフゲーム とか見てみると、たいてい私の嫌いな if があるか、単に 8 個足し算を書いてるかだったりします。
こういうアルゴリズムとしての冗長性が消える短縮化っていうのはゴルフじゃなくても割と重要で、ゴルフやってるとこういう変換に慣れてくるのは、ゴルフの数少ないメリットと言えなくもないかなぁという感じではあります。こういう些細なところを見直す機会というのは普段のコーディングではなかなか無いですし。
TODO: それはそうと SDL なんちゃらでさらしたものは過去に遡って公開する(どうせ続きとか作らん気がするし)。