カメヲラボ

主にプログラミングとお勉強全般について書いてます

ISBN(3)

超絶テクニック(その2)

まず、このコードを見てほしい。


main(n){
int a=11,b,s;
for(;a--;){
n=getchar();
if(n==63)b=a;
else if(n==88)s+=10;
else if(n>=48&&n<=57)s+=(n-48)*a;
}
s-=b;
for(;s%11;a++)s+=b;
printf(a+b?"%d":"X",a);
}


最初のループは冗長なコードであるが、最後の2行はとてもスッキリしている。仕組みは、
①最初のループで終了判定をa--にすることで、ループを抜けた後のaが-1にセットされ、2番目のループはa=-1で始まる。


②2番目のループで'?'が現れた桁数b(一番左なら10、一番右なら1)を合計値sに加えていく。sが11で割り切れるとループを抜ける。


③最初から割り切れる場合はa=-1になり、a==-1かつb==1('?'が一番最後の桁)ならば'X'を出力、そうでなければaの値をそのまま出力する。a==-1かつb==1ということは、a+b==0であれば良いということになり、最後のprintfまでスッキリ記述できる。


もし最初のループの終了判定を--aとしていれば、ループを抜けた直後のaは0であり、2番目のループを抜けた時に不正なISBNまたは最後の桁がXの場合、a=10になってしまう。これでも良さそうだが、その場合は最後のprintfが冗長になってしまうのだ。


前回の113byteコードでは、このようなテクニックを全く利用していない。おそらくこのコードを短縮するだけでも113byteは切れるだろう、と私は思ったのだが一人でやってても面白くなさそうだから煽ってみた次第だ。