レベル4:剰余を使わずに処理を行う
レベル4では、新たに「%」が禁止されて、剰余が利用できなくなります。というわけで剰余を使わずに、3の倍数、5の倍数を判定しなければなりません。なかなか大変です。さすが、ダンジョンの最奥です。というわけで、その解き方を示していきます。
配列を使って文字列を結合
それでは、まずは最も簡単な方法です。文字列を、配列を利用して結合して、答えの一覧を作成します。これは、シンプルなコードなので、実際に見てもらった方が分かりやすいでしょう。というわけで、以下をご覧ください。
Array(8).join("300102100120100")[i]
Array(8).join(300102100120100)[i]
要素数8の「空の配列」を作り、「"300102100120100"」を間に挟んで結合しています。なかなかうまいやり方です。
小数点の数で判定1 split
ある値で割った場合、小数点があれば割り切れておらず、小数点がなければ割り切れています。そこで、小数点の数を数えることで、判定を行います。処理としては、文字列として結合して、「.」の位置で「split」を使って分割します。
4-(""+i/3+i/5+i/5).split(".").length
小数点の数で判定2 正規表現
小数点が存在するかどうかは、正規表現でも判定できます。というわけで、その方法を示します。
3-/\./.test(i/3)-/\./.test(i/5)*2
number.toStringを使う
除算の代わりに、進数変換を利用します。「number.toString([radix])」で、「radix」で指定した進数の文字列に変換できます。この仕様を使い「(14).toString(3)」とすれば「"112"」が得られます。「(15).toString(3)」ならば「"120"」が得られます。
そこで、「"120".slice(-1)」とすれば「"0"」という末尾の文字列が得られます。3進数で末尾の値が「0」の場合は、3で割り切れます。この方法は、3や5で剰余を求める計算の代わりに使えます。以下、コードです。
"322"[i.toString(3).slice(-1)]-"02222"[i.toString(5).slice(-1)]
15進数にしない理由は、文字列を数値に戻す場合に、「parseInt("文字列", 桁数)」と、「,」を使わないといけないからです。「,」は禁止文字なので、そのまま数値として利用できる3や5を使って計算しています。
倍数を引く
以降は、計算的手法で答えを求めていきます。まずは、除算後、整数化して倍数を作成します。「i-parseInt(i/3)*3」のように計算することで「0,1,2,0,1,2,…」という剰余と同じ値が取れます。それでは、コードを見ていきましょう。
"3001021001201000"[i-parseInt(i/15)*15]
シンプルな方法で剰余の代わりが得られます。
割り切れるか確認
「parseInt」と「Boolean」を使い、割り切れるかを確認します。「Boolean(i/3-parseInt(i/3)」で、割り切れるときは「0」となり「false」が得られます。それ以外では少数点以下が発生して「0以外」になり「true」になります。それでは、コードを見ていきましょう。
3-Boolean(i/3-parseInt(i/3))-Boolean(i/5-parseInt(i/5))*2
割り切れる位置を検出
「parseInt」を使い、割り切れる位置を検出します。「parseInt(i/3)-parseInt((i-1)/3)」で、割り切れる場合のみ「1」になります。それ以外は「0」になります。以下、コードです。
parseInt(i/3)-parseInt((i-1)/3)+(parseInt(i/5)-parseInt((i-1)/5))*2
おわりに
記事は以上です。同じ処理を行うのにも、さまざまな方法があると気付いたのではないでしょうか。普段、プログラムを書く上では、こんなトリッキーなコードを書くことは、まずないと思います。しかし、たまにパズル的に遊ぶ上では、こういったコードを考えるのも楽しいです。また、今まで知らなかったプログラミング言語の仕様に気づくきっかけにもなります。
今回は「FizzBuzz問題」を解決する、「FizzBuzzダンジョン」でしたが、「CodeIQ」では同系統の問題で「素数ダンジョン」も出題しています。「10~100」の間の素数を、1行で判定するという問題です。短く書いた場合は、20文字で書けることが確認されています。こういった遊びは、かたくなった頭をときほぐすのによいです。やわらかい頭になり、プログラムを書いてみてください。
