まず、FizzBuzz問題とは。
1~100までの数字で3で割り切れる時は「Fizz」、5で割り切れる時は「Buzz」、両者で割り切れる時は「FizzBuzz」と出力する。
たったこれだけです。
せんだ!みつお!なはなは!とか3の倍数と3が付くときのアレみたいな感じです。
「2分以内で書け」や「1行で書け」や「○○バイト以内で書け」や「%を使うな」などの条件を付ける場合もありますが、これをPHPで書いたらどうなるかと思いましてやってみました。
<?php for ( $i = 1; $i <= 100; $i++ ) { if ( $i % 15 == 0 ) { print 'FizzBuzz'; } else if ( $i % 3 == 0 ) { print 'Fizz'; } else if ( $i % 5 == 0 ) { print 'Buzz'; } else { print $i; } print "n"; } // <プークスクス ?>
ハッ 嘲笑なんか気にしなければこれで良いんですよ!!
では「1行で書く」ってのを考えると、これを改行入れなければいいじゃん?ってなる訳で「どれだけ短く書けるか」ってのに挑戦しました。
まず、 if { } else if { } … この辺が長いので三項演算子を使うことに。
あまりひねらない書き方ですが、それぞれを三項演算子に置き換え、1行で書いた方が短いので for文の {} や余計なスペース、最後のセミコロンも省略します。
<?php for($i=1;$i<=100;$i++)print($i%15?($i%3?($i%5?$i:'Buzz'):'Fizz'):'FizzBuzz')."n"?>
何かそれっぽくなってきた!!
この時点で89バイト。
更に短くするにはと思いついたのが
for ( $i = 1; $i <= 100; $i++ )
の部分です。ここを
for ( $i = 1; $i < 101; $i++ )
にしたら1文字減りますね。
何かで見た事あった次の書き方でも動きます。
for ( $i = 0; ++$i < 101; )
これでいい気もしますが101ってのがどうも気に入らないので1減らして
for ( $i = 0; $i++ < 100; )
この書き方の方が見やすいかもです。文字数変わりませんし。
[php title="1行でFizzBuzz (87バイト)"]<?php for($i=0;$i++<100;)print($i%15?($i%5?($i%3?$i:"Fizz"):"Buzz"):"FizzBuzz")."n";?>[/php]
これをTwitterに書いた直後に print を echo に変えるって気付きました。
echo は print と違って ,(コンマ) で区切って出力するって方法があります。ついでに最初の <?php を <? でもいいっての思い出して
[php title="79bytes"]<?for($i=0;$i++<100;)echo$i%15?($i%3?($i%5?$i:'Buzz'):'Fizz'):'FizzBuzz',"n"?>[/php]
ギリギリ80バイトの壁を越えました。
もうこの辺からparse error覚悟で動けばいいや!ってスペースどこ削って大丈夫か体当たり的になってます。
echo$i なんか続けて書いていいのかよ!とツッコミ入れたい。
ただ、この書き方 15の時がどうにか出来そうな気がします。
「3で割り切れる」=「FizzもしくはFizzBuzzなのでFizzだけ出力」、「5で割り切れない」=「数字だけ」ということを頭に入れて15という数字を消すと
[php gutter="0" classname="inline"]( $i % 3 ( $ % 5 ? $i : '' ) : 'Fizz' ), ( !$i % 5 ? 'Buzz' : '' )[/php]
こう書くこともできます。
いや ( !$i%5 ? 'Buzz' : '' ) は逆に出来るじゃないか… ということで ( $i%5 ? '' : 'Buzz' )
それでPHPの定数で思い出した事が1つ。
定義してない定数(主にtypo)はそのまま定数名が出力されたことありませんか?
このPHPのいい加減な何でも文字列を利用して
「Fizz, Buzzという定数のつもりだけど実は定義してなかったからそのまま出力してね!」作戦。
[php title="FizzBuzz 67bytes "]<?for($i=0;$i++<100;)echo$i%3?($i%5?$i:''):Fizz,$i%5?'':Buzz,"n"?>[/php]
ここで67バイトまで縮めることが出来ました。
ギブアップ。
翌日、forじゃなくても良いんじゃね?て思いwhileに変えると結構短く出来ました。
[php title="FizzBuzz 63bytes"]<?while($i++<100)echo$i%3?($i%5?$i:''):Fizz,$i%5?'':Buzz,"n"?>[/php]
ここで、Twitterにpostしたところ救世主 @daira4000 さんに「三項演算子の()を外して、nを直接LFにする」と教えて頂きましてさらに短くなり、最後の ?> は ; に変えても大丈夫ということでついに60バイトの壁突破。
<?while($i++<100)echo$i%3?$i%5?$i:'':Fizz,$i%5?'':Buzz," ";
ΩΩΩ< ()は消しても大丈夫なのか-!!!
さらに考えたけど順番が変わった程度でした。
<?while($i++<100)echo$i%3?'':Fizz,$i%5?$i%3?$i:'':Buzz," ";
PHPでは最短56バイトで書けるらしいんですがそんな脳みそは持ち合わせておりません。おわり。