C言語のプリプロセッサでFizzBuzz
alucky0707さんの下の2記事に触発されて(かつ参考にしながら)C言語のプリプロセッサだけでFizzBuzzを書いてみました。
インクルードファイルの階層の深さの制限とかは(事実上)なくなるようにしました。
- CPP(コンパイルしない方の関数型なC言語)プログラミング入門。とりあえずFizzBuzzまで - Qiita
- http://qiita.com/alucky0707/items/3599cdcf973382df978b
- C言語 - MSVCでもCPPでFizzBuzzしてみた - Qiita
- http://qiita.com/alucky0707/items/d4073a9a3af9a804477a
下のソースコードを普通にコンパイルしてできる実行可能ファイルを実行すると、1000までのFizzBuzzができます。
FizzBuzzの上限数を変えたい場合は、(例えば31415までやりたいとかだとすると)gccだと
$ gcc -D"FIZZBUZZ_MAX=31415" fizzbuzz.c
MSVCだと
> cl /DFIZZBUZZ_MAX=31415 fizzbuzz.c
とかでコンパイルすればいいと思います(ソースコード上は5桁までしか対応してないですが、適宜拡張すれば桁数はいくらでも増やせます)。
それではとりあえずソースコード全体です。
# ifndef __FIZZBUZZ__ # # define __FIZZBUZZ__ # # ifndef FIZZBUZZ_MAX # define FIZZBUZZ_MAX 1000 # endif # # define FIZZ_FLAG ((COUNTER % 3 == 0) && (0 < COUNTER)) # define BUZZ_FLAG ((COUNTER % 5 == 0) && (0 < COUNTER)) # # define c0 0 # define c1 0 # define c2 0 # define c3 0 # define c4 0 # # define TOSTRING_(x) #x # define TOSTRING(x) TOSTRING_(x) # define JOIN_(a, b) a##b # define JOIN(a, b) JOIN_(a, b) # # define ctr4 c4 # define ctr3 JOIN(c3, ctr4) # define ctr2 JOIN(c2, ctr3) # define ctr1 JOIN(c1, ctr2) # define ctr0 JOIN(c0, ctr1) # define COUNTER # # define DEPTH 0 # # endif # if c0 != 0 # undef COUNTER # define COUNTER ctr0 # elif c1 != 0 # undef COUNTER # define COUNTER ctr1 # elif c2 != 0 # undef COUNTER # define COUNTER ctr2 # elif c3 != 0 # undef COUNTER # define COUNTER ctr3 # else # undef COUNTER # define COUNTER ctr4 # endif # if DEPTH == 0 # #include <stdio.h> int main() { # # undef DEPTH # define DEPTH 1 # # undef c0 # define c0 0 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c0 # define c0 1 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c0 # define c0 2 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c0 # define c0 3 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c0 # define c0 4 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c0 # define c0 5 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c0 # define c0 6 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c0 # define c0 7 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c0 # define c0 8 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c0 # define c0 9 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c0 # define c0 0 # # undef DEPTH # define DEPTH 0 # return 0; } # # elif DEPTH == 1 # # undef DEPTH # define DEPTH 2 # # undef c1 # define c1 0 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c1 # define c1 1 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c1 # define c1 2 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c1 # define c1 3 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c1 # define c1 4 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c1 # define c1 5 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c1 # define c1 6 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c1 # define c1 7 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c1 # define c1 8 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c1 # define c1 9 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c1 # define c1 0 # # undef DEPTH # define DEPTH 1 # # elif DEPTH == 2 # # undef DEPTH # define DEPTH 3 # # undef c2 # define c2 0 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c2 # define c2 1 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c2 # define c2 2 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c2 # define c2 3 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c2 # define c2 4 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c2 # define c2 5 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c2 # define c2 6 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c2 # define c2 7 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c2 # define c2 8 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c2 # define c2 9 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c2 # define c2 0 # # undef DEPTH # define DEPTH 2 # # elif DEPTH == 3 # # undef DEPTH # define DEPTH 4 # # undef c3 # define c3 0 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c3 # define c3 1 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c3 # define c3 2 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c3 # define c3 3 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c3 # define c3 4 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c3 # define c3 5 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c3 # define c3 6 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c3 # define c3 7 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c3 # define c3 8 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c3 # define c3 9 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c3 # define c3 0 # # undef DEPTH # define DEPTH 3 # # elif DEPTH == 4 # # undef DEPTH # define DEPTH 5 # # undef c4 # define c4 0 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c4 # define c4 1 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c4 # define c4 2 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c4 # define c4 3 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c4 # define c4 4 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c4 # define c4 5 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c4 # define c4 6 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c4 # define c4 7 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c4 # define c4 8 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c4 # define c4 9 # if COUNTER <= FIZZBUZZ_MAX # include __FILE__ # endif # undef c4 # define c4 0 # # undef DEPTH # define DEPTH 4 # # elif DEPTH == 5 # # if FIZZ_FLAG && BUZZ_FLAG printf("FizzBuzz\n"); # elif FIZZ_FLAG printf("Fizz\n"); # elif BUZZ_FLAG printf("Buzz\n"); # elif 0 < COUNTER printf(TOSTRING(COUNTER)"\n"); # endif # # endif
以下適当に解説します。
カウンターは十進数の各桁に分割して管理します。
元のコードでは単にループして頑張って各桁の数字を書き換えるものでしたが、インクルードファイルの階層ごとに扱う桁を分けて深さ優先探索的なことをすることで事実上の制限をなくしました。
イメージ的にはこんなCのコードを実行している感じ。
fizzbuzz1()がalucky0707さんのFizzBuzzのイメージで、fizzbuzz2()が私のFizzBuzzのイメージです。
int c0 = 0; int c1 = 0; int c2 = 0; int c3 = 0; int c4 = 0; void counter(); // returns the value of the counter // alucky0707's fizzbuzz void fizzbuzz1() { if (c4 == 0) { c4 = 1; } else if (c4 == 1) { // // ... // } else if (c4 == 9) { c4 = 0; if (c3 == 0) { // // ... // } } // // write fizz buzz... // fizzbuzz1(); } // my fizzbuzz void fizzbuzz2(int depth) { if (depth == 0) { ++depth; c0 = 0; if (counter() <= FIZZBUZZ_MAX) fizzbuzz2(depth); c0 = 1; if (counter() <= FIZZBUZZ_MAX) fizzbuzz2(depth); // // ... // c0 = 9; if (counter() <= FIZZBUZZ_MAX) fizzbuzz2(depth); } else if (depth == 1) { ++depth; c1 = 0; if (counter() <= FIZZBUZZ_MAX) fizzbuzz2(depth); c1 = 1; if (counter() <= FIZZBUZZ_MAX) fizzbuzz2(depth); // // ... // c1 = 9; if (counter() <= FIZZBUZZ_MAX) fizzbuzz2(depth); } else if (depth == 2) { // // ... // } else if (depth == 5) { // // write fizz buzz... // } }
ちなみにこの方法だと、FizzBuzzできる最大数を制限するのはインクルードファイルの階層数よりももはや数値定数の最大値だとかコンパイル時間だとかそっちになってくると思います。
もっとコードを短くスマートにできるのかもしれませんが、私にはそのスキルはありませんでした。
コンパイル時実行バンザイ!