FizzBuzzのcodegolfを世界一分かりやすく解説！#c言語 

# はじめに
codegolf ShortCodingと聞くと、「何してるかわかんない」「見にくい」「意味ない」等マイナスなイメージが付きがちですが、そんなことはありません！
確かに見にくいのは事実。通常であれば誰もが理解出来るコードを書くべきです。（自分も普段はそう書いてます。）
しかしコードを短くすることは簡単ではありません。ただ見にくくすれば良いわけではありません。
データ構造・アルゴリズム・処理の観点から探求し、コードを短くするためにありとあらゆる知識を使います。
コードを短くするには想像以上の知識、そして発想力が求められるのです。
日々の生活等に役に立つかと言われたら微妙です、ですが考え方や言語への理解、そして熱き精神が必ずあなたを成長させます。
今までの先入観を捨て是非楽しんでいってください。
あくまでも遊びの一つです、実際のコードでは見やすく分かりやすく書いてください。

# 短縮する元のコード
Wikipediaを参照してください。
https://ja.wikipedia.org/wiki/Fizz_Buzz
今回はこのWikipediaのサンプルコードを短くしていきます。

``` c:280byte
#include <stdio.h>
int main(void) {
	int i;
	for (i = 1; i <= 100; i++) {
		if (i % 3 == 0 && i % 5 == 0) {
			printf("FizzBuzz\n");
		} else if (i % 3 == 0) {
			printf("Fizz\n");
		} else if (i % 5 == 0) {
			printf("Buzz\n");
		} else {
			printf("%d\n", i);
		}
	}
	return 0;
}
```
最終的にはこうなります。順を追って短くして行きましょう！

``` c:74byte
main(i){for(;i<101;puts(i++%5?"":"Buzz"))printf(i%3?i%5?"%d":0:"Fizz",i);}
```

# 実際に短くしてみよう
codegolfをするにあたりErrorを大量に吐きますが、動けば問題無いので無視してOKです。
短くするためならセキュリティ面も気にしなくていいので`gets`等の関数も積極的に使っていきましょう。
バージョンはgcc version 6.3.0です。

## gccを使おう
c言語でcodegolfをするならgccがおすすめです。
gccは破茶目茶なコードを書いても無理やりバイナリを生成してくれるので、例外はありますが基本的に1番短くなります。

## 基本的な削りから
それでは削れるところから削っていきます。
まず簡単なところから、

>### スペースを詰める
>改行は後から削った方が理解しやすいので、いつも後回しにしています。

</bloacqate>

>### `return 0;`を削ります。
>C99は`main`関数で`return`文を省略すると自動的に`0`を返すので必要ありません。

</bloacqate>

>### `#include <stdio.h>`を削ります。
>`#include`を省略するとErrorを吐きますが動きます。おまけに型の判定がゆるくなります。

</bloacqate>

>### `int main(void)`を削ります。
>`main`というシンボルさえ定義されていれば動きます。
>なので`main()`で動きます。

</bloacqate>

>### `int i`の場所を工夫する
>gccではグローバル変数の型を省略するとint型になります。
>さらにグローバル変数の初期値を省略すると`0`になります。

</bloacqate>

### 省略出来る場所を消すだけでこんなに短くなります

``` c:198byte
i;main(){
	for(i=1;i<=100;i++){
		if(i%3==0&&i%5==0){
			printf("FizzBuzz\n");
		}else if(i%3==0){
			printf("Fizz\n");
		}else if(i%5==0){
			printf("Buzz\n");
		}else{
			printf("%d\n",i);
		}
	}
}
```

## ちょっと頭をひねってみる

>### `3`かつ`5`で割れる時、実質`15`で割れる時なのでそこをまとめます。
``` c:Before
if(i%3==0&&i%5==0){
```
``` c:After
if(i%15==0){
```

</bloacqate>

>### 条件式を変える
>`i<=100`を`i<101`にすると1byte省略されます

</bloacqate>

>### インクリメントと条件式をまとめる
>`i<101;i++`を`++i<101`にするとまずインクリメントされてから条件判断します。
>ちなみに`i++<101`にすると条件判断した後にインクリメントをします。この使い分けが出来ると1byte減ったりするので完全に理解しましょう。
>条件判断の前にインクリメントするので初期値は`0`になります、gccでグローバル変数の初期値を省略すると`0`になるので、初期値設定を省略出来ます。

### 10byte以上短くなる

``` c:186byte
i;main(){
	for(;++i<101;){
		if(i%15==0){
			printf("FizzBuzz\n");
		}else if(i%3==0){
			printf("Fizz\n");
		}else if(i%5==0){
			printf("Buzz\n");
		}else{
			printf("%d\n",i);
		}
	}
}
```

>#### codegolferは`for`を使う
>`for`文の中を書かなくても動きます。むしろ別の式をぶっこめるので`while`は使っては行けません、`for`を使いましょう。
>
``` c:Before
printf("Hello, World");
for(;i<10;){
	printf("Hello, World");
}
```
``` c:after
for(printf("Hello, World");i<10;printf("Hello, World"));
```
>
>`for`と`while`のbyte数も同じです。
>
>``` c:byte数が一緒
>while()
>for(;;)
>```
>
>``` c:無限ループならforのが短い
>while(1)
>for(;;)
>```

## ifは使わない
codegolfする際に`if`文は使いません。三項演算子か論理演算子の二択です。
この2種類を場合によって使い分けましょう。

>### 三項演算子とは
>`条件式 ? true文 : false文;`なので`if`文と対して変わりません、ただし三項演算子は式だということを忘れないでください。
>三項演算子は式なので結果を代入したり、`printf`の中にぶっこんだり出来ます。そこが最大の強みです。
>ちなみに三項演算子の`true文`のところは`()`が入りません、覚えておくと役に立ちます。

>``` c:全て同じ結果
>if(i==5){puts("true");}else{puts("false");}
>i==5?puts("true"):puts("false");
>puts(i==5?"true":"false");
>```

</bloacqate>

>### 論理演算子の仕様
>論理演算子は左を判断したあとに右を判断します。
>AND演算子は左側が`false`の時、右側を評価しません。
>OR演算子は左側が`true`の時、右側を評価しません。
>なので`if`文と同じ使い方が出来ます。

>``` c:イコールの時
>if(i==5){puts("true");}
>i==5&&puts("true");
>```
>``` c:ノットイコールの時
>if(i!=5){puts("false");}
>i==5||puts("false");
>```

### 遂に100byteを切る
今回は`if`文を三項演算子に変更します。

``` c:139byte
i;main(){
	for(;++i<101;){
		i%15==0?printf("FizzBuzz\n")
			:i%3==0?printf("Fizz\n")
			:i%5==0?printf("Buzz\n")
			:printf("%d\n",i);
	}
}
```

さらに`printf`の中に式をぶっこみます。
`for`文は一行ならブレースが要らないのでそこも省略し、改行を消します。

``` c:99byte
i;main(){
	for(;++i<101;)
		printf(i%15==0?"FizzBuzz\n":i%3==0?"Fizz\n":i%5==0?"Buzz\n":"%d\n",i);
}
```

``` c:94byte
i;main(){for(;++i<101;)printf(i%15==0?"FizzBuzz\n":i%3==0?"Fizz\n":i%5==0?"Buzz\n":"%d\n",i);}
```

100byteを切りましたね！まだまだ詰めていきます。

## ド・モルガンの法則、`true` `false`について

>### ド・モルガンの法則

>``` c:ド・モルガンの法則
>!(P || Q) == !P && !Q
>!(P && Q) == !P || !Q
>```

>ド・モルガンの法則ってどう使うの？と思ったあなた。

>``` c:全て同じ
>!(P != 0 && Q != 0)
>!(!(P == 0 || Q == 0))
>P == 0 || Q == 0
>```

>ド・モルガンの法則を使用するとコードがスッキリするので普段使いも出来ます！

</bloacqate>

>### 条件式の仕様について
>条件式は`0`なら`false`、`!0`なら`true`。
>`P!=5`とは、`P`が`5`以外なら`true`、要するに`P`が`5`なら`false`。
>`P-5`は`0`、`0`は`false`、要するに`P!=5`と`P-5`が同じ。

>``` c:全て同じ
>P==5&&puts("")
>P!=5||puts("")
>P-5||puts("")
>```

>``` c:全て同じ
>P==0?true:false
>P!=0?false:true
>P?false:true
>```

>このようにド・モルガンの法則を利用したり、条件式の仕様を理解する事でコードが短くなります。

</bloacqate>

>### 今回のコードでは
>``` c
>printf(i%15==0?"FizzBuzz\n":i%3==0?"Fizz\n":i%5==0?"Buzz\n":"%d\n",i);
>```
>中の三項演算子でド・モルガンの法則をしてみます。
>一旦、理解し難いので`if`文に戻します。
>
``` c
if (i % 15 == 0) {
	printf("FizzBuzz\n");
} else if (i % 3 == 0) {
	printf("Fizz\n");
} else if (i % 5 == 0) {
	printf("Buzz\n");
} else {
	printf("%d\n", i);
}
```
>
>ド・モルガンの法則でnotにしてみます。
>
``` c
if (i % 15 != 0) {
	if (i % 3 != 0) {
		if (i % 5 != 0) {
			printf("%d\n", i);
		} else {
			printf("Buzz\n");
		}
	} else {
		printf("Fizz\n");
	}
} else {
	printf("FizzBuzz\n");
}
```
>
>`!=0`は`0`じゃない場合は`true`、なので`!=0`を消しても動きます。
>
``` c
if (i % 15) {
	if (i % 3) {
		if (i % 5) {
			printf("%d\n", i);
		} else {
			printf("Buzz\n");
		}
	} else {
		printf("Fizz\n");
	}
} else {
	printf("FizzBuzz\n");
}
```
>
>三項演算子に戻します。
>
>``` c
>i%15?i%3?i%5:printf("%d\n",i):printf("Buzz\n"):printf("Fizz\n"):printf("FizzBuzz\n")
```
>
>`printf`に入れ直します。
>
>``` c
>printf(i%15?i%3?i%5?"%d\n":"Buzz\n":"Fizz\n":"FizzBuzz\n",i);
>```

### 更に減ったコード
85byteまで減りました。

``` c:85byte
i;main(){for(;++i<101;)printf(i%15?i%3?i%5?"%d\n":"Buzz\n":"Fizz\n":"FizzBuzz\n",i);}
```

## 1byte減らすのに頭を使う
ここから先はとても分かりにくく、難しくです。
むしろ、ここからが本番です。頑張りましょう。

>### `15`ではなくす
>最初の方に`3`かつ`5`で割れる時、実質`15`で割れる時と言いました。
>確かに`&&`を使うなら`15`にしたほうが短いです、ですが下のようにするとどうでしょう？
>
>>`3`で割れて`5`で割れる`FizzBuzz`。
>>`3`で割れて`5`で割れない`Fizz`。
>>`3`で割れずに`5`で割れる`Buzz`。
>>`3`で割れずに`5`で割れない数字。
>
>こうすると`15`も`&&`使ってないので1byte短く出来ます！

</bloacqate>

>### アルゴリズムを作り直す
>同じく理解し難いので`if`文に戻します。
>
``` c
if (i % 15) {
	if (i % 3) {
		if (i % 5) {
			printf("%d\n", i);
		} else {
			printf("Buzz\n");
		}
	} else {
		printf("Fizz\n");
	}
} else {
	printf("FizzBuzz\n");
}
```
>
>並び替えます。
>
``` c
if (i % 3) {
	if (i % 5) {
		printf("%d\n", i);
	} else {
		printf("Buzz\n");
	}
} else {
	if (i % 5) {
		printf("Fizz\n");
	} else {
		printf("FizzBuzz\n");
	}
}
```
>
>三項演算子に戻し、`printf`に入れ直します。
>
>``` c
>printf(i%3?i%5?"%d\n":"Buzz\n":i%5?"Fizz\n":"FizzBuzz\n",i);
>```

### 1byte減りました
``` c:84byte
i;main(){for(;++i<101;)printf(i%3?i%5?"%d\n":"Buzz\n":i%5?"Fizz\n":"FizzBuzz\n",i);}
```
>#### 別解
>改行するのに通常`\n`を使いますが、`puts`は自動的に改行をしてくれるので、`puts`で何も出力しなければただ改行します。
>`printf`をしたあとに`puts`で何も出力しなければ、`printf`のなかでわざわざ`\n`を4回も書かなくて済みます。
>今回はbyte数が同じですが、場合によっては短くなります。
>
>``` c:84byte
>i;main(){for(;++i<101;puts(""))printf(i%3?i%5?"%d":"Buzz":i%5?"Fizz":"FizzBuzz",i);}
>```

## FizzBuzzを省略したい
``` c
printf(i%3?i%5?"%d\n":"Buzz\n":i%5?"Fizz\n":"FizzBuzz\n",i);
```

`Fizz`と`Buzz`が2回書いてあるのを省略したくありませんか？
頑張って省略してみます。

> ### 2回出力にしてFizzBuzzを分割する
>
>`if`文に戻します。
>
``` c
if (i % 3) {
	if (i % 5) {
		printf("%d\n", i);
	} else {
		printf("Buzz\n");
	}
} else { // ← ここ
	if (i % 5) {
		printf("Fizz\n");
	} else {
		printf("FizzBuzz\n");
	}
}
```
>ここの`else`で分割出来そうじゃないですか？
>分割してみます。
>
``` c
if (i % 3) {
	if (i % 5) {
		printf("%d", i);
	} else {
		printf("");
	}
} else {
	printf("Fizz");
}
>
if (i % 5) {
	puts("");
} else {
	puts("Buzz");
}
```
>
>1回目の`if`は`Fizz`の方の処理をしていて、2回目の`if`は`Buzz`の方の処理をしています。
>詳しく説明します。

</bloacqate>

>### 各パターンでの流れです。
>
>>#### `FizzBuzz`の場合
>>1回目の`if`では、`3`で割れるので`Fizz`を出力します。
>>2回目の`if`では、`5`で割れるので`Buzz`を出力します。
>
></bloacqate>
>
>>#### `Fizz`の場合
>>1回目の`if`では、`3`で割れるので`Fizz`を出力します。
>>2回目の`if`では、`5`で割れないのでなにも出力しません。
>`puts`で何も出力しないので改行だけされます。
>
></bloacqate>
>
>>#### `Buzz`の場合
>>1回目の`if`では、`3`で割れなくて`5`で割れるのでなにも出力しません。
>>`printf`なので改行しません。
>>2回目の`if`では、`5`で割れるので`Buzz`を出力します。
>
></bloacqate>
>
>>#### 数字の場合
>>1回目の`if`では、`3`で割れなくて`5`で割れないので数字を出力します。
>>2回目の`if`では、`5`で割れないのでなにも出力しません。
>
>何も出力しないのを挟むことで、2回に出力を分割出来ました。

</bloacqate>

>### コードに戻してみる
>
>まずは三項演算子に戻します。
>
>``` c
>i%3?i%5?printf("%d",i):printf(""):printf("Fizz");
>i%5?puts(""):puts("Buzz");
>```
>
>次に`printf` `puts`に入れ直します。
>
>``` c
>printf(i%3?i%5?"%d":"":"Fizz",i);
>puts(i%5?"":"Buzz");
>```

### ほぼほぼ完成系
``` c
for(;;puts(i%5?"":"Buzz"))printf(i%3?i%5?"%d":"":"Fizz",i);
```

`for`の間に入れることで`;`を1つ省略しています。

``` c:76byte
i;main(){for(;++i<101;puts(i%5?"":"Buzz"))printf(i%3?i%5?"%d":"":"Fizz",i);}
```

## 極限まで減らす
もう減らせる場所がなさそうですが実はまだあります。

>### `printf(0);`
>`printf(0);`とやると何も表示されません。
>ですが何も出力していないから何も表示されていないのではなく、エラーが起きています。
>実は`printf`には戻り値があります。戻り値は出力された文字数で、エラーの場合は負の値が返されます。
>
``` c
int i = printf("abc\n");
printf("%d\n", i); // 4
>
int j = printf(0);
printf("%d\n", j); // -1
>
int k = printf(0, "abc\n");
printf("%d\n", k); // -1
```
>
><img width="137" alt="printf_error.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/218691/57b59a2e-7550-139f-ef9e-8e8e42579e0f.png">
>
>
>なので今回は`""`を`0`に変えます、これで1byte。
>
>``` c:Before
>printf(i%3?i%5?"%d":"":"Fizz",i);
>```
>``` c:After
>printf(i%3?i%5?"%d":0:"Fizz",i);
>```

</bloacqate>

>### `i`のインクリメント
>グローバル変数の型を省略するとint型になり、初期値を省略すると`0`になるというのは、先程説明しました。
>実は初期値を`1`にする方法もあります。
>
>``` c
>main(i){printf("%d",i);} // 1
>```
>`main`の第1引数は`argc`です。`argc`はコマンドラインに記述されたパラメータの数を格納します。
>プログラム自体も数えられるので、引数を渡さない場合`1`になります。
>初期値が`1`で行けるなら下のほうが1byte短いです。
>
>``` c:初期値が0
>i;main(){}
>```
>``` c:初期値が1
>main(i){}
>```
>
>>引数の数を増やすと`argc`の数が増えます。
>>
>>``` c
>>main(i){printf("%d",i);}
>>```
>>
>><img width="171" alt="argc.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/218691/7ffc4080-d109-1b31-1090-8c5fe7f9d5fa.png">
>
>今までは`i`の初期値が`0`で、インクリメントしたあとに条件判断でした、なので`i`の初期値を`1`にして、条件判断した後にインクリメントすれば、1byte短く出来ます。
>`++i<101`を`i++<101`にしても`printf`の中身で`i`を使用しているので駄目です、全ての処理をした後にインクリメントしなければなりません。
>`printf`と`puts`を分割したので`puts`の条件判断の後にインクリメントすれば、全ての処理をした後にインクリメント出来ます！
>
>``` c:Before
>i;main(){for(;++i<101;puts(i%5?"":"Buzz"))printf(i%3?i%5?"%d":"":"Fizz",i);}
>```
>``` c:After
>main(i){for(;i<101;puts(i++%5?"":"Buzz"))printf(i%3?i%5?"%d":"":"Fizz",i);}
>```

## 完成
お疲れ様です。
長い戦いがこれで終了です。
今までを振り返りながら見ると完成したコードは自明です。

``` c:74byte
main(i){for(;i<101;puts(i++%5?"":"Buzz"))printf(i%3?i%5?"%d":0:"Fizz",i);}
```

>最少は73byteなんですが自分の環境では自分の環境だと上手く動きませんでした。(gcc version 6.3.0)
>
>``` c:73byte
>main(i){for(;i<101;puts("Buzz"-i*i++%5))printf(i%3?i%5?"%d":0:"Fizz",i);}
>```

# 最後に
1つ1つ丁寧に説明したらとても長くなってしまいました。
これをきっかけに是非codegolfに挑戦してみて下さい。
色んなFizzBuzzのcodegolfが見れるのでこちらの記事も是非見て下さい。
[FizzBuzzを1byteで実装する](https://qiita.com/ymg_aq/items/b8e5d26035180bc8797e#_reference-47928755625956643f7b)

# 参考文献
[ShortCoding職人達の技法](https://www.amazon.co.jp/dp/4839925232)