はじめに
いつもは「マンガで分かるプログラミング用語辞典」を描いている、クロノス・クラウンの柳井です。JavaScript大好きで、「マンガで分かる JavaScriptプログラミング講座」を書いたりもしています。そして最近は「CodeIQ」というサイトで、さまざまなプログラミングの問題を出題しています。
今回は、その「CodeIQ」で出題して人気のあった「FizzBuzzダンジョン」という問題のさまざまな解法を紹介しようと思います。私自身も勉強になり、コードを読むことを楽しめましたので、プログラマーの方々はきっと楽しめると思います。
「FizzBuzz問題」とは、3の倍数のときは「"fizz"
」、5の倍数のときは「"buzz"
」、共通の倍数のときは「"fizzbuzz"
」、その他は「数値」を戻すという単純な処理です。ループ処理と分岐処理を理解していればコードを書けます。
「FizzBuzzダンジョン」は、その「FizzBuzz問題」に「レベル」を設けた問題です。どんな問題かというと、FizzBuzzの1行穴埋め問題なのですが、レベルが上がるごとに、使える予約語や演算子、関数やオブジェクトが制限されていきます。さらに、使える文字数の上限も設定されます。
以下に、問題の穴埋めコードとともに、どのような制限が課されるかを紹介します。
function yourCode() { var arr = []; for (var i = 1; i <= 100; i ++) { arr.push([i, "fizz", "buzz", "fizzbuzz"][/*★穴埋め位置★*/]); } return arr; }
Lv | テーマ | 文字数 | 禁止文字 |
1 | 条件分岐を1行で書く | 100以内 | なし |
2 | 条件分岐を禁止 | 30以内 |
? : & | , $ eval function Function if switch for while return |
3 | 使える演算子を制限 | 40以内 |
? : & | , $ eval function Function if switch for while return ! ^ ~ < > = Math |
4 | 剰余を使わずに判定 | 70以内 |
? : & | , $ eval function Function if switch for while return ! ^ ~ < > = Math % |
簡単なプレイグラウンドも用意していますので、パズルが好きな人は、自分ならどんなコードを書くのか挑戦してから解答例を見てください。また、プレイグラウンドのコードも用意しています。本ページの上部からダウンロード可能です。
それでは、それぞれのレベルで、どういったコードが登場してくるのか紹介していきます。
対象読者
以下の読者を対象にしています。
- JavaScriptでプログラムを書ける人。
- JavaScriptでプログラムを書けなくても、他の言語を使っており基本的なプログラミングの知識がある人。
必要な環境
「Google Chrome」や「Mozilla Firefox」といったブラウザがあればよいです。特になくても、頭の中でコードを考えて、解答を確認することもできます。
レベル1:条件分岐を1行で書くには?
最初の課題は、「普段は複数行で書く条件分岐を、1行で書く」というものです。禁止文字はありません。文字数制限は100文字ですが、ほとんど制限なしと変わりありません。うまく1行で条件分岐を書くことができればクリアーです。解法はいくつかありますので、一つ一つ見ていきましょう。
「function」を使い、匿名関数で処理を分岐
JavaScriptには「function
」という関数オブジェクトがあります。そして、「(function(arg) {})(arg)
」と書くことで、匿名関数を作成して、その場で実行できます。また「;
」を使い、複数の処理を1行で書くことも可能です。
ではまず、この「function
」を使った処理を複数行で書き、その後1行にまとめましょう。
(function(n) { if (n % 15 == 0) return 3; if (n % 3 == 0) return 1; if (n % 5 == 0) return 2; return 0; })(i)
(function(n){if(n%15==0)return 3;if(n%3==0)return 1;if(n%5==0)return 2;return 0;})(i)
この方法は、普段のプログラムの書き方を大きく変えずに処理を書けるというメリットがあります。しかし、かなりの文字数を使います。実際、不要なスペースを除去しても、85文字もかかっています。制限文字数のある問題では、かなりひやひや物です。というわけで、もう少し短い方法を、次は試してみましょう。
「eval」を使い、条件分岐
JavaScriptには「eval
」という、文字列を解釈してコードとして実行する関数があります。「eval("実行コード")
」のように書いて利用します。この「eval
」を使うことでも、複数の処理を1行で書けます。
eval("if(i%15==0){3}else if(i%3==0){1}else if(i%5==0){2}else{0}")
if (i % 3 == 15) { 3 } else if (i % 3 == 0) { 1 } else if (i % 5 == 0) { 2 } else { 0 }
上記のように展開してみると分かりますが、「eval
」の結果は「return
」を使わずに書きます。例えば「eval("3")
」ならば、「eval
」の戻り値は「3」になります。
さて、「function
」よりは短くなりましたが、まだまだ長いです。それに、「1行で書く」ことを求められているのに、本来「複数行で書く」方法で書いています。というわけで次は、元々「1行で書く」ために用意された方法で書いてみます。