ニュース
美人サンタよりコードがお好き?:JavaScriptエンジニアの変態プレイが炸裂(2/2 ページ)
12月20日、CodeIQと@ITは合同で「リアル版:サンタのためのコードゴルフコンペ&クリパ」を開催した。クリスマスを目前に、エンジニアが集う!
ランキング上位5位のコード解説
上位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文字)
1位:tompng氏のコード(194文字)
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
1位:柳井氏による解説付きコード
/*
* アニメの制御
*/
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
2位:hogeover30氏のコード(202文字)
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
2位:柳井氏による解説付きコード
/*
* アニメの制御
*/
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
3位:colun氏のコード(210文字)
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
3位:柳井氏による解説付きコード
/*
* 全ての計算を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
4位:mtym氏のコード(214文字)
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
4位:柳井氏による解説付きコード
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
5位:hotpepsi氏のコード(215文字)
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
5位:柳井氏による解説付きコード
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.