diff options
| author | nsfisis <nsfisis@gmail.com> | 2022-04-09 21:58:34 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2022-04-10 09:39:00 +0900 |
| commit | 1f542ef7a965b0bfc400053a254567ddf2d47df3 (patch) | |
| tree | c71bb26f9d2d4d39bc336ae4eced52f57a7fc356 /content/posts | |
| parent | 1c647fbb6ff2710de6bcc8d88a874c32c0f742de (diff) | |
| download | blog.nsfisis.dev-1f542ef7a965b0bfc400053a254567ddf2d47df3.tar.gz blog.nsfisis.dev-1f542ef7a965b0bfc400053a254567ddf2d47df3.tar.zst blog.nsfisis.dev-1f542ef7a965b0bfc400053a254567ddf2d47df3.zip | |
new post: phperkaigi-2022-tokens
Diffstat (limited to 'content/posts')
| -rw-r--r-- | content/posts/phperkaigi-2022-tokens.md | 160 |
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問目はまだ解説を書いていない。 |
