カロリーメイトリキッドのQuineを書きました

縁あって、カロリーメイトリキッドのプロモーション用にちょっとした Ruby プログラムを書かせてもらいました。

www.otsuka.co.jp

↑のリンクを開いて、cd .Quine したところにある CML_quine.rb がそれです。 cat CML_quine.rb とすると中身が見えます。ruby CML_quine.rb すると動きます。

f:id:ku-ma-me:20200803184915p:plain
CalorieMate-Liquid-Quine

実行してみましたか?サイト上で気楽に実行できるので、ぜひ試してみてください。

これがどういうプログラムなのか、簡単に解説しておきます *1

ローカルでの遊び方

サイト上で ruby CML_quine.rb をするだけでも楽しめますが、自分のパソコンに保存するとより楽しめます。

まず、cat CML_quine.rb した中身をまるごとコピーしてください。 n=2;で始まる行の頭から、'CalorieMate-Liquid-Quine' で始まる行の終わりまでです。 それをペーストして、CML_quine.rb というファイル名でローカルに保存してください。

そして、Ruby をインストールして、ターミナル(端末)で ruby CML_quine.rb で実行してください。 Windows Terminal で動作確認しています。

Quine

Quine とは、実行すると自分のソースコードを出力するプログラムのことです。 といっても、ソースコードをファイル読み込みして出力するわけではありません。 ちょっとしたパズルのようなコードを書くことで、ファイル読み込みせずに自分を出力できます。 詳しくはWIkipediaの記事や拙著『あなたの知らない超絶技巧プログラミングの世界』をご覧ください。

そして、このプログラムはQuineみたいなもので、実行するとまずソースコードを出力し、それからアニメーションをします。

「みたいなもの」と言ったのは、1回実行しただけではちょっとだけ違う結果になるからです。 サイトのreadme.mdにも書いてありますが、次のように3回実行を繰り返すと元に戻るようになっています。

$ ruby CML_quine.rb  > CML_quine2.rb

$ ruby CML_quine2.rb > CML_quine3.rb

$ ruby CML_quine3.rb > CML_quine4.rb

$ diff -s CML_quine.rb CML_quine4.rb
ファイル CML_quine.rb と CML_quine4.rb は同一です

ターミナル上でのアニメーション

各プログラムの違いは、『フレーバー』です。 CML_quine.rb と CML_quine2.rb と CML_quine3.rb をそれぞれ単体で実行すると、いずれも同じアニメーションをしますが、最終的に出来上がるフレーバーが変わるようになってます。 次のように実行してみてください。

$ ruby CML_quine.rb

$ ruby CML_quine2.rb

$ ruby CML_quine3.rb

このアニメーションは、エスケープシーケンスを使って色付き文字のモードにしたり、カーソルを移動したりすることで行っています。

ロゴを描くためのカーソルの動きのデータは、すべてコード中に埋め込まれています。 そのままだと巨大になってしまうので、バイトペア符号化によって圧縮しています。

流体シミュレーション

最後。缶に黄色い液体が注ぎ込まれるアニメーションですが、これは決まった動きをハードコーディングしているわけではなく、流体シミュレーションを使って実行時に計算しています。 流体力学の原理であるナビエ-ストークス方程式Smoothed Particle Hydrodynamicsと言われる方法で数値的・近似的に解きます。 簡単に言えば、液体を表現する粒子同士がお互いに押し合ったり(圧力)、粘ついたり(粘性)、重力に引っ張られたり(外力)するのをシミュレーションしています。

実はここは、以前C言語で書いたコードの移植です *2 。こちら。

www.youtube.com

ただ、今回はシミュレーションの精度を上げるために粒子の数を増やしたこともあって実行速度が遅くなってしまったので、空間分割法を実装して高速化しました。

おまけ

「プログラムを表示した後、アニメーションで上書きしちゃったら Quine にならないじゃないじゃん!」と思う人がいるかもしれません。 しかし、背景色と文字色が同じになってて読めないだけで、実は文字はちゃんと表示されています。 次の動画のように端末からコピペすれば実行できます。

「出力にエスケープシーケンスを混ぜたらプログラムとして実行できない!」と思う人がいるかもしれません。 しかし、エスケープシーケンスはコメント内に出すようになっているので、実はちゃんと動きます。 次のように実行すれば、エスケープシーケンス入りの CML_quine2.rb がちゃんとプログラムとして動くことがわかります。

$ script -q -c "ruby CML_quine.rb" /dev/null | tee CML_quine2.rb
$ ruby CML_quine2.rb
$ vim CML_quine2.rb

ということで

このコードはカロリーメイトリキッドを 3 種類ぜんぶ飲みながら実装しました。

以上の処理はどこか見えないところに隠されているわけではなく、cat CML_quine.rb で見ることができる 22 行のプログラムの中にすべて詰め込まれています。 プログラミング言語 Ruby の簡潔さ・強力な言語機能・柔軟性を悪用するとこんなこともできるんですよ。他の言語ではなかなかむずかしい。

ということで、腕に覚えのある人はぜひ解読してみてください! 他にもここで解説しなかった工夫がいくつか仕込まれています *3

なお、Quine に興味がある人は、拙著『あなたの知らない超絶技巧プログラミングの世界』に詳しいやり方からたくさんの実例までむちゃくちゃ詳しく書いてあるので、ぜひ読んでみてください。(宣伝)

*1:念のために書いておくと、このブログを書くことは関係者の方に了承を得ております。

*2:余談ですが、元のソースコードを失っていたので、難読化コードを読み解いた。

*3:流体シミュレーションをさらに高速化するためのチート(上げ底)や、缶の形状を実行時に生成する式、isatty を使っているところ、謎のイニシャル :-)などなど