ゆなこんブログ

ゆなこんぴゅーたー (Yuna Computer) の公式ブログ

コンパイル時ゲーム爆誕

コンパイル時にゲームを動かす

初っ端から「何を言っているんだお前」状態ですが、コンパイル時ゲームを作った人が現れました。 Jean Guegant です。

プレゼンの動画もアップされています。

www.youtube.com

Meta Crush Saga

作ったゲームの名前は Meta Crush Saga といいます。Bejeweled や Candy Crush Saga に似たアスキーアートのゲームです。

GitHub にソースコードがアップされています。Jiwan/meta_crush_saga: A C++17 compile-time game

仕組み

通常のゲームの場合

通常のゲームは、まずソースコードをコンパイルし、実行ファイルを作ります。 そして、その実行ファイルがメインループでレンダリング(表示)とユーザーの入力を延々と繰り返します。

コンパイル時ゲームの場合

まずソースコードをコンパイルします。 そのコンパイルの時に、初期のレンダリング状態とユーザーの入力を受け取り処理します。 コンパイルの結果できた実行ファイルを実行すると次のレンダリング状態を(アスキーアートで)出力します。 次のコンパイルの時に、出力されたレンダリング状態とユーザーの入力を処理します。

このようにコンパイル時ゲームの場合は、メインループでコンパイルを延々と繰り返します。

疑問

相変わらず「何を言っているんだお前」状態かもしれません。

レンダリング(表示)状態の入力はどうやるの?

ただのテキストファイルを #include しているだけです。 *.h*.hpp ファイルでなく、 *.txt ファイルも普通に #include できます。 このゲームでは #include "current_state.txt" しています。

ユーザーの入力はどうやるの?

ただのマクロです。#define KEYBOARD_INPUT xxx 相当のことをどこかでやればいいです。

コンパイルをするメインループはどうするの?

作者も残念がっていますが Bash を使っています。 meta_crush_saga.sh がメインループに相当します。

Bash でキー入力を受け取り、その入力を元に g++ -DKEYBOARD_INPUT="$keypressed" して、外からKEYBOARD_INPUT マクロを定義しています。

C++17 テクニック

制限が緩和された constexpr が大活躍しています。

if constexpr により、SFINAE を使わず簡潔にコンパイル時分岐ができるようになりました。

constexpr 引数

残念なことに引数を constexpr にすることはできません。 引数は実行時にもコンパイル時にも使えるようにする必要があります。 引数を constexpr 相当にするにはどうしたらいいでしょうか?

どうやら constexpr ラムダでラップするといいようです。 一つのイディオムになっているようです。

constexpr

string や string_view などは constexpr 化するために自作したようです。

発展

saarraz が GCC 7.1 で static_print できるようにするパッチを書いたようで、これを使うとコンパイル時出力を行えるようになります。

コンパイル時入出力がリッチになれば、完全なコンパイル時ゲームも作れるようになるかもしれません。