LoginSignup
30
29

More than 5 years have passed since last update.

PHPでFizzBuzz最短56バイト

Last updated at Posted at 2014-05-17

http://golf.shinh.org/p.rb?FizzBuzz#PHP
PHPのFizzBuzzで最短56バイトを投稿、9位になりました。(NurseAngel = rana_kualu)

以下を読み進める前に、とりあえず前提知識
・php変態文法最速マスター
 http://d.hatena.ne.jp/milieu/20100203
・可変変数
 http://www.php.net/manual/ja/language.variables.variable.php
・文字列のビット演算
 http://perl-users.jp/articles/advent-calendar/2010/sym/2
を見といてください。

PHPでは現状56バイトが最高記録ですが、何故か何処にも公開されていません。

公開されているものでは59バイトが最短のようです。
http://d.hatena.ne.jp/milieu/20100204/1265305089
http://oflow.me/archives/110
http://d.hatena.ne.jp/ts_asano/20130320/1363791538
よく見たら最後のは改行ではなくスペースになってるので間違ってるな。

私はずっと58バイトで詰まっていたのですが、このたびようやく56バイトに成功しました。

まず公開されている59バイトのから始めてみます。

60バイトまでは、普通に三項演算子とかをいじっていれば減らせます。
そこから"\n"を直接LFにすると1バイト減って59バイトになります。
そこからちょっとだけいじってみます。

<?for(;$i++<100;)echo$i%3?$i%5?$i:"":Fizz,$i%5?"":Buzz,~ ;

~の後ろの空白は普通の文字ではないのでたぶん正しくアップできてませんが、chr(245)です。
この文字を~でビット反転するとASCIIコード10、つまりLFになるので『~ 』は『"\n"』と同じ意味です。
直接LFを書くよりさらに1バイト減らすことができ、該当部分を差し替えるだけで58バイトになります。

しかしこっちはこれで行き止まりです。
56バイトはこんなかんじ。

<?while($i++<100)echo$i%3?!$$i=$i:Fizz,$i%5?$$i:Buzz,~ ;
<?for(;$i++<100;)echo$i%3?!$$i=$i:Fizz,$i%5?$$i:Buzz,~ ;

とりあえずコードをわかりやすく分解。

<?php
    while($i++<100){
        // $iが3の倍数であれば「Fizz」を表示、倍数でなければ「!$$i=$i」を表示
        echo $i%3 ? !$$i=$i : 'Fizz';
        // $iが5の倍数であれば「Buzz」を表示、倍数でなければ「$$i」を表示
        echo $i%5 ? $$i : 'Buzz';
        // 改行
        echo ~ ;
    }

!$$i=$i」ってなんだよ。

まず1行目。
3の倍数だった場合は単にFizzを表示して終わりです。
3の倍数でなかった場合、$$i=$iで、$$i$iを代入しています。
例として$i=4だった場合、$$i = ${4} = 4、つまり${4}という変数に4が代入されます。
これはただの代入なので、「$$i=$i」全体の値は$iになります。
ところで数値を!するとfalseになります。
結果として「!$$i=$i」全体の値はfalseとなり、echoでは何も表示されません。

1行目のまとめは、
$iが3の倍数であれば「Fizz」を表示する。
$iが3の倍数でなければ${$i}$iを代入する。何も表示しない。
です。

次に2行目ですが、
$iが5の倍数であれば「Buzz」を表示する。
$iが5の倍数でなければ${$i}を表示する。
です。

5の倍数であれば単にBuzzを表示して終了なので問題ありません。
5の倍数ではない時を見てみましょう。

${$i}は、$iが3の倍数でないときは1行目によって$iが代入されているので、結果として$iが表示されます。
$iが3の倍数だった場合、${$i}は未定義なのでNULLとなり、結果としてなにも表示されません。
例として$i=4の場合、1行目により$$i = ${4} = 4が代入されていたので4となります。
$i=6だった場合、$$i = ${6}は何も代入されていないのでNULLです。

以上をまとめると、
$iが15の倍数である場合、1行目でFizzが表示され、2行目でBuzzが表示される
$iが3の倍数であり5の倍数ではない場合、1行目でFizzが表示され、2行目で$$i=NULLなので何も表示されない
$iが3の倍数ではなく5の倍数である場合、1行目で$$i=$iが実行され、2行目でBuzzが表示される
$iが3の倍数でも5の倍数でもない場合、1行目で$$i=$iが実行され、2行目で$$i=$iが表示される

となりFizzBuzzの定義を満たしました。
めでたし。

ということで次は55バイトなわけですが、さすがに世界中誰も成功してないから無理かな?

30
29
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
29