- 13KiBサイズの単一ファイルで、Windows、Linux、ブラウザのすべてで動作するSnakeゲームであり、3つのプラットフォームを1つのソースでサポート
- ヘビを操作して餌を食べ、壁にぶつからないようにする古典的なSnakeのルールに従い、スコア・レベル・迷路構造を含む
- 各プラットフォームごとにC(WinAPI/X11) および JavaScript(HTML5 Canvas) で実装され、それぞれ3〜5KiB程度に圧縮・結合されている
- Windowsでは異常なPEヘッダーとapphelpメカニズム、Linuxではlzma圧縮とシェルドロッパー、ブラウザではHTML/CSSトリックを利用して実行
- 3つの実装を結合した結果、13,312バイトの単一実行ファイルが完成し、マルチプラットフォーム実行ファイル構造の実験的可能性を示している
Cosmopolitan libcから着想を得たマルチプラットフォームの試み
- Cosmopolitan libc は、Cソースコードを複数のオペレーティングシステムで実行可能な単一バイナリにコンパイルできるツールキット
- Windows、Linux、BSDなどさまざまなOSでネイティブ実行をサポート
- GUI非対応と大きなバイナリサイズという制約から、作者は16KiB以下のビデオゲームを自作する挑戦を選択
- 目標はWindows、Linux、ブラウザのすべてで動作する単一ソースベースのゲームを作ること
ゲーム構造とルール
- ゲームは標準的なSnakeゲームで、方向キーまたはWASDで操作
ESCで終了、Rでリセット、Pで一時停止、スペースバーで開始
- 餌を食べるたびにスコアが増加し、通常の餌は10点、黄色い餌(15%の確率) は20点
- 餌は一定時間後に消え、消えるまでの時間はヘビの速度(長さに比例)に応じて決まる
- 10個の餌を食べると次のレベルへ移動し、壁の配置がランダムに変更される
- 常に餌までの経路が存在するように迷路を生成
- ヘビの初期位置もランダムだが、最低5マスの余裕空間が確保された方向に配置
- 完成したゲームファイルのサイズは13,772バイト
3つのプラットフォームごとの実装方式
- Windows版はWinAPIベースのCコードで書かれ、圧縮スクリプトとデコンプレッサスタブを含む
- PEヘッダーの
MZシグネチャ以降に自由に制御できるバイト列を活用してシェルスクリプトを埋め込み
- これにより、ファイルはWindows実行ファイルであると同時にLinuxシェルスクリプトとしても有効
- 初回実行時に「The application was unable to start correctly (0xc0000005)」エラーが発生することがあるが、再実行すると正常に動作
- Linux版は
lzma圧縮を使用し、小さなシェルドロッパーが圧縮されたELF64バイナリを抽出・実行
- ファイルの前後の一部をスキップしながら実行されるよう構成
- HTML版は、ブラウザがファイルの不要な先頭部分を無視してHTMLを処理する特性を利用
- CSSによって不要なデータが画面に表示されないよう処理
単一ファイル結合と構造
- 3つのプラットフォーム向けファイルを特定の順序で連結(concatenate) し、各環境が自分に合った部分だけを実行するよう構成
- WindowsはPEセクション、LinuxはELFセクション、ブラウザはHTMLセクションを認識
- 最終ファイルサイズは13,312バイトで、3つの環境すべてで動作するポリグロットバイナリが完成
- ファイル内部にはWindows PEヘッダー、Linux向けLZMA圧縮コード、HTML/CSS/JavaScriptコードが順番に含まれる
- 例示コードブロックには
MZシグネチャ、ksマーカー、<html>タグ、<script>ブロックなどが順に存在
技術的意義
- 単一ファイルでWindows、Linux、ブラウザをすべてサポートする実行構造を実装
- PE、ELF、HTMLフォーマットの入れ子活用によってプラットフォームごとの実行経路を分岐
- 13KiBという極めて小さなサイズで圧縮、フォーマットハック、マルチプラットフォーム実行を組み合わせた実験的成果
1件のコメント
Hacker Newsのコメント
Linux実行ファイルを取り出してみたが、readelf と objdump がまともに読めず驚いた
調べてみると、PT_DYNAMICヘッダの未使用フィールドに動的リンカ名を無理やり入れて容量を節約した構造だった
ただ、こういうフォーマットをわざと壊すのは 無意味な節約 だと思う
アンチウイルスや DEP のようなセキュリティ機能と衝突することもありそうなので、こういう実行ファイルはいじりたくない
元の ゼルダ(Zelda) のゲームのファイルサイズがあまりに小さくて驚く
あれほど少ないコードとデータで、これほど大きな 感動と没入感 を生み出したのは驚異的だ
The Legend of Zelda (Wikipedia)
40年後にマップを抽出したところ、PNG だけで 800KB を超えた
ゲームマップを見る
デザイナーたちは空間制約の中でパズルのように構成していた
Zeldaのマップ構造の参考
私のテスト結果
.htmlに変えると実行できるlzmaコマンドがないというエラーが出たが、xzパッケージをインストールすると動いた.comや.exeで実行するとエラー (0xc0000005) になったが、DEP設定を無効化すると動いたchmod +x snake.comして実行すると Mono が試みられて失敗する代わりに
bash snake.comで実行すると問題なく動く。Debian 13 での話興味深いのは、このファイルが 3つの実行ファイルを1つに結合した形 だということだ
そのため各プラットフォーム向けにまったく別のプログラムを入れることもできる
kkrieger という 96KB の FPS ゲームを思い出した
当時としてはグラフィックのレベルが驚異的だった
kkrieger (archive)
Mac でブラウザ以外に実行する方法があるのか気になる
cannot execute binary fileエラーが出るこうしたメカニズムを発展させて、本当の 汎用実行ファイル(universal binary) を作れるのか気になる
たとえば Haxe でコードを書いて C++ にコンパイルすれば Win32 と Linux 向けを作れ、
JavaScript に変換して HTML でも実行できるようにしたうえで、
その3つの成果物を1つのファイルに結合する、といった形で実現できそうだ
1つのファイルでどこでも実行できる 単一実行アプリ という発想が気に入った
私もサーバーレスプラットフォームを作りながら、こういう方向を研究している
たった1つの
.htmlファイルでデータ駆動型アプリを作り、web-components をリモートから読み込む構造だfile://プロトコルで HTML を直接開く機能は強力だが、しばしば見落とされているつまり、単にブラウザインスタンスを立ち上げたのではなく、完全なネイティブアプリを2つ作ったことになる
Polyglotファイル がこんなに遅く登場したのが不思議だ
技術的には10〜20年前でも可能だったように思える
EICAR.COM が、テキストと実行ファイルを兼ねた初期の例として思い浮かぶ
js13kGames のような超小型ウェブゲームコンテストを思い出す