FizzBuzzプログラムがはやっているらしい。プログラミング言語Cではどれくらいになるのか、ざっと考えてみた。
ロジックを動かすだけでそれなりにコードが必要なので、30バイトというのは無理そうです。「FizzBuzzを30byteで作る方法 – 何気に大変」といった解もあるようですから、Cで同様のことをするなら専用ライブラリを用意してそれを使うということになりますが、それだと課題としてはどうかな、という気がします。インタプリタ系の言語でも30バイトは厳しいという声があるようです。
#include <stdio.h>
#define f printf("Fizz")
#define b printf("Buzz")
#define n printf("\n")
#define d(i) printf("%d", i)
$ cat a.c
#include "a.h"
void main(){int i=0;while(i++<100){int c=2;i%3?c++:f;i%5?c++:b;c%4?:d(i);n;}}
$ ls -l a.* | grep -v "a.out" |awk '{printf("%d\t%s\n",$5,$8);}'
93 a.c
122 a.h
3項演算子を使うと、こんな感じにできます。
#include <stdio.h>
void main(){int i=0;while(i++<100){i%15?i%3?i%5?printf("%d\n",i):puts("Buzz"):puts("Fizz"):puts("FizzBuzz");}}
$ ls -l b.c |awk '{printf("%d\t%s\n",$5,$8);}'
131 b.c
比較的わかりやすいロジックで書くと、こんな風にもできますね。
void main(){
int i=0;
while(i++<100){
char* a=i%15?i%5?i%3?0:"Fizz":"Buzz":"FizzBuzz";
a?puts(a):printf("%d\n",i);
}
}
いろいろ調べてみると、73バイトとかでできるらしいですが、どうやっているんですかねぇ。プログラミング言語Cだと「void main(){int i=0;while(i++<100){}}」これで37バイト。30バイトは軽くオーバー。stdio.hをインクルードしたら +19バイトですからね。56バイトは使います。これに、Fizz, Buzz, 文字列囲むダブルクォートを追加すると、12バイト追加。68バイト。残り5バイトでどうやったのだろう。すごいな。
関数とか使えばいくらでも可能なので、ちょこっと試してみました。汚いコードですが… 。しかし、stdio.hインクルードしてmain関数から関数fを呼ぶだけで 36バイトですから、プログラミング言語Cを選んでいる時点でアウトだということです。
#include <stdio.h>
#include <string.h>
char* pb;
char b[9];
void g(char* s) {
strcpy(pb, s); pb += 4;
}
void d(int i) {
sprintf(b, "%d", i);
}
void f() {
int i=0;
while (i++<100) {
pb = b;
i%3?:g("Fizz");
i%5?:g("Buzz");
pb!=b?:d(i);
puts(b);
}
}
void main(){f();}
//3456789012345678901234567890
文字列の連結が肝ですから、「i%3?””:”Fizz”」とか「i%5?””:”Buzz”」とかがもっとシンプルに表現できて、これらの結果を文字連結できて、かつその結果が空文字のときに数字を出力できるみたいな機能を持った言語があればできそうですが、やはり30バイトは厳しそうです。だって… 普通に使うだろう文字を出してみると、使えるのは16バイトですからね…。
xxxxxxxxxxxxxxxx3Fizz5Buzz0100
ところで、bashが気になっていたのですが、これみたいですね。すごいな。