はじめに

-

本日開始された PHPerKaigi 2022 の PHPer チャレンジにおいて、弊社デジタルサーカスの問題を 3問作成した。この記事では、これらの問題の解説をおこなう。

-

リポジトリはこちら: https://github.com/nsfisis/PHPerKaigi2022-tokens

-

注意: ネタバレ防止のため、2問目と 3問目はまだ解説を書いていない。

-

第1問 brainf_ck.php

-

ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。

-
<?php
-
-declare(strict_types=0O1);
-
-namespace Dgcircus\PHPerKaigi\Y2022;
-
-/**
- * @todo
- * Run this program to acquire a PHPer token.
- */
-
-https://creativecommons.org/publicdomain/zero/1.0/
-
-\error_reporting(~+!'We are hiring!');
-
-$z = fn($f) => (fn($x) => $f(fn(...$xs) => $x($x)(...$xs)))(fn($x) => $f(fn(...$xs) => $x($x)(...$xs)));
-$id = \spl_object_id(...);
-$put = fn($c) => \printf('%c', $c);
-$mm = fn($p, $n) => new \ArrayObject(\array_fill(+!![], $n, $p));
-
-$👉 = fn($m, $p, $b, $e, $mp, $pc) => [++$mp, ++$pc];
-$👈 = fn($m, $p, $b, $e, $mp, $pc) => [--$mp, ++$pc];
-$👍 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, ++$m[$mp]];
-$👎 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, --$m[$mp]];
-$📝 = fn($m, $p, $b, $e, $mp, $pc) => [$mp, ++$pc, $put($m[$mp])];
-$🤡 = fn($m, $p, $b, $e, $mp, $pc) => match ($m[$mp]) {
-    +!![] => [$mp, $z(fn($loop) => fn($pc, $n) => match ($id($p[$pc])) {
-      $b => $loop(++$pc, ++$n),
-      $e => $n === +!![] ? ++$pc : $loop(++$pc, --$n),
-      default => $loop(++$pc, $n),
-    })($pc, -![])],
-    default => [$mp, ++$pc],
-};
-$🎪 = fn($m, $p, $b, $e, $mp, $pc) => match ($m[$mp]) {
-    +!![] => [$mp, ++$pc],
-    default => [$mp, $z(fn($loop) => fn($pc, $n) => match ($id($p[$pc])) {
-      $e => $loop(--$pc, ++$n),
-      $b => $n === +!![] ? $pc+![] : $loop(--$pc, --$n),
-      default => $loop(--$pc, $n),
-    })($pc, -![])],
-};
-$🐘 = fn($p) => $z(fn($loop) => fn($m, $p, $b, $e, $mp, $pc) =>
-  isset($p[$pc]) && $loop($m, $p, $b, $e, ...($p[$pc]($m, $p, $b, $e, $mp, $pc)))
-)($mm(+!![], +(![].![])), $p, $id($🤡), $id($🎪), +!![], +!![]);
-
-$🐘([
-  $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-  $🤡,
-    $👉, $👍, $👍, $👍,
-    $👉, $👍, $👍, $👍, $👍, $👍,
-    $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-    $👉, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍, $👍,
-    $👈, $👈, $👈, $👈, $👎,
-  $🎪,
-  $👉, $👍, $👍, $👍, $👍, $👍, $📝,
-  $👎, $👎, $📝,
-  $👉, $👎, $👎, $👎, $📝,
-  $👉, $👎, $👎, $👎, $📝,
-  $👎, $👎, $📝,
-  $👎, $📝,
-  $👈, $📝,
-  $👉, $👉, $👎, $👎, $📝,
-  $👍, $👍, $👍, $👍, $👍, $👍, $👍, $📝,
-  $👈, $👎, $👎, $👎, $👎, $📝,
-  $👈, $📝,
-  $👉, $👍, $👍, $📝,
-  $👉, $👎, $📝,
-  $👈, $📝,
-]);
-

この問題は、単に適切なバージョンの PHP で動かせばトークンが得られる。

-

解説

-

絵文字

-

まず目につくのは大量の絵文字だろう。 -PHP は識別子に使用できる文字の範囲が広く、絵文字も使うことができる。

-

URL

-

ソースコードのライセンスを示したこの部分だが、

-
https://creativecommons.org/publicdomain/zero/1.0/
-

完全に合法な PHP のコードである。 -https: 部分はラベル、// 以降は行コメントになっている。

-

リテラルなしで数値を生成する

-

ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。 -PHP では、型変換を利用することで任意の整数を作り出すことができる。

-
assert(0 === +!![]);
-assert(1 === +![]);
-assert(2 === ![]+![]);
-assert(3 === ![]+![]+![]);
-assert(10 === +(![].+!![]));
-

[]! を適用すると TRUE が返ってくる。それに + -を適用すると、bool から int ヘの型変換が走り、1 が生成される。10 -はさらにトリッキーだ。まず 10 を作り、. で文字列として結合する -('10')。これに + を適用すると、string から int -への型変換が走り、10 が生まれる (コード量に頓着しないなら、1 を 10 -個足し合わせてももちろん 10 が作れる)。

-

if 文なしで条件分岐

-

三項演算子ないし match 式を使うことで、if を一切書かずに条件分岐ができる。 -また、&& / || も使えることがある。 -遅延評価が不要なケースでは、[$t, $f][$cond] のような形で分岐することもできる。

-

whilefor 文なしでループ

-

不動点コンビネータを使う (説明は省略)。ここでは、一般に Z -コンビネータとして知られるものを使った ($z)。

-

プログラム全体

-

Brainf*ck。以上。

-

第2問 riddle.php

-

前述のとおり、ネタバレ防止のため、2問目はまだ解説を書いていない。

-

第3問 toquine.php

-

前述のとおり、ネタバレ防止のため、3問目はまだ解説を書いていない。

-