From 13b159c6dd499b5c67a110e02780d9e741f0ecdb Mon Sep 17 00:00:00 2001 From: nsfisis Date: Mon, 24 Feb 2025 06:27:07 +0900 Subject: feat(blog/nuldoc): do not insert whitespace to linebreaks between Japanese sentences --- .../2022-04-09/phperkaigi-2022-tokens/index.html | 94 +++++++++++----------- 1 file changed, 47 insertions(+), 47 deletions(-) (limited to 'vhosts/blog/public/posts/2022-04-09') diff --git a/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html b/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html index c8eed57d..b4875558 100644 --- a/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html +++ b/vhosts/blog/public/posts/2022-04-09/phperkaigi-2022-tokens/index.html @@ -70,7 +70,7 @@

はじめに

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

@@ -81,7 +81,7 @@

第1問 brainf_ck.php

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

<?php
@@ -155,7 +155,7 @@ $🐘([
 ]);

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

@@ -163,14 +163,14 @@ $🐘([

絵文字

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

プログラム全体

- Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。 + Brainf*ck のインタプリタとプログラムになっている。 Brainf*ck とは、難解プログラミング言語のひとつであり、ここで説明するよりも Wikipedia の該当ページを読んだ方がよい。

@@ -178,7 +178,7 @@ $🐘([

- なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。 + なお、brainf*ck プログラムを普通の書き方で書くと、次のようになる。

+ + + + + + + + + +
@@ -209,7 +209,7 @@ $🐘([
                 

- それぞれの絵文字で表された関数が、各命令に対応している。 + それぞれの絵文字で表された関数が、各命令に対応している。

    @@ -243,45 +243,45 @@ $🐘([

- , (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。 + , (入力) に対応する関数はない (このプログラムでは使わないので用意していない)。

- なお、$🐘 はいわゆる main 関数であり、プログラムの実行部分である。 + なお、$🐘 はいわゆる main 関数であり、プログラムの実行部分である。

絵文字の選択

- おおよそ意味に合致するよう選んでいるが、$🤡$🎪 は弊社デジタルサーカスにちなんでいる。 また、$🐘 は PHP のマスコットの象に由来する。 + おおよそ意味に合致するよう選んでいるが、$🤡$🎪 は弊社デジタルサーカスにちなんでいる。 また、$🐘 は PHP のマスコットの象に由来する。

strict_types

- declare 文の strict_types に指定できるのは、01 の数値リテラルだが、 0x00b1 のような値も受け付ける。 今回は、PHP 8.1 から追加された、0O または 0o から始まる八進数リテラルを使った。 + declare 文の strict_types に指定できるのは、01 の数値リテラルだが、 0x00b1 のような値も受け付ける。 今回は、PHP 8.1 から追加された、0O または 0o から始まる八進数リテラルを使った。

URL

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

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

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

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

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

assert(0 === +!![]);
@@ -291,33 +291,33 @@ $🐘([
 assert(10 === +(![].+!![]));

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

- また、error_reporting に指定しているのは -1 である。 これは、! によって文字列を false にし、+ によって false0 にし、さらにビット反転して -1 にしている。 + また、error_reporting に指定しているのは -1 である。 これは、! によって文字列を false にし、+ によって false0 にし、さらにビット反転して -1 にしている。

if 文なしで条件分岐

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

whilefor 文なしでループ

- 不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に Z コンビネータとして知られるものを使った ($z)。 + 不動点コンビネータを使って無名再帰する (詳しい説明は省略する。これらの単語で検索してほしい)。 ここでは、一般に Z コンビネータとして知られるものを使った ($z)。

- 実際のところ、$🤡$🎪$🐘 は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。 + 実際のところ、$🤡$🎪$🐘 は、一度 Scheme (Lisp の一種) で書いてから PHP に翻訳する形で記述した。

- なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。 + なお、PHP は末尾再帰の最適化をおこなわない (少なくとも今のところは) ので、 あまりに長い brainf*ck プログラムを書くとスタックオーバーフローする。

@@ -326,7 +326,7 @@ $🐘([

第2問 riddle.php

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

<?php
@@ -365,17 +365,17 @@ $🐘([
 }

- さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。 トークンを得るためには、ソースコードを読み、定数 N を特定する必要がある。 + さて、この問題はさきほどのように単純に実行しただけでは、謎のブロックが表示されるだけでトークンは得られない。トークンを得るためには、ソースコードを読み、定数 N を特定する必要がある。

- ここでは、私の想定解を解説する。 + ここでは、私の想定解を解説する。

読解

- まずはソースコードを読んでいく。 + まずはソースコードを読んでいく。

$token = [
@@ -383,38 +383,38 @@ $🐘([
 ];

- 数値からなる $token があり、各要素をループしている。 + 数値からなる $token があり、各要素をループしている。

$x = $x ^ N;

- まずは排他的論理和 (xor) を取り、 + まずは排他的論理和 (xor) を取り、

$x = sprintf('%025b', $x);

- 二進数に変換して、 + 二進数に変換して、

$x = str_replace(search: ['0', '1'], replace: [' ', '#'], subject: $x);

- 0 を空白に、1 を # にし、 + 0 を空白に、1 を # にし、

$x = implode("\n", str_split($x, length: 5));

- 5文字ごとに区切ったあと、改行で結合している。 + 5文字ごとに区切ったあと、改行で結合している。

ヒント

- 次に、ソースコードに書いてあるヒントを読んでいく。 + 次に、ソースコードに書いてあるヒントを読んでいく。

    @@ -436,14 +436,14 @@ $🐘([

- ここで、PHPer トークンは必ず # 記号から始まることを思いだすと、 $token の最初の数字 0x14B499C は、変換の結果 # になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。 + ここで、PHPer トークンは必ず # 記号から始まることを思いだすと、$token の最初の数字 0x14B499C は、変換の結果 # になるのではないかと予想される (なお、このことは、リポジトリの README ファイルに追加ヒントとして書かれている)。

解く

- ここまでわかれば、あと一歩で解ける。すなわち、0x14B499C# に変換されるような N を見つければよい。 + ここまでわかれば、あと一歩で解ける。すなわち、0x14B499C# に変換されるような N を見つければよい。

@@ -453,7 +453,7 @@ $🐘([

assert(0 <= N && N <= 0b11111_11111_11111_11111_11111);

- なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。 + なのでブルートフォースしてもよいが、ここではブルートフォースしない方法を紹介する。

<?php
@@ -474,7 +474,7 @@ $🐘([
 " # # ");

- この一連の変換に対する逆変換を考えると、次のようになる。 + この一連の変換に対する逆変換を考えると、次のようになる。

<?php
@@ -495,7 +495,7 @@ $🐘([
 echo "N = $n\n";

- これを実行すると、N が得られる。 + これを実行すると、N が得られる。

@@ -503,7 +503,7 @@ $🐘([

第3問 toquine.php

- ソースコードはこちら。 + ソースコードはこちら。

<?php
@@ -537,13 +537,13 @@ $t .= implode("\n", str_split(str_replace(['printf($s, $t, str_rot13("<<<'D'\n{$s}\nD"), implode(",\n", $ws));

- コメントにもあるとおり、次のようにして実行すれば答えがでてくる。 + コメントにもあるとおり、次のようにして実行すれば答えがでてくる。

$ php toquine.php | php | php | php | ...

- 実際にはもう少しパイプで繋げなければならない。 + 実際にはもう少しパイプで繋げなければならない。

@@ -551,36 +551,36 @@ $t .= implode("\n", str_split(str_replace(['

プログラム全体

- コメントにもあるとおり、これは quine (風) のプログラムになっている。 Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。 + コメントにもあるとおり、これは quine (風) のプログラムになっている。Quine とは、自分のソースコードをそっくりそのまま出力するようなプログラムのことである。

- このプログラムは、実行すると自身とほとんど同じプログラムを出力する。 異なるのはトークンになっている部分のみである。 + このプログラムは、実行すると自身とほとんど同じプログラムを出力する。異なるのはトークンになっている部分のみである。

トークン

- $xs がトークンに対応している。変換のロジックは riddle.php とほぼ同じなので省略する。 + $xs がトークンに対応している。変換のロジックは riddle.php とほぼ同じなので省略する。

状態保持

- トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。 このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、__LINE__ から情報を取得している。 + トークンの何文字目まで出力したかを、ソースコードを変えずに (quine なので) 覚えておく必要がある。このプログラムでは、トークンが出力されるとソースコードがだんだんと長くなっていくのを利用して、__LINE__ から情報を取得している。

ROT 13

- Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。 これがあまり美しくないので、toquine.php では、ROT 13 変換を使って難読化した。 + Quine は、素朴に書くとプログラムの一部が 2回記述されてしまう。これがあまり美しくないので、toquine.php では、ROT 13 変換を使って難読化した。

- それにしてもなぜこんなものが標準ライブラリに……。 + それにしてもなぜこんなものが標準ライブラリに……。

@@ -589,15 +589,15 @@ $t .= implode("\n", str_split(str_replace(['

おわりに

- 解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。 + 解いていただいたみなさん、また、難易度調整につきあっていただいた社内のみなさん、ありがとうございました。

- 今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、 来年は 5問、より面白い問題を持っていきます。 + 今回は直前に作りはじめたのもあり、3問だけかつ使い古されたネタばかりになってしまいましたが、来年は 5問、より面白い問題を持っていきます。

- 実はもう作りはじめているので、どうか来年もありますように……。 + 実はもう作りはじめているので、どうか来年もありますように……。

-- cgit v1.2.3-70-g09d2