はじめに
よくこんなニッチなところにたどり着きましたね(困惑)
どうも、Sei2423です。(初めての自己紹介)
JavaScriptで数字禁止FizzBuzzをしているコードが ↓ これ ↓ くらいしか見つからなかったのでまとめようと思い立ちました。
Javascript 97 chars - no numbers at all
Numbers ? Who needs number when you have Javascript !
a=b=!![]+![],a--,c=b+b;while(++a)e=!(a%(c+c+b)),alert(!(a%(c+b))?e?"FizzBuzz":"Fizz":e?"Buzz":a);
どうやら1~100ではなくずっと続きそうですね
そもそもcodegolfとしてやってる人見かけたことないけど今回書いたコードは多分FizzBuzz in JavaScript without using digitsでは最短になっていると思われる
数字縛り
突然ですが質問です。
Q. 数字禁止縛りというものを知っていますか?
A. その名の通り、コード内に0~9が含まれていてはいけないという縛りです
英語圏でno numbersとかno digits challengeとかdigits restrictedとかwithout using numbersとか書かれてる奴ですね
情報一覧
わざわざこんなのを見に来る人に普通のショートコードテクニック等は必要ないという前提で始めます!
一般的なテクニックを知りたい方へ ↓
JSFUCKの情報が知りたい方へ ↓
あとは-~とかが分かっていれば多分大丈夫!!
数字禁止の特徴
- JSFUCKと違って英語が使える
-
""や{}が使える - 算術演算子かbit演算子が使える
- evalを使わないのでいいので安全性が担保される!!!!(絶対にそこではない)
真偽値とか
・ True, False
!""; // true
![]; // false {}も可
JSFUCKとは違い""が使えるためtrue、falseがそれぞれ1文字短く表せる。
Truthy Falsy
[]; // Truthy {}も可
""; // Falsy
実はwhile(true)はwhile([])に代替可能である。
・ undefined
"".a; // undefined []も可
数字編
・ 0, 1, -1
+""; // 0 []も可
+!""; // 1
-~""; // 1 [], {}も可
~""; // -1 [], {}も可
※-1は1より短いため次のような場面では-1を反転する方が有効な場面がある。
・ 99, 100, 101
~(~""+"e"+-~!""); // 99
-(~""+"e"+-~!""); // 100
-~""+"e"+-~!""; // '1e2'
-~-(~""+"e"+-~!""); // 101
+!""+"e"+-~!""|!""; // 101
-~(+!""+"e"+-~!""); // 101
100では上で言った通り、+(-!""...)ではなく-(~""...)となっている
条件編
定数編
次の式のexprの式を変えることで条件を変えるものとします。
function expr(i) {
return /* 式 */;
}
for(let i = []; expr(++i);) { // i = 1 ~ n;
console.log(`\u001b[35m${i}\u001b[0m: ${expr(i)}`); //i: expr(i)
}
・ 99, 100, 101
~-~-~-(i>>-~i); // (0|1) ~ 99
~-~-~-(i>>i); // (0|1) ~ 100
~-~-~-(i>>~-i); // (0|1) ~ 101
実践
じゃあ、ここからは上の知識を使ったり使わなかったりしながらいろいろな問題を解いてみましょう
私より短いコードを書けた場合はコメントまでご連絡ください。IDと一緒に追記として記載いたします。
FizzBuzz
for(f=~(i=''),b=--f+--f;i++<b*b*~b;console.log(i%b?x||i:x+'Buzz'))x=i%f?'':'Fizz'
81byte
解説
まず、有名なJavaScriptのFizzBuzz最短コードを用意します
for(i=0;++i<101;console.log(i%5?x||i:x+'Buzz'))x=i%3?'':'Fizz'
多分これで大体わかります()
ということで私のコードを展開して見て見ましょう
for(
f=~(i=''), ...➀
b=--f+--f; ...➁
i++<b*b*~b; ...➂
console.log(i%b?x||i:x+'Buzz')
)x=i%f?'':'Fizz'
➀
i=''の式としての値は代入結果になるので''
''は数値化すると0なのでfの値~''は-1
i = '' // ''
f = ~'' // -1
➁
がんばってf=-3, b=-5に調整
--f1つ目は-2、--f2つ目は-3
bは-2 + -3で-5
b = --f + --f // b = -5, f = -3
➂
左辺はi
右辺は-5 * -5 * ~-5 = 25 * 4 = 100
~-~-~-(i>>i)より短かったためこちらを採用
++i<101とi++<100は大体同義
i++ < b * b * ~b; // i < 100
あとは元のコードと一緒です
あとがき
実は数字縛りって言う縛りの欠陥なのですが、
そもそもコードにおいて1, 0, -1か100以外の数字を使うことがそれほどなく あってもforかカウンターとかの初期値がほとんどで、
それなのに短縮が難しくなるのは大きい数字を作るときくらいしかなく、
そうなると
「FizzBuzzくらいしかやることがない」
という事でした。
まあまた何かがあったら追記します
終わり!!!