上位1位から5位までのコードと、柳井氏による解説付きコードは以下のとおり。
1位:tompng氏(194文字)
2位:hogeover30氏(202文字)
3位:colun氏(210文字)
4位:mtym氏(214文字)
5位:hotpepsi氏(215文字)
6位:もけもけちきん氏(219文字)
7位:yvl氏(221文字)
8位:mbsp氏(227文字)
8位:sta_k氏(227文字)
9位:setchi_氏(228文字)
10位:OrgaChem氏(233文字)
for(u=[i=4];i--;)for(x=y=s=j=c="";y<40;j++<160?c=( p=1+r%78-x)*p+(q=1+r%38-y)*q<2?2-!p+!q:c:j=c&=s+=" \n|*-_%"[x++<80?c||2*Math.abs(x-41)<y+y%8|4:x&=u[y ++,i]=s])r=(i+j)*j*49999-5537&65535;return u
/* * アニメの制御 */ for( u=[i=4]; // 配列数と4要素の配列を初期化 i--; // 配列数分の処理を行い、iが0になれば終了 ) /* * 各マスとイルミネーションの制御 */ for( x=y=s=j=c=""; // 変数を初期化 0値の変数は""で初期化を統合 y<40; // 高さの回数計算 j++<160 // 160はイルミネーションの個数 // 全てのイルミネーションの位置を確認 ? /* * イルミネーションの個数以下の場合は、現在XY位置に対応した * イルミネーションが存在するか確認する */ c= ( p=1+r%78-x // 「1+r%78」はイルミネーションXの位置 // 「-x」することで、距離を求める )*p+( q=1+r%38-y // 「1+r%38」がイルミネーションYの位置 // 「-y」することで、距離を求める )*q <2 // イルミネーションの中心座標からの距離 // 距離が2未満ならばイルミネーションの一部が // 現在走査中の座標に差し掛かっていると判断 ? /* * イルミネーションの場所である */ 2-!p+!q // 中心か否かを判定 「!」を使うことで0か1を生成 // 中心なら2、上下なら1、左右なら3 : /* * イルミネーションの場所ではない */ c // 初期値の0か、上記で判定した1〜3の値になる : /* * イルミネーションを全て確認したら描画を行う */ j= // jを初期化(cと同じ値) c&= // cを初期化(数値以外とビット演算して0を生成) s+= // 文字列をアスキーアート1枚分連結していく "\n|*-_%"[ x++<80 ? /* * 通常の行位置 */ c // イルミネーションであるなら、 // その位置の文字を取得 || // cが0だった(イルミネーションでない) // 場合は以下を計算 2*Math.abs(x-41) // 「2*Math.abs(x-41)」が < // 「y+y%8」より小さければ(trueなら) y+y%8 // 「1」になる、falseなら0になる // 「y+y%8」で、以下のように増え、 // 元の式と同じになる // 1+1=2, 2+2=4, 3+3=6, ... 7+7=14, // 8+0=8, 9+1=10, 10+2=12, ... |4 // 0|4で 0|b100なのでb100 つまり4→「_」 // 1|4で 1|b100なのでb101 つまり5→「%」 : /* * 改行位置 */ x&= // xを初期化(数値以外とビット演算して0化) u[ y++, // 行を1行加算 i // uの配列の現在位置iに対して ]=s // 連結し続けているsを格納 ] ) // 内側のfor文の「)」 r=(i+j)*j*49999-5537&65535; // 乱数もどき // 0xFFFF = 65535 // 59999-(0x10000)=-5537 // →「+59999 & 0xFFFF」と「-5537 & 0xFFFF」は等価 // 例)0xF = 15 = b1111 // 9 の場合は 9+(0x10) = 9+16 = 25 // 9 の場合は 9-(0x10) = 9-16 = -7 // 10+ 25 & 15 → 35 & 15 →b100011 & b1111 → b11 // 10+ 9 & 15 → 19 & 15 → b10011 & b1111 → b11 // 10- 7 & 15 → 3 & 15 → b11 & b1111 → b11 // マスクする値+1を足したり引いたりした値でも // 同じ結果になる return u
for(r=[a=4];a--;)for(p=y=r[a]="";y<40;p-=y%8?-1:3) for(x=!y++;x<81;r[a]+="_%*|-\n"[x++?f:5])for(i=f=4 1-p<x&x<p+41;i<160;f=(q=2*d*d+c*c)>2?f:q+2)t=(a+i) *i++*49999-5537&65535,c=t%38+2-y,d=t%78+2-x;return r
/* * アニメの制御 */ for( r=[a=4]; // 配列数と4要素の配列を初期化 a--; // 配列数分の処理を行い、aが0になれば終了 ) /* * y軸の制御 */ for( p=y=r[a]=""; // 変数を初期化 0値の変数は""で初期化を統合 y<40; // 高さの回数計算 p-=y%8?-1:3 // 「y%8」が0(false)になる時は、木のジグザグ // が発生する場所なので「3」を引く。 // 通常の場合は、1段y軸が下がるごとに1ずつ // 木のすそ野の幅を広くしていく ) /* * x軸の制御 */ for( x=!y++; // 最初の1回目のみ、xをtrue(1)で初期化 // 2回目からは、xをfalse(0)で初期化 // 2回目の0から、文字列の改行を参照する // ようになる x<81; // 横幅の回数計算 r[a]+="_%*|-\n"[x++?f:5] // xが0の場合は改行 // その他の場合は // アスキーアートを描画 ) /* * イルミネーションと背景と木 */ for( i=f= 41-p<x&x<p+41; // 背景なのか木なのかを判定 // 背景なら0(_)、木なら1(%)の文字列を参照 // 文字の位置を参照するfには0か1が入る // この値と同じ値を使い、イルミネーションの // ループを回すiを初期化する // 「i = 1」なら、ループの開始位置0にならない // のではという問題は、iが0の場合は一意に // x=18,y=36となり、ここは背景の位置なので // 「i = 0」の判定を行う必要がない。 // なので、「i = 0」を飛ばして、「i = 1」から // 開始して構わない i<160; // イルミネーションの数だけ確認 f=(q=2*d*d+c*c)>2?f:q+2 // イルミネーションの中心座標からの距離が2超なら // f(以前に入った値と同じ値)を取る // 2未満ならqを取る(新たな値になる) // 0は中心、1は縦線(c*c)、2は横線(2*d*d) // この0〜2に2を足すことで、文字列「"_%*|-\n"」の // 「*|-」を取得することができる ) t=(a+i)*i++*49999-5537&65535, // 乱数もどき // iの値を利用した後1増やす // 0xFFFF = 65535 // 59999-(0x10000)=-5537 // →「+59999 & 0xFFFF」と「-5537 & 0xFFFF」は等価 // 例)0xF = 15 = b1111 // 9 の場合は 9+(0x10) = 9+16 = 25 // 9 の場合は 9-(0x10) = 9-16 = -7 // 10+ 25 & 15 → 35 & 15 →b100011 & b1111 → b11 // 10+ 9 & 15 → 19 & 15 → b10011 & b1111 → b11 // 10- 7 & 15 → 3 & 15 → b11 & b1111 → b11 // マスクする値+1を足したり引いたりした値でも // 同じ結果になる c=t%38+2-y, // 「(t%38+1)-(y-1)」 d=t%78+2-x; // 「(t%78+1)-(x-1)」 // 距離を取る。1を引いているのは // x, y は1で開始しているから return r
for(v=u=[a=w=x=81];~a;x+160?0<x--?v[x]="_%\n"[2*!z |Math.abs(z-82)<y+y%8]:v[y=b%78+b%38*w+w]=v[v[++y] ="*",v[y-w]=v[y+w]="|",y+1]="-":u[a--]=v.join(v=[] ,x=3239))y=x/w|0,z=x%w*2,b=(x-a)*x*49999-5537&6553 5;return u
/* * 全ての計算を1つのループで回す */ for( v=u=[a=w=x=81]; // v, u を配列として初期化 // (中の値には意味がない) // a, w, x を81で初期化 ~a; // 「~」は、4バイト整数と見なして // 各ビットを反転させた結果を返す // 例) // 81 → -82 → true // 1 → -2 → true // 0 → -1 → true // -1 → 0 → false // -2 → 1 → true // つまり a が-1になるまで計算を行う x+160 // イルミネーション計算の分、160下駄を履かせる ? /* * アスキーアートの描画行う */ 0<x-- // x を減算 ? /* * x が0より大きい間は背景と木と改行の判定 */ v[x]="_%\n"[ 2*!z // z が0の場合(改行位置)のみ「!z」は // true(1)になる // そのため、で2番目の文字「\n」を // 参照する // その他の場合は「!z」はfalse(0) // になる // そのため「2*0=0」で「|」以降に // 1が来なければ「_」を参照する | Math.abs(z-82)<y+y%8 // z は2刻みで0〜160を取る // 「Math.abs(z-82)」で真ん中から // 折り返す // 「y+y%8」で、以下のように増え、 // 元の式と同じになる // 1+1=2, 2+2=4, 3+3=6, ... 7+7=14, // 8+0=8, 9+1=10, 10+2=12, ... ] : /* * x が0より小さい場合はイルミネーションの判定 * (ここで160の下駄を履かせたのが生きてくる) */ v[ y=b%78+b%38*w+w // イルミネーション // の位置を計算 ]= // 横棒が入る v[ // 横棒が入る v[++y]="*", // 中心が入る v[y-w]=v[y+w]="|", // 縦棒が入る y+1 ]= "-" : /* * 文字列を結合して配列に格納 */ u[a--]=v.join(v=[],x=3239) // join([])で、空文字連結と同じ // joinの第2引数(使わない場所)を利用して // 「x=3239」をセット // 3239 = (横80字+改行1字)×40行−末尾改行1字 // 「u[a--]」配列4つではなく、a=81で設定された // 数のアスキー後が格納される ) /* * 描画に必要な値を計算 */ y=x/w|0, // y 座標の値 // x/w の浮動小数点数に対してOR演算で0を // 指定することで、浮動小数点数を整数と // みなして計算を行い、結果的に整数を作る z=x%w*2, // z は2刻みで0〜160を取る b=(x-a)*x*49999-5537&65535; // 乱数もどき // x がマイナスの間だけ、イルミネーション用の // 変数として使われる。元のコードは「(a+i)*i」 // で正の値を前提としたコード // このiの位置にマイナスであるxを入れると値が // おかしくなる // そこで「(-a+x<負値>)*x<負値>」として、同等の // 計算が行えるようにする // // 0xFFFF = 65535 // 59999-(0x10000)=-5537 // →「+59999 & 0xFFFF」と「-5537 & 0xFFFF」は等価 // 例)0xF = 15 = b1111 // 9 の場合は 9+(0x10) = 9+16 = 25 // 9 の場合は 9-(0x10) = 9-16 = -7 // 10+ 25 & 15 → 35 & 15 →b100011 & b1111 → b11 // 10+ 9 & 15 → 19 & 15 → b10011 & b1111 → b11 // 10- 7 & 15 → 3 & 15 → b11 & b1111 → b11 // マスクする値+1を足したり引いたりした値でも // 同じ結果になる return u
for(i=r=[4];i--;)for(p=[w=y=x=40],h=t=0;y;p[h++]=' _%\n'[x+w?x--<t&~x<t:(t+=--y%8?1:-3,x=w,2)])for(r[ i]=p.join(c='');c<160;)for(n=5,f=(i+c)*c++*49999-5 537&65535,o=f%78+f%38*81;n--;p[o+=n%3?1:80]='|-*-| '[n]);return r
for( i=r=[4]; // 戻り値の配列rを初期化 // iは要素数1の配列 // 要素数1の数値配列は数値計算を行うと // 数値変数として動作する(要素数2以上 // ではNaN(Not a Number)になる) // 同様の処理は文字列でも行える i--; // 戻り値用の配列4つ分を計算 ) for( p=[w=y=x=40], // pは配列として初期化 // w, y, x は40で初期化 // ※ y は座標位置ではなく行数分 // 処理をするカウンタでしかない h=t=0; // h, t は0で初期化 y; // y が0になったら(全行走査 // したら終了) p[h++]='_%\n'[ // h で文字位置を指定 x+w // 「x+40」とすることで // アスキーアートを // 0になるまで80回描画可能 ? x--<t&~x<t // 「(x--<t)&(~x<t)」 // 左辺は x の値がt以下 // 右辺は x-1 の反転なので // 元の x の -x に等しい // なので 右辺は -x の値がt以下 // 満たすなら1で「%」を参照 // 満たさないなら0で「_」を参照 : // 改行位置 ( t+=--y%8?1:-3, // 改行位置なのでyを減算 // 「y%8」が0(false)になる時は、木のジグザグ // が発生する場所なので変化量は-3 // 通常の場合は、1段y軸が変化するごとに // 変化量は1 // その値をtに加える x=w, // xを40に戻す 2 // 文字列の改行位置を参照 ) ] ) for( // ここで、戻り値用の配列に結合した文字列を入れる r[i]=p.join(c=''); // c を''で初期化し0とみなす // joinは''の空文字列で結合 c<160; // イルミネーションの計算 ) for( n=5, // イルミネーションの文字数5 f=(i+c)*c++*49999-5537&65535, // 0xFFFF = 65535 // 59999-(0x10000)=-5537 // →「+59999 & 0xFFFF」と「-5537 & 0xFFFF」は等価 // 例)0xF = 15 = b1111 // 9 の場合は 9+(0x10) = 9+16 = 25 // 9 の場合は 9-(0x10) = 9-16 = -7 // 10+ 25 & 15 → 35 & 15 →b100011 & b1111 → b11 // 10+ 9 & 15 → 19 & 15 → b10011 & b1111 → b11 // 10- 7 & 15 → 3 & 15 → b11 & b1111 → b11 // マスクする値+1を足したり引いたりした値でも // 同じ結果になる o=f%78+f%38*81; // 中心の左上を基準点に n--; // nが0になるまで実行 p[ o+=n%3?1:80 // 改行があるので横81文字 // なので、80をy軸の移動量に取ると // 斜めに移動することになる // そのため、星の上部(@の位置)から // 移動を開始して、右(1)、下(80)、 // 右(1)、右(1)、右(1)、下(80)と // 移動する // @| // -*- // | ]= '|-*-|'[n] // nで取得位置を指定 ); return r
for(a=c=k=y=t=z='',b=[],i=h=40;j=y%8+y>>1,r=(a+k)* k*49999-5537&65535,v=r%38-y+1,w=r%78-h+i+1,a<4;)h+ i?k++<160?z=v*v+w*w<2?v?4:w?2:6:z:(c+="_%--||**"[z |i*i--<j*j],k=z=0):(i=h,++y<h?c+='\n':(b[a++]=c,c= y=''));return b
for( a=c=k=y=t=z='', // 変数を初期化 b=[], // 戻り値用の配列を初期化 i=h=40; // 40で初期化 j=y%8+y>>1, // 「y>>1」で整数演算の「÷2」と同じ // 「y+y%8」で、以下のように増え、 // 元の式と同じになる // 1+1=2, 2+2=4, 3+3=6, ... 7+7=14, // 8+0=8, 9+1=10, 10+2=12, ... r=(a+k)*k*49999-5537&65535, // 乱数もどき // 0xFFFF = 65535 // 59999-(0x10000)=-5537 // →「+59999 & 0xFFFF」と「-5537 & 0xFFFF」は等価 // 例)0xF = 15 = b1111 // 9 の場合は 9+(0x10) = 9+16 = 25 // 9 の場合は 9-(0x10) = 9-16 = -7 // 10+ 25 & 15 → 35 & 15 →b100011 & b1111 → b11 // 10+ 9 & 15 → 19 & 15 → b10011 & b1111 → b11 // 10- 7 & 15 → 3 & 15 → b11 & b1111 → b11 // マスクする値+1を足したり引いたりした値でも // 同じ結果になる v=r%38-y+1, // 「r%38+1」から y を引いて中心からの距離 w=r%78-h+i+1, // 「r%78+1」から「h-i」(40-i)(iは40から始 // まるので、0, 1, 2...と推移)を引いて // 中心からの距離 a<4; // aが4未満まで(配列数だけ)ループを回す ) h+i // h は固定値40、i は40から開始され減算されていく // そのため「40+i」が0になるまでがアスキーアートで // 0で改行と、戻り値用配列の遷移 ? /* * アスキーアートの処理 */ k++<160 // イルミネーションを調べる ? /* * イルミネーションの判定 */ z= v*v+w*w<2 // 中心からの距離が2未満 ? /* * イルミネーションが存在 */ v // 縦方向の確認 ? 4 // 0でない「|」である : w // 横方向の確認 ? 2 // 0でない「-」である : 6 // v, w 共に0なので「*」 : /* * イルミネーションでないので * 直前の z の値をそのまま維持する */ z : /* * 文字列を参照して結合 */ ( c+="_%--||**"[ z // イルミネーションの文字列参照位置 // 値は2(b10)、4(b100)、6(b110) // なので、下の式で1が来た場合には // 参照位置が1つ右にずれる // なので「--||**」と2文字ずつある | i*i--<j*j // 中心位置からの距離の比較 // i は0を中心に対称に広がる2乗で // 負の符号を相殺して、jの2乗と比較 // 距離がjの範囲内なら1、外なら0 ], k=z=0 // イルミネーション系変数を初期化 // k カウント // z 文字列参照位置 ) : /* * アスキーアート以外の処理 */ ( i=h, // 横ライン移動用のiを40で初期化 ++y<h // yが40行以内か確認 ? c+='\n' // 40行以内なので改行を追加 : ( b[a++]=c, // 文字列を配列に格納し // 対象配列を次に移行 c=y='' // c を空文字で初期化 // y を空文字(0)で初期化 ) ); return b
Copyright © ITmedia, Inc. All Rights Reserved.