美人サンタよりコードがお好き?:JavaScriptエンジニアの変態プレイが炸裂(1/2 ページ)
12月20日、CodeIQと@ITは合同で「リアル版:サンタのためのコードゴルフコンペ&クリパ」を開催した。クリスマスを目前に、エンジニアが集う!
12月20日、ITエンジニアのための実務スキル評価サービス「CodeIQ」と@ITは合同で「リアル版:サンタのためのコードゴルフコンペ&クリパ」を開催した。イベントは、CodeIQであらかじめ出題されていた「サンタのためのコードゴルフ」との連動企画。クリスマスを目前に、エンジニアが集うガチイベントの模様をレポートする。
「コードゴルフ」とは、ゴルフがカップインまでの打数を競うように、プログラムの文字数を削り、なるべく短くプログラムを書く遊びのことをいう。スポーツのゴルフでは、打数が少なければ少ないほど高得点が得られるが、コードゴルフでは、ソースコードの文字数が少なければ少ないほど良いとされる。従って、最短コードを書いた人が勝者となる。イベントでは、「サンタのためのコードゴルフ」問題の出題者であるクロノス・クラウンの柳井政和氏によるコードレビューが行われた。
今回出題された問題は、アスキーアニメ。4枚のアスキーアートでアニメーションさせる問題である。テーマは、「配列」と「ループ処理」だ。
問題とポイント
というわけで、サンタ見習いの智美ちゃんが振られた仕事を、こっそりと手伝ってあげて下さい。サンタ見習いの智美ちゃんのコードは、下記に掲載しています。JavaScriptを使って、このコードゴルフにチャレンジしてください。
以下の関数yourCode()に書かれているコードと同じ文字列を返す処理を、なるべく短い文字数で書いてください。短いほど評価が高いです。ただし、関数外から直接答えを取ったり、通信で答えを得るなどした場合は、ランキング外になってしまいますので、行わないでください。
function yourCode() {
var arrayMax = 4;
var resArray = new Array(arrayMax);
// アニメ用の4枚のアスキーアートを返す
var w = 80;
var h = 40;
var illumination = 160;
// キャンバス用配列を初期化
var canvasArray = new Array(4);
for (var a = 0; a < arrayMax; a ++) {
canvasArray[a] = new Array(h);
for (var y = 0; y < h; y ++) {
canvasArray[a][y] = new Array(w);
}
}
// ツリーを作成
for (var a = 0; a < arrayMax; a ++) {
for (var y = 0; y < h; y ++) {
for (var x = 0; x < w; x ++) {
canvasArray[a][y][x] = "_";
var treeTop = Math.floor(y / 8) * 4;
var treeW = Math.floor(y / 8 + 1) * 8;
if (Math.abs(x - w / 2) < (y - treeTop) % treeW) {
canvasArray[a][y][x] = "%";
}
}
}
}
// イルミネーションを作成
for (var a = 0; a < arrayMax; a ++) {
for (var i = 0; i < illumination; i ++) {
var r = (a + i) * i * 49999 + 59999 & 0xFFFF;
var x = 1 + r % (w - 2);
var y = 1 + r % (h - 2);
canvasArray[a][y][x] = "*";
canvasArray[a][y][x - 1] = "-";
canvasArray[a][y][x + 1] = "-";
canvasArray[a][y - 1][x] = "|";
canvasArray[a][y + 1][x] = "|";
}
}
// 文字列化
for (var a = 0; a < arrayMax; a ++) {
var arrayY = new Array(h);
for (var y = 0; y < h; y ++) {
arrayY[y] = canvasArray[a][y].join("");
}
resArray[a] = arrayY.join("\n");
}
// 戻り値を戻して終了
return resArray;
*** 一部省略されたコンテンツがあります。PC版でご覧ください。 ***
この基のコードには、あらかじめ冗長性を設けているという。短く書けるコードを、わざと長く書いているのだ。「大きなトラップが3つある」と柳井氏はいう。
- 不要な処理の削除
- ループの統合
- 多数の配列
1.不要な処理の削除
最初のトラップは、「不要な処理の削除」である。例えば、
// キャンバス用配列を初期化
var canvasArray = new Array(4);
for (var a = 0; a < arrayMax; a ++) {
canvasArray[a] = new Array(h);
for (var y = 0; y < h; y ++) {
canvasArray[a][y] = new Array(w);
}
}
このブロックは丸ごと削除できる。[x][y]の配列ではなく、[x + w * y]の配列にすれば、そもそも初期化は不要になるためだ。
2.ループの統合
第2のトラップは、「ループの統合」。基のコードは、ループの統合が可能なように、本来ランダムに行うべき処理を一意に決まるコードで書いている。
var r = (a + i) * i * 49999 + 59999 & 0xFFFF;
「勘の鋭い人は、線形合同法の変形だと気付くだろう」と柳井氏は解説を続ける。線形合同法とは、擬似乱数列を生成するアルゴリズムの一つである。
例えば、Visual BasicのRnd関数は次のような構造になっている。
static long x=327680;
float Rnd(void)
{
x=x*16598013+12820163&16777215;
return x*(1.0/16777216.0);
}
今回の問題では、この「線形合同法もどき」を利用し、星の表示場所を散らしている。従って、次の部分は丸ごと短くできる。
var r = (a + i) * i * 49999 + 59999 & 0xFFFF;
ここは、どの順番で計算しても可能であるため、ソースコードの中に複雑に埋め込むことができる。あえてここを正しい乱数にしなかったのは、「計算順番は問わないので好きに計算する位置を変えてください」という出題者からのサインで問題を解くヒントになる。何度も登場するループは、乱数の処理順にとらわれずに統合できるため、柳井氏は「統合してね」というメッセージを問題の中に隠したそうだ。問題を見た瞬間にここまで分かるかどうかが、この問題の大きなハードルである。
3.多数の配列
第3のハードルは、「多数の配列」だ。問題のコードでは、ネストした配列が出てくる。アスキーアートの4枚の配列は、まず木を書いて、その後に星を書いている。すなわち、4枚の同じ絵のレイヤーを作り、その後個別の絵を描くという処理だ。「『この処理をどこまで統合できるか』というところで、文字数の差が付くようにしている」と柳井氏は語る。
変態コード現る!
今回のイベントには、1人の勇者がいた。2バイト文字も「1文字」として扱ったコードをとくとご覧あれ。
for(var i=0,C,Z="";C="景爨癡爠刽孝ⱡ㴴ⱷ㴸ㄻ愭ⴻ剛慝 㵃潩渨∢⤩筃㵛崻景爨椽㌲㌹ⱚ㴲?椭ⴻ⥃孩崽繩╷㽩╷㸴〭娦 椥眼㐰⭚㼢┢㨢弢㨨娫㵾椯眥㠿ⴱ㨳Ⱒ屮∩㭦潲⠻娼ㄶ〻䍛 椭睝㵃孩⭷崽≼∩椽⡡⭚⤪娫⬪㐹㤹㤭㔵㌷☶㔵㌵Ⱪ㵩┳㠪眫椥 㜸眬䍛楝㴢⨢ⱃ孩ⴱ崽䍛椫ㅝ㴢ⴢ絒".charCodeAt(i++);) Z+=String.fromCharCode(C>>8&255,C&25 5);return eval(Z)
for(
var i=0,C,Z="";
C="景爨癡爠刽孝ⱡ㴴ⱷ㴸ㄻ愭ⴻ剛慝㵃潩渨∢⤩筃㵛崻景爨椽㌲㌹ⱚ㴲?椭ⴻ⥃孩崽繩╷㽩╷㸴〭娦椥眼㐰⭚㼢┢㨢弢㨨娫㵾椯眥㠿ⴱ㨳Ⱒ屮∩㭦潲⠻娼ㄶ〻䍛椭睝㵃孩⭷崽≼∩椽⡡⭚⤪娫⬪㐹㤹㤭㔵㌷☶㔵㌵Ⱪ㵩┳㠪眫椥㜸眬䍛楝㴢⨢ⱃ孩ⴱ崽䍛椫ㅝ㴢ⴢ絒"
.charCodeAt(i++);
)
Z+=String.fromCharCode(C>>8&255,C&255);
return eval(Z)
for(var R=[],a=4,w=81;a--;R[a]=C.join("")){C=[];fo
r(i=3239,Z=23;i--;)C[i]=~i%w?i%w>40-Z&i%w<40+Z?"%"
:"_":(Z+=~i/w%8?-1:3,"\n");for(;Z<160;C[i-w]=C[i+w
]="|")i=(a+Z)*Z++*49999-5537&65535,i=i%38*w+i%78-~
w,C[i]="*",C[i-1]=C[i+1]="-"}R
for(
var R=[],
a=4,
w=81;
a--;
R[a]=C.join("")
){
C=[];
for(
i=3239,
Z=23;
i--;
)
C[i]=
~i%w
?
i%w>40-Z
&
i%w<40+Z
?
"%"
:
"_"
:
(
Z+=~i/w%8
?
-1
:
3,
"\n"
);
for(
;
Z<160;
C[i-w]=C[i+w]="|"
)
i=(a+Z)*Z++*49999-5537&65535,
i=i%38*w+i%78-~w,
C[i]="*",
C[i-1]=C[i+1]="-"
}
R
柳井氏によるコードレビューの後、チーム対抗戦「ミニ・コードゴルフ コンペ」が行われた。まるで当たり前のようにサンタの帽子をかぶって、コードゴルフに打ち込む姿は貴重な光景だった。
コンペが終わると、クリスマスパーティーに突入。しかし、集まったエンジニアたちは、いかにコードを短く書くかに夢中だった。ヘソ出しサンタがすぐそこにいるというのに、このありさまだ。
こうして、「リアル版:サンタのためのコードゴルフコンペ&クリパ」は幕を閉じた。JavaScriptエンジニアは、ヘソ出しサンタよりコードが好きだった。
Copyright © ITmedia, Inc. All Rights Reserved.




