aboutsummaryrefslogtreecommitdiffhomepage
path: root/content/posts/phperkaigi-2022-tokens.md
diff options
context:
space:
mode:
Diffstat (limited to 'content/posts/phperkaigi-2022-tokens.md')
-rw-r--r--content/posts/phperkaigi-2022-tokens.md160
1 files changed, 160 insertions, 0 deletions
diff --git a/content/posts/phperkaigi-2022-tokens.md b/content/posts/phperkaigi-2022-tokens.md
new file mode 100644
index 0000000..a3ff244
--- /dev/null
+++ b/content/posts/phperkaigi-2022-tokens.md
@@ -0,0 +1,160 @@
+---
+title: "PHPerKaigi 2022 トークン問題の解説"
+date: 2022-04-09T21:50:19+09:00
+draft: false
+---
+
+
+# はじめに
+
+本日開始された [PHPerKaigi 2022](https://phperkaigi.jp/2022/) の PHPer チャレンジにおいて、弊社デジタルサーカスの問題を 3問作成した。この記事では、これらの問題の解説をおこなう。
+
+リポジトリはこちら: https://github.com/nsfisis/PHPerKaigi2022-tokens
+
+
+注意: ネタバレ防止のため、2問目と 3問目はまだ解説を書いていない。
+
+
+# 第1問 brainf_ck.php
+
+ソースコードはこちら。実行には PHP 8.1 以上が必要なので注意。
+
+```php
+<?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
+
+ソースコードのライセンスを示したこの部分だが、
+
+```php
+https://creativecommons.org/publicdomain/zero/1.0/
+```
+
+完全に合法な PHP のコードである。
+`https:` 部分はラベル、`//` 以降は行コメントになっている。
+
+### リテラルなしで数値を生成する
+
+ソースコード中に、ほとんど数値リテラルが書かれていないことにお気づきだろうか。
+PHP では、型変換を利用することで任意の整数を作り出すことができる。
+
+```php
+assert(0 === +!![]);
+assert(1 === +![]);
+assert(2 === ![]+![]);
+assert(3 === ![]+![]+![]);
+assert(10 === +(![].+!![]));
+```
+
+`[]` に `!` を適用すると `TRUE` が返ってくる。それに `+`
+を適用すると、`bool` から `int` ヘの型変換が走り、`1` が生成される。`10`
+はさらにトリッキーだ。まず `1` と `0` を作り、`.` で文字列として結合する
+(`'10'`)。これに `+` を適用すると、`string` から `int`
+への型変換が走り、`10` が生まれる (コード量に頓着しないなら、`1` を 10
+個足し合わせてももちろん 10 が作れる)。
+
+### `if` 文なしで条件分岐
+
+三項演算子ないし `match` 式を使うことで、`if` を一切書かずに条件分岐ができる。
+また、`&&` / `||` も使えることがある。
+遅延評価が不要なケースでは、`[$t, $f][$cond]` のような形で分岐することもできる。
+
+### `while`、`for` 文なしでループ
+
+不動点コンビネータを使う (説明は省略)。ここでは、一般に Z
+コンビネータとして知られるものを使った (`$z`)。
+
+
+### プログラム全体
+
+Brainf\*ck。以上。
+
+
+
+# 第2問 riddle.php
+
+前述のとおり、ネタバレ防止のため、2問目はまだ解説を書いていない。
+
+
+# 第3問 toquine.php
+
+前述のとおり、ネタバレ防止のため、3問目はまだ解説を書いていない。