diff options
| author | nsfisis <nsfisis@gmail.com> | 2025-12-28 03:12:31 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2025-12-28 03:14:38 +0900 |
| commit | 2cba57e66c3727ef0ffb1a55fdefd4f53b00dd21 (patch) | |
| tree | 9cbdf2d56ac7f133e324c2b38bd3ab1d7f0edd02 | |
| parent | 8390d9ef4b1eb72d9f86e90a00889db61b6136cf (diff) | |
| download | phperbiglt-2025-main.tar.gz phperbiglt-2025-main.tar.zst phperbiglt-2025-main.zip | |
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | README.md | 95 | ||||
| -rw-r--r-- | assets/0.py.png | bin | 0 -> 440110 bytes | |||
| -rw-r--r-- | assets/1.py.png | bin | 0 -> 441740 bytes | |||
| -rw-r--r-- | assets/107.py.png | bin | 0 -> 331705 bytes | |||
| -rw-r--r-- | assets/108.php.png | bin | 0 -> 440815 bytes | |||
| -rw-r--r-- | tools/vhs/0.py.tape | 7 | ||||
| -rw-r--r-- | tools/vhs/1.py.tape | 7 | ||||
| -rw-r--r-- | tools/vhs/107.py.tape | 7 | ||||
| -rw-r--r-- | tools/vhs/108.php.tape | 7 | ||||
| -rw-r--r-- | tools/vhs/_config.tape | 4 |
11 files changed, 130 insertions, 0 deletions
@@ -3,3 +3,6 @@ q0.py: python .107.unformatted.py > .108.php php .108.php > 0.py rm .107.unformatted.py .108.php + +assets/%.png: tools/vhs/%.tape tools/vhs/_config.tape + nix run 'nixpkgs#vhs' $< @@ -15,3 +15,98 @@ $ diff 0.py 0-2.py ``` 変則 Quine であり、最初の `0.py` は `gen.py` によって生成されます (`make` で出力可能)。 + + +# 基本動作 + +`0.py` は「巳」の字の形をしています。これは、2025 年が巳年であることにちなんだものです。Python を使っているのも同様の理由です。 + + + +`0.py` を Python で実行すると、次のような出力が得られます。 + + + +これは `0.py` と同じく Python コードであり、その大部分が `0.py` と共通しています。 + +この出力を `1.py` として保存し、実行結果を `2.py` として保存するという動作を繰り返すと、108 回目に異なる動作となります (「108」という数字は、除夜の鐘から取ったものです)。 + +``` +$ python 0.py > 1.py +$ python 1.py > 2.py +$ python 2.py > 3.py +... +$ python 107.py +``` + + + +この実行結果は、「午」の字の形をしています。来年 2026 年は午年ですね! + +また、Python のソースコードではなく PHP のソースコードとなっています。PHP のマスコットは馬......であればよかったのですが残念ながら象でした。 + +これを PHP インタプリタで実行すると、次のようになります。 + + + +これは、最初の `0.py` と完全に一致します。以降は同じ挙動を繰り返します。 + + +# 解説 + +基本となるのは、mame 氏による「Quine リレー」の記事 (https://mametter.hatenablog.com/entry/20130715/p1) にて説明されているテクニックです。 + +> 普通の Quine は、こんな感じの構造です。 +> +> ``` +> s = (自分自身のソースコード文字列を得る) +> puts s +> ``` +> +> 一方、例えば何かを出力する Perl プログラム、を出力する Ruby プログラムはこんな感じです。 +> +> ``` +> puts "print(\"...\");" +> ``` +> +> これと Quine を組み合わせれば、Ruby と Perl を行き来する multi-Quine のできあがり。 +> +> ``` +> s = (自分自身のソースコード文字列を得る) +> puts "print(\"#{ s }\");" +> ``` + +実装に用いた言語こそ異なりますが、基本となるのはこのアイデアです。 + +ここに、「巳」「午」の字形を出力したり、108 回のカウントをしたりする機構を加えると、今回のソースコードができます。 + +`0.py` は `gen.py` というプログラムによって生成しており、その `template1` 変数に記述されたソースコードが動作の基盤となるものです。 + +その大部分を占めている出力の形を整えるコード (`fmt`) を除くと、次のようになっています。 + +```python +from base64 import b64encode +from zlib import compress, decompress +j = b'107' # 108 回のカウント +s = b"@@" # この変数にソースコードが埋め込まれる +z = decompress(b64decode(s)).replace(b"j = b'%s'" % j, b"j = b'%03d'" % ((int(j)+1) % 108)) +t = z.replace(b"@"+b"@", b64encode(compress(z))) +u = b64encode(t) + +def fmt(u, f, php): # 整形 + ... + +F1 = ["巳の字形データ"] +F2 = ["午の字形データ"] + +v = fmt(u, F1, False) # Python で「巳」に整形 +if j == b"107": + # 108 回目。PHP で「午」に整形 + print(fmt(b64encode(compress(v)), F2, True).decode("utf-8")) +else: + print(v.decode("utf-8")) +``` + +言語間での文字列エスケープを簡単にするため、Base64 エンコードを用いています。これによってソースコード中のクォートやバックスラッシュが消えるので、ソースコードを内部に埋め込む際のエスケープについて考える必要がなくなります。 + +また、PHP コード側で整形処理を書く手間を減らすため、ソースコードの整形処理はすべて Python 側でおこなうようにしています。「午」の PHP コードは、内部に「巳」の形へ整形済みの Python コードを保持し、それを加工なしで出力するようになっています。 diff --git a/assets/0.py.png b/assets/0.py.png Binary files differnew file mode 100644 index 0000000..67aa7d2 --- /dev/null +++ b/assets/0.py.png diff --git a/assets/1.py.png b/assets/1.py.png Binary files differnew file mode 100644 index 0000000..7680e51 --- /dev/null +++ b/assets/1.py.png diff --git a/assets/107.py.png b/assets/107.py.png Binary files differnew file mode 100644 index 0000000..6c38a72 --- /dev/null +++ b/assets/107.py.png diff --git a/assets/108.php.png b/assets/108.php.png Binary files differnew file mode 100644 index 0000000..e49d626 --- /dev/null +++ b/assets/108.php.png diff --git a/tools/vhs/0.py.tape b/tools/vhs/0.py.tape new file mode 100644 index 0000000..dd19867 --- /dev/null +++ b/tools/vhs/0.py.tape @@ -0,0 +1,7 @@ +Source "tools/vhs/_config.tape" + +Type "cat 0.py" +Enter +Sleep 1s + +Screenshot assets/0.py.png diff --git a/tools/vhs/1.py.tape b/tools/vhs/1.py.tape new file mode 100644 index 0000000..63391e1 --- /dev/null +++ b/tools/vhs/1.py.tape @@ -0,0 +1,7 @@ +Source "tools/vhs/_config.tape" + +Type "python 0.py" +Enter +Sleep 1s + +Screenshot assets/1.py.png diff --git a/tools/vhs/107.py.tape b/tools/vhs/107.py.tape new file mode 100644 index 0000000..5410f96 --- /dev/null +++ b/tools/vhs/107.py.tape @@ -0,0 +1,7 @@ +Source "tools/vhs/_config.tape" + +Type "python 107.py" +Enter +Sleep 1s + +Screenshot assets/107.py.png diff --git a/tools/vhs/108.php.tape b/tools/vhs/108.php.tape new file mode 100644 index 0000000..3fec172 --- /dev/null +++ b/tools/vhs/108.php.tape @@ -0,0 +1,7 @@ +Source "tools/vhs/_config.tape" + +Type "python 107.py | php" +Enter +Sleep 1s + +Screenshot assets/108.php.png diff --git a/tools/vhs/_config.tape b/tools/vhs/_config.tape new file mode 100644 index 0000000..0bf7842 --- /dev/null +++ b/tools/vhs/_config.tape @@ -0,0 +1,4 @@ +Set FontSize 8 +Set Width 950 +Set Height 950 +Set Theme "iceberg-dark" |
