更新履歴

    +
  1. + : 公開 +
  2. +
  3. + : 小さな文言の修正・変更 +
  4. +
+
+
+

記事の構成について

+

+ この記事は、普通の fizzbuzz を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、このページにソースコードがあるので、そちらを先に見てほしい。 +

+
+ +
+

レギュレーション

+

+ PHP で、次のような制約の下に fizzbuzz を書いた。 +

+ +
    +
  • +

    + 1行あたりの文字数は2文字までに収めること (ただし<?phpタグは除く) +

    + +
      +
    • +

      + 厳密な定義:<?phpタグ以降のソースコードが、2 byte ごとに ラインフィード (LF) で区切られること +

      +
    • +
    +
  • -
  • - : 公開 -
  • +
  • +

    + スペースやタブを使用しないこと +

    +
  • -
  • - : 小さな文言の修正・変更 -
  • +
  • +

    + ループのアンロールをしないこと +

    + +
      +
    • +

      + 100 回ループの代わりに 100 回コードをコピペ、というのは禁止 +

      +
    • +
    +
  • - +
  • +

    + PHP 7.4〜8.1 で動作すること +

    +
  • + +
  • +

    + 実行時に Notice や Warning が出ないこと +

    +
  • + +
  • +

    + 標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと) +

    +
  • +
+ +

+ 備考: PHP にはshort_open_tagというオプションがあり、これを有効にするとファイル冒頭の<?phpの代わりに<?を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト off になっている環境が多いようなので、今回は使わないことにした。 +

-
-

- - 記事の構成について - -

-
-
-

この記事は、普通の fizzbuzz -を徐々に変形して最終形にしていく、という構成で書かれている。最終形を見てどのような仕組みで動いているのか解読してから解説を読みたい、というかたがいれば、 -このページ -にソースコードがあるので、そちらを先に見てほしい。

-
-
-
-
-

- - レギュレーション - -

-
-
-

PHP で、次のような制約の下に fizzbuzz を書いた。

-
-
-
    -
  • -

    1行あたりの文字数は2文字までに収めること (ただし <?php タグは除く)

    -
    -
      -
    • -

      厳密な定義: <?php タグ以降のソースコードが、2 byte ごとに -ラインフィード (LF) で区切られること

      -
    • -
    -
    -
  • -
  • -

    スペースやタブを使用しないこと

    -
  • -
  • -

    ループのアンロールをしないこと

    -
    -
      -
    • -

      100 回ループの代わりに 100 回コードをコピペ、というのは禁止

      -
    • -
    -
    -
  • -
  • -

    PHP 7.4〜8.1 で動作すること

    -
  • -
  • -

    実行時に Notice や Warning が出ないこと

    -
  • -
  • -

    標準的なインストール構成の PHP で実現できること -(デフォルトで有効になっていない拡張等を使わないこと)

    -
  • -
-
-
-

備考: PHP には short_open_tag -というオプションがあり、これを有効にするとファイル冒頭の <?php -の代わりに <? -を使うことができ、文字どおり1行2文字で書ける。ただ、このオプションはデフォルト -off になっている環境が多いようなので、今回は使わないことにした。

-
-
-
-
-

- - 主な障害 - -

-
-
-

1行あたりの文字数など、適当に改行を挟めばいいだけではないのか?

-
-
-

特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。

-
-
-
-
#\
-i\
-n\
-c\
-l\
-u\
-d\
-e\
-<\
-s\
-t\
-d\
-i\
-o\
-.\
-h\
->\
-/*
-*/
-i\
-n\
-t\
-/*
-*/
-m\
-a\
-i\
-n(
-){
-f\
-o\
-r(
-i\
-n\
-t\
-/*
-*/
-i=
-1;
-i<
-1\
-0\
-0;
-i\
-+\
-+)
-if
-(i
-%\
-15
-==
-0)
-p\
-r\
-i\
-n\
-t\
-f(
-"\
-F\
-i\
-z\
-z\
-B\
-u\
-z\
-z\
-%\
-c\
-",
-10
-);
+          
+          
+

主な障害

+

+ 1行あたりの文字数など、適当に改行を挟めばいいだけではないのか? +

+ +

+ 特に、C言語でこのような試みをおこなったことがあるかたならそう思うだろう。事実、Cでのこの制約はほとんど無意味に等しい。 +

+ +
+              #\
+  i\
+  n\
+  c\
+  l\
+  u\
+  d\
+  e\
+  <\
+  s\
+  t\
+  d\
+  i\
+  o\
+  .\
+  h\
+  >\
+  /*
+  */
+  i\
+  n\
+  t\
+  /*
+  */
+  m\
+  a\
+  i\
+  n(
+  ){
+  f\
+  o\
+  r(
+  i\
+  n\
+  t\
+  /*
+  */
+  i=
+  1;
+  i<
+  1\
+  0\
+  0;
+  i\
+  +\
+  +)
+  if
+  (i
+  %\
+  15
+  ==
+  0)
+  p\
+  r\
+  i\
+  n\
+  t\
+  f(
+  "\
+  F\
+  i\
+  z\
+  z\
+  B\
+  u\
+  z\
+  z\
+  %\
+  c\
+  ",
+  10
+  );
 
-/* あとは同じように普通のプログラムを変形するだけなので省略 */
-
-
-
-

バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。

-
-
-

さて、PHP -ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、echo -で出力することや、for でループすること、new -でインスタンスを生成することができない。特に、出力は fizzbuzz -をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。

-
-
-

当然、名前が3文字以上ある関数も使えない。なお、標準 PHP -の範囲内において、名前が 2文字以下の関数は以下のとおりである:

-
-
-
    -
  • -

    _: gettext のエイリアス

    -
  • -
  • -

    dl: 拡張モジュールをロードする

    -
  • -
  • -

    pi: 円周率を返す

    -
  • -
-
-
-

(環境によって多少は変わるかも)

-
-
-

2文字の関数を定義しまくった拡張モジュールを用意しておいて dl() -で読み込む行為は、レギュレーションで定めた

-
-
-
-
-
    -
  • -

    標準的なインストール構成の PHP で実現できること -(デフォルトで有効になっていない拡張等を使わないこと)

    -
  • -
-
-
-
-
-

に反する -(というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。

-
-
-

また、2文字だと文字列がまともに書けないのも辛い。'' だけで -2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP -では文字列リテラル中に生の改行が書けるので

-
-
-
-
$a
-='
-a'
-;;
-
-
-
-

とすると $a"\na" になるのだが、余計な改行が入ってしまう。

-
-
-

これらの障害をどのように乗り越えるのか、次節から見ていく。

-
-
-
-
-

- - 解説 - -

-
-
-

- - 普通の (?) fizzbuzz - -

-
-
-

まずは普通に書くとしよう。

-
-
-
-
<?php
+  /* あとは同じように普通のプログラムを変形するだけなので省略 */
+            
+ +

+ バックスラッシュを使った行継続がトークンを区切らない、というのがポイントだ。 +

+ +

+ さて、PHP ではそもそもバックスラッシュを行継続に使うことができない。これにより、「3文字以上からなるトークンが一切使えない」という制約が課される。例えば、echoで出力することや、forでループすること、newでインスタンスを生成することができない。特に、出力は fizzbuzz をどんなアルゴリズムで実装しようとおこなわなければならないので、できないのは致命的である。 +

+ +

+ 当然、名前が3文字以上ある関数も使えない。なお、標準 PHP の範囲内において、名前が 2文字以下の関数は以下のとおりである: +

+ +
    +
  • +

    + _:gettextのエイリアス +

    +
  • + +
  • +

    + dl: 拡張モジュールをロードする +

    +
  • + +
  • +

    + pi: 円周率を返す +

    +
  • +
+ +

+ (環境によって多少は変わるかも) +

+ +

+ 2文字の関数を定義しまくった拡張モジュールを用意しておいてdl()で読み込む行為は、レギュレーションで定めた +

+ +
+
    +
  • +

    + 標準的なインストール構成の PHP で実現できること (デフォルトで有効になっていない拡張等を使わないこと) +

    +
  • +
+
+ +

+ に反する (というより、「それだとおもしろくもなんともないので、このルールを足した」というのが正しい)。 +

+ +

+ また、2文字だと文字列がまともに書けないのも辛い。''だけで 2文字使うので、「1文字の文字列リテラル」というものを書くことができない。PHP では文字列リテラル中に生の改行が書けるので +

+ +
+              $a
+='
+a'
+;;
+            
+ +

+ とすると$a"\na"になるのだが、余計な改行が入ってしまう。 +

+ +

+ これらの障害をどのように乗り越えるのか、次節から見ていく。 +

+
+ +
+

解説

+
+

普通の (?) fizzbuzz

+

+ まずは普通に書くとしよう。 +

+ +
+                <?php
 
-for ($i = 1; $i < 100; $i++) {
-  echo (($i % 3 ? '' : 'Fizz') . ($i % 5 ? '' : 'Buzz') ?: $i) . "\n";
-}
-
-