おはこんばんちは。
Yukiです。
今、ブレッドボードの空きが無く、電子工作出来ないので、今回はPCでプログラミングしてみようかなと思います。
今回やる言語はBrainf*ckです。
![](https://ssl-stat.amebame.com/pub/content/9477400408/amebapick/item/picktag_autoAd_301.png)
Brainf*ckとは
Brainf*ckとはプログラミング言語の一種で、たった8つの命令のみで書くことが出来る言語です。可読性が悪く、記述性も悪いため、実用性は無に等しいのです。
要は冗談プログラミング言語ですよね。
が、面白そうなのでやってみたいと思います。
なおBrainf*ckのF*ckでは英語圏の方からするとあまり使って良い言葉ではないため、伏せ字になっています。(Brainf**kとかも使われるみたいです)
Brainf*ckの入手(環境構築)
Hello Worldを実行する上で、欠かせないものがあります。
環境構築ですね。ただ、Brainf*ckはインタプリタとして配布しているので、すぐに始めることが出来ます。
上のサイトのBrainf*ck -> compiled -> win -> BFI.exeから入手することが出来ます。
またオンラインデバッガもあり、そちらも利用することが出来ます。
今回は、BFI.exeで実行しています。
Brainf*ckの基本
Brainf*ckは > < + - . , [ ] の8種類の記号を組み合わせる事でプログラミングします。
これらの詳しい説明はWikipediaに書いてあるので、今回は割愛します。
またこの記事はちょっと内容がわかりにくいので、詳しく知りたいのであれば、別の記事を参考にしたほうが良いと思います。
![](https://ssl-stat.amebame.com/pub/content/9477400408/amebapick/item/picktag_autoAd_301.png)
Hello Worldをとりあえず書いてみる
Brainf*ckはポインタが指す値の初期値は0となっています。
もう少し言い換えると、全ての変数は0ということです。
ということで、Brainf*ckでは、ポインタの指す値をインクリメント(つまり+1)とデクリメント(つまり-1)していけば、HELLO WORLD!が出力できるという意味です。
Brainf*ckではASCIIコードとにらめっこしながら、インクリメントしたりデクリメントしていきます。
ポインタが指す値のインクリメントは +
デクリメントは – で表すことが出来ます。
出力は . (ドット) で表すことが出来ます。
(ポインタアレルギーの人でC言語向け)
何らかの変数があるとします。今回はiとしたら、
Brainf*ckの+はi++に
-はi--に
.(ドット)はputchar(i); に相当します。
このことから、HELLO WORLD! は次のように表せます。
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.---.+++++++..+++.-----------------------------------------------.+++++++++++++++++++++++++++++++++++++++++++++++++++++++.--------.+++.------.--------.-----------------------------------.
これを動かすとこんな感じで出力されます。
Outputが見にくいので、メモ帳にコピーしています。
これをC言語に直すと
#include <stdio.h>
int main(void) {
int a = 0;
a += 72;
putchar(a);
a -= 3;
putchar(a);
a += 7;
putchar(a);
putchar(a);
a += 3;
putchar(a);
a -= 47;
putchar(a);
a += 55;
putchar(a);
a -= 8;
putchar(a);
a += 3;
putchar(a);
a -= 6;
putchar(a);
a -= 8;
putchar(a);
a -= 35;
putchar(a);
return 0;
}
となります。Brainf*ckって分かりやすーい(棒)
ループを使ったHの表示
ただ、これだと+とか-が多すぎて非効率です。
そこで、ループを使います。
ループは [ と ] を使います。
[ は ループ開始 ただし 0なら ] の後に飛ばす
]は閉じカッコに近いものですね。
Cに当てはめると
while (*p){ が [ に相当するという意味です。
(ポインタにアレルギー持っている人)
unsinged char data[255] = {0}; //全て0で初期化
while(data[0]){ と同じ意味(若干違うけど)です。
ただし、これだとwhileの前に繰り返す分のインクリメント(+)を置かなければならず、意味がありません。
そこで、ポインタそのものの値をずらすことで、より柔軟に扱えるようになります。
ポインタの値をずらすには、 < と > を使います。
C言語だと > は ptr++ に相当します。
また < は ptr-- に相当します。 (ただしptrはポインタ)
(ポインタアレルギーの人)
別の変数を使っていると思えばいいです。
例えば data[255]という変数があるとするならば、
>はdata[0]からdata[1] にするイメージです。
<はdata[1]からdata[0]にするイメージです。
例えば、Hを表示したい場合、HはASCIIで0x48(72)のため、
今回は72を 8×9に分解して考えます。
そしてそれらの値をそれぞれのポインタ(0番目と1番目 画像ではptr1とptr2)に突っ込んであげます。そして、ループの中で引いてあげて、その中でptr3をインクリメントしてあげると出来ます。(難解)
ということで、これらをまとめると次のようになります。
++++++++[>+++++++++[>+<-]<-]>>.
なんと+だけで組むと72回も必要だったのが、出力含めて31文字まで短縮できました。
ちなみにWikibookさんによると、次のやり方でも作れるみたいです。
-[>+<-------]>-.
16文字!? となりますが、たしかにこれでも正常に出力されますねぇ。
1つ目のレジスタ(ptr1)をデクリメントして、255にする。その後7で引いていくことで、73回でループを抜けると言う意味ですね。しかもこれ、255で7引いていくと、もう一度オーバーフローするので、2回目のオーバーフローでループを抜けると言うことですよね。考えた人変態ですよこれ。(褒め言葉)
ちょっとWikibookさんはレベルが違いますが、今回もC言語に直してみたいと思います。
もちろん++++++++[>+++++++++[>+<-]<-]>>. ですよ。
やっぱりCって神ですね。このわかりやすさですよ。
#include <stdio.h>
int main(void) {
unsigned char data[255] ={0};
data[0] += 8;
while(data[0]){
data[1] += 9;
while(data[1]){
data[1]--;
data[2]++;
}
data[0]--;
}
putchar(data[2]);
return 0;
}
![](https://ssl-stat.amebame.com/pub/content/9477400408/amebapick/item/picktag_autoAd_301.png)
ループなどを組み合わせてHELLO WORLD!を作る
いよいよ作りたいと思います。
まあ私はそこまで頭良くないので、普通の方法で行きます。
++++++++[>+++++++++[>+<-]<-]>>.
これでHを表示します。この時点で ptr1とptr2は0 , ptr3は0x48(72)が入っています。
次はEですが、H(72)とE(69)の差が3しかないので、ここは手打ちします。
---.
つぎにLですが、L(76)はE(69)で差が7 ということでこれも手打ちします。
+++++++..
次にL(76)とO(79)なのでこれも手打ちです。(手打ちしかしてないですねはい)
+++.
次に空白ですが、空白(32)とO(79)は47も差があるので、これは使います。
今回は7×7 = 49 として最後に2プラスします。
<+++++++[<+++++++[>>-<<-]>-]>++.
難読すぎる!
次に空白(32)からW(87)まで飛ばします。差は55です。これは7×8を使います。
<+++++++[<++++++++[>>+<<-]>-]>-.
上のやつとそっくりですね。
次にW(87)からO(79)です。差は8です。8ならデクリメントを使えば出来ますが、どうせなら2×2×2でやってみようと思います。
<++[<++[>>>++[<->-]<<<-]>-]>.
8より多くなってるじゃん!ってツッコミはなしで。
次にO(79)からR(82)です。差は3です。ここは素直にインクリメントします。
+++.
次にR(82)からL(76)です。差は6です。ここはふざけて2×3で
<++[<+++[>>-<<-]>-]>.
次にL(76)からD(68)ですね。ここも8ですが、先程とはパターンを変えて2×4でやってみようと思います。
<++[<++++[>>-<<-]>-]>.
ここまで来るとサラサラと書けるようになります。人間ってすごい。(自分でも驚いています)
最後にD(68)と!(33)です。差が35なので、普通に5×7にしてみようと思います。
<+++++[<+++++++[>>-<<-]>-]>.
最後とか、5秒位で書けましたよ。慣れってすごい。
まあ掛け算はある程度型が決まっているからかもしれないですけどね。
最終的には、全部繋げてこんな感じになります。
++++++++[>+++++++++[>+<-]<-]>>.---.+++++++..+++.<+++++++[<+++++++[>>-<<-]>-]>++.<+++++++[<++++++++[>>+<<-]>-]>-.<++[<++[>>>++[<->-]<<<-]>-]>.+++.<++[<+++[>>-<<-]>-]>.<++[<++++[>>-<<-]>-]>.<+++++[<+++++++[>>-<<-]>-]>.
量的にはそこまで変わっていないという。
こんな感じで一応動きます。
まあ定例なんで、C言語でも書き直しますか。
#include <stdio.h>
int main(void) {
unsigned char data[255] = {0};
data[0] += 8;
while(data[0]){
data[1] += 9;
while(data[1]){
data[1]--;
data[2]++;
}
data[0]--;
}
putchar(data[2]);
data[2] -= 3;
putchar(data[2]);
data[2] += 7;
putchar(data[2]);
putchar(data[2]);
data[2] += 3;
putchar(data[2]);
data[1] += 7;
while(data[1]){
data[0] += 7;
while(data[0]){
data[2]--;
data[0]--;
}
data[1]--;
}
data[2] += 2;
putchar(data[2]);
data[1] += 7;
while(data[1]){
data[0] += 8;
while(data[0]){
data[2]++;
data[0]--;
}
data[1]--;
}
data[2]--;
putchar(data[2]);
data[1] += 2;
while(data[1]){
data[0] += 2;
while(data[0]){
data[3] += 2;
while(data[3]){
data[2]--;
data[3]--;
}
data[0]--;
}
data[1]--;
}
putchar(data[2]);
data[2] += 3;
putchar(data[2]);
data[1] += 2;
while(data[1]){
data[0] += 3;
while(data[0]){
data[2]--;
data[0]--;
}
data[1]--;
}
putchar(data[2]);
data[1] += 2;
while(data[1]){
data[0] += 4;
while(data[0]){
data[2]--;
data[0]--;
}
data[1]--;
}
putchar(data[2]);
data[1] += 5;
while(data[1]){
data[0] += 7;
while(data[0]){
data[2]--;
data[0]--;
}
data[1]--;
}
putchar(data[2]);
return 0;
}
意味分からないです。
ただ、一応これでも動くという凄さ。
だってprintf(“HELLO WORLD!”);
だけで動くプログラムが102行ですよ。なんて難読性なんでしょう。
ちなみにこのプログラムは = 単体は最初以外使っておらず、それ以外は複合演算子と
インクリメント・デクリメント演算子しか使ってません。(つまり += とか -= とか ++とか -- ですね)
複合演算子はずるい!って思うかもしれませんが、実質 i += 3とかだったら
i++;
i++;
i++;
と同じですからね。
ちなみにWikibookさんによるとたったこれだけで動くらしいです。(難解過ぎる)
++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.
![](https://ssl-stat.amebame.com/pub/content/9477400408/amebapick/item/picktag_autoAd_301.png)
終わりに
非常に難読で、頭が痛くなりそうでした。
ただ、非常に面白い! パズルとかそれに近いのかもしれません。
次もしやるとしたら、条件とか面白いかもなと思っています。
おわり。