TOP >> マニアックなプログラミング
トリッキーコードネット トリッキーなコード

【芸術的な凄いプログラミング】IOCCC作品のコード解説4:数字の渦巻きを表示

a[900]; b;c;d=1 ;e=1;f; g;h;O; main(k, l)char* *l;{g= atoi(* ++l); for(k= 0;k*k< g;b=k ++>>1) ;for(h= 0;h*h<= g;++h); --h;c=( (h+=g>h *(h+1)) -1)>>1; while(d <=g){ ++O;for (f=0;f< O&&d<=g ;++f)a[ b<<5|c] =d++,b+= e;for( f=0;f<O &&d<=g; ++f)a[b <<5|c]= d++,c+= e;e= -e ;}for(c =0;c<h; ++c){ for(b=0 ;b<k;++ b){if(b <k/2)a[ b<<5|c] ^=a[(k -(b+1)) <<5|c]^= a[b<<5 |c]^=a[ (k-(b+1 ))<<5|c] ;printf( a[b<<5|c ]?"%-4d" :" " ,a[b<<5 |c]);} putchar( '\n');}} /*Mike Laman*/
↑のコードは、1984年(第一回)IOCCCの登場作品です。 このコードをコンパイルして実行すると、数字の渦巻きが表示されます。( ^ω^)オモスレー 数字の渦巻きって何ぞや??と思われた方、↓の画像をご覧下さい。 IOCCC作品の解説:渦巻き数字プログラミング 中央に1があり、そこから反時計回りに任意の数まで、数字が順に並んで表示されます。 C言語の標準出力は、 左 → 右 そして、 上 ↓ 下 へと表示されるため、最終的に渦巻き状に数字を配置するには、出力の都度、計算が必要になります。 ちょっと面白いです^^;) VC++2005での実行方法: 特にコードを修正する必要もなく、そのままコンパイル、実行できます。 ただし、以下の様な警告が表示されるため、 ---------------------------------------------------------------- warning C4013: 関数 'atoi' は定義されていません。int 型の値を返す外部関数と見なします。 warning C4013: 関数 'printf' は定義されていません。int 型の値を返す外部関数と見なします。 warning C4013: 関数 'putchar' は定義されていません。int 型の値を返す外部関数と見なします。 ---------------------------------------------------------------- これが気になる方は、コードの先頭に以下2行を記述して下さい。
#include <stdio.h> #include <stdlib.h>
出来上がった実行ファイルに、パラメータ(幾つの数までの渦巻きを表示するか)を渡せば、 数字の渦巻きが表示されます。 それではいよいよ、お待ちかね、アルゴリズムの解説を行います。キタ━(゚∀゚)━!!!!! 冒頭のコードですが、そのままだと非常に見辛い!! ・・・というわけで、まず改行 及び インデントを入れます。 そして、変数O(オー)が、0(ゼロ)と紛らわしい為「r」に置換します。 変数l(エル)が、1(イチ)や|(or演算子)と紛らわしい為、「s」に置換します。 ついでに、お行儀良く#include <stdio.h>と、#include <stdlib.h>も付け足します。 という訳で、冒頭のコードを多少読みやすく(?)修正したコードがコチラ↓↓
#include <stdio.h> #include <stdlib.h> a[900]; b; c; d=1; e=1; f; g; h; r; main(k,s)char**s; { g = atoi(*++s); for(k=0; k*k < g; b=k++>>1); for(h=0; h*h<=g; ++h); --h; c = ( (h += g>h*(h+1)) -1 ) >> 1; while(d <=g){ ++r; for(f=0; f< r && d<=g; ++f) a[b<<5|c] =d++, b+=e; for(f=0; f<r && d<=g; ++f) a[b<<5|c]=d++, c+=e; e= -e; } for(c=0; c<h; ++c){ for(b=0; b<k; ++b) { if(b <k/2) a[b<<5|c] ^=a[(k-(b+1)) << 5|c] ^= a[b<<5|c] ^= a[(k-(b+1))<<5|c]; printf(a[b<<5|c] ? "%-4d" : " ",a[b<<5|c]); } putchar('\n'); } } /* Mike Laman */
このコードの先頭から読み解いていきます。 C言語では、変数の型が宣言されない場合、int型変数とみなします。 その為、グローバル変数のa,b,c,d,e,f,g,h,rは int型の変数です。 main関数のパラメータkも、int型の変数です。 また、main(k,s)char**s;{} は古いコードの書き方ですが、現在でいう main(k, char ** s){} に相当します。 (つまり、main(k,s)char**s;{} の部分は、変数名の違いこそあれ、良く目にする main(int argc, char ** argv){} と同じ物だという事です^^;) その下の g = atoi(*++s) ですが、 プログラム実行直後、 *sには第1パラメータ(通常はプログラムのパス)文字列へのポインタ、 *(s+1)には第2パラメータ(ここでは、ユーザが入力した任意の数)文字列へのポインタ が格納されています。 つまり、g = atoi(*++s)は、g = atoi( *(s+1) )と直す事ができ、変数gにユーザが入力した値を代入しているだけです。
トリッキーコードネット の TOPへ HOTNEWS の 総合TOPへ