CodeIQでお正月チャレンジをしていた時に遭遇した問題を解決するために、いろいろと試行錯誤したことがありました。
ある条件下で数値を作成しなければいけないという問題に直面したときのことです。
条件としては、以下のとおりになっていました。
入力欄の文字数:100文字以内
禁止文字:1 2 3 4 5 6 7 8 9 0 , + % ? : this eval function Function Array join split repeat ‘ “
この条件下で数字の1を作成した結果は以下のとおりになりました。
1
初期案 (11文字)
[].push([])
数字の1を作成するためにまず思いついたのがこれです。
Arrayオブジェクトのpushは返り値が要素数になることを利用して、空配列に空配列を追加して1を得ました。
まだまだこれは短縮できそうということで、考えを練っていたら次にこのようなものが思い浮かびました。
改善案 (6文字)
~~!![]
6文字まで短縮することができました。
このコードは主に3つの要素から成り立っています。
[]
空配列です。
ここでは、実態のあるオブジェクトがほしいだけなので、{}でも大丈夫です。
!
否定演算子です。
今回は、配列として実態があるものに対して行っているので、![]ではfalseが返ってきます。
!![]とすることで、trueを得ることができます。
~
ビット反転演算子です。
!![]で返ってきたtrueをビット反転することによって、数値として認識させます。
~!![]は、すなわち~trueであり、すなわち~1なので、-2を返します。
~~!![]とすることで、ビット反転を打ち消し、1を返させることができます。
6文字ではまだまだ字数が多すぎると思い、ふと閃いたものが以下になります。
最終案 (4文字)
-~[]
Arrayオブジェクトに対して、直接ビット演算をしてしまいます。
要素数ゼロのArrayオブジェクトは数値として扱った場合に、ゼロとなるのでそれを用いてゼロをビット反転してしまいます。
補数により0は-1となり、正負を反転させるために-(マイナス)を加えて1としました。
記号を使った1を生成する最短コードなんじゃないでしょうか。
おまけ
2と3も作ってみました。
2
初期案 (10文字)
-~[]<<-~[]
上で作成した1を用いてビットシフトしています。
1を倍にすることで2になるという単純なものです。
ここで、1を作成した時のことを考えていたら、もっと単純で短いものがありました。
最終案 (6文字)
-~!![]
先ほどの1を作成する改善案を元に、符号を反転させただけのものです。
最短コードなんじゃないでしょうか。
3
初期案 (11文字)
-~!![]|-~[]
1と2でビットの論理和を計算して3とします。
最終案 (8文字)
-~-~!![]
2の最終案を元に、ビット反転して-3にし、それを-(マイナス)で符号反転して3を作りました。
これら2と3を作った方法を元にすれば4,5,6..も同様に作れてしまいます。
この方法をもとにCodeIQのお正月ダンジョンLv.3に挑んだコードがトップ画像になります。
以上、豆知識的なメモでした。