climpetさんのものすごいC
climpetさんも194Bのコードを公開してくださっているので、紹介しておきます。
char z['÷']; i,j,c,n,w; main(h){ scanf("%d%d%d %[^_]",&n,&h,&w,z); for(h*=++w;i<n*h;++i) for(c=j=9;j--;z[h+i]=~i%w?c-15&&z[i]%c?46:42:10) c+=z[(i%w-j%3+w)%~-w+(i/w-j/3-~h)*w%h+i/h*h]%3; n=!puts(z+i); }
全体的にはtailsさんと同じですが、配列サイズに'÷'という定数を用いています。'÷'はUTF-8でC3B7(50103)で、今回はn, h, wの最大値がそれぞれ30, 40, 35ですので、30×40×35=42000あれば良いので十分な大きさです。
特に素晴らしいのはやはり生死判定の部分ですね。カウンタ変数cの初期化コストを抑えるため、近傍走査のためのループ変数jと同じ値(9)をセットしています。'.', '*'のASCIIコードはそれぞれ46, 42で、これらに対してで3の剰余を計算するとそれぞれ1, 0になることから、死んでいるセルをカウントしています。このようにすると、
- 中心セルが「死」で周囲3セルが「生」の場合、cは6加算
- 中心セルが「生」で周囲2セルが「生」の場合もcが6加算
されることになります。つまり、これら2つの条件はcが9+6=15であるかどうかの判定だけで済みます。残りの条件の判定を行うため、同じようにcの値を見てみると
- 中心セルが「生」で周囲3セルが「生」の場合、cは5加算
なので、cの値は9+5=14になります。しかし、今度は14かどうかの判定をしようとすると、
- 中心セルが「死」で周囲5セルが「生」の場合もcが5加算
となり、14かどうかを調べるだけでは判定できません。これらの区別するのに、'.'と'*'のASCIIコードすなわち46と42を利用しています。
- 中心セルが「死」の場合はASCIIコードが46で、14で割り切れない
- 中心セルが「生」の場合はASCIIコードが42で、14で割り切れる
これを上手く利用しています。cの初期値が9であることと、死んでいるセルをカウントするということ、ASCIIコードの値の調和がたまらないコードですね!!