はじめに
皆さん、Brainfuckというプログラミング言語は知っていますか?和訳すると大変なことになってしまいますが、言語名の由来は、可読性が低すぎる(コードが見づらい)ために、頭がイかれるというのが意味でBrainfuckという名前が付いています。(出典)
そもそも可読性が低いとはどういうことか、簡単に説明したいと思います。
例
"Hello, World"を出力してください。
Python:
print("Hello, World")
C++:
#include<iostream>
using namespace std;
int main(){ //ここまでおまじない
cout << "Hello, World" << endl;
}
プログラミング言語をほとんど知らない人でも、ぱっと見てなんとなくは何が起きるかわかると思います。
では、ここでBFのコード例を見てみましょう。
Brainfuck:
+++++++++[>++++++++<-]>.
<+++++++++[>+++<-]>++.+++++++..
+++.
<+++++++++[>-------<-]>----.
<+++++++++[>-<-]>---.
<+++++++++[>++++++<-]>+.
<+++++++++[>++<-]>++++++.
+++.
------.
--------.
これの意味が一瞬でわかった人は言語界の天才かキチガイです。
この言語のことが少しでも理解できるように解説していきます。
この言語の凄い所
まず、この言語には8文字しか使われません。上の"Hello, World"のコードを見てください。
[]<>+-.,
","は今回使っていませんが、たったこれだけの文字でコードが書けてしまうんです。凄くないですか??
さらに、BFはチューリング完全な言語です。つまり、プログラムで処理できる仕事はどんなことでもこの言語で書くことができます。C++やPythonなんていらなかったんや
この言語のヤバい所
はい、この言語はハッキリ言って、マゾが勉強する言語です。意味不明なレベルで難しいです。
- その1:数値が256までしか保存できない
まず、BFはどのようにデータを保存しているかを理解しなければいけません。BFでは、メモリにASCIIコードの16進数で保存されます。例えば、"A"という文字はASCIIコードでは65、16進数ではで保存されています。
イメージ
41 42 00 00 00 00 .....
"A" "B" 初期状態...
上記イメージの通り、メモリは二桁の16進数で記録されます。16進数の二桁で最大の数は、255を超えるとになってしまいオーバーフローします。
00から-1した場合もオーバーフローしてになってしまいます。1000なんて論外。めっちゃ不便。
- その2:計算結果が出力できない
ここで、簡単な一桁+一桁の計算をしてみましょう。
3+5=8
今、メモリには8という値が保存されました。
イメージ
08 00 00 00 00 00 .....
これを"8"と出力するのは、簡単です。8のASCIIコードであるになるように数字を足してあげれば、この計算結果がめでたくASCIIコードの数字に変換されて保存できました。
イメージ
08 00 00 00 00 00 .....
↓(ASCIIに戻す)
38 00 00 00 00 00 .....
"8"
さて、次の問題です。
5+7=12
今、メモリにはという値が保存されました。
イメージ
0c 00 00 00 00 00 .....
ここからどうやって"12"と出力しましょうか?ASCIIコードには1や2はありますが、12は存在しません。つまり、12と出力するためには01 02
のように保存されていないといけません。
出力するときに最適なイメージ
01 02 00 00 00 00 .....
↓(ASCIIに戻す)
31 32 00 00 00 00 .....
"1" "2"
しかし、上記結果のように、二桁に分ける必要がある場合と無い場合の二通りがあると、この言語は混迷を極めます。
「A%10で10で割った余りを出力して、A/10で10の位を出力すればいいじゃない」と他言語をやったことがある人なら思うかもしれません。
そう、他の言語にとってこの程度全く苦にすらなりませんが(そもそも足し算結果そのまま出力できる)、この言語はわけが違います。たった8文字しかないうえに簡単にオーバーフローする言語が割り算できると思いますか?普通に無理です。
今の結果が二桁なのか、一桁なのかを簡単に判別する方法がありません。ありえん不便。
- その3:入力も大変
BFはASCIIコードを使う関係で、入力も全て一文字ずつしか受け取れません。
例えば、4桁の数列を読み込めるように4回入力を受け付けたとします。しかし、3桁のデータしか渡されなかった場合、たまにバグります。一桁ずつなのでそれを元の入力された数字に戻すのも一苦労。何桁かわからないと普通にヤバいです。まあ256以上の数字扱いにくくて無理なので高々3桁しかやらないけれども
イメージ
入力:194
31 39 34 ?? 00 00 .....
"1" "9" "4" ↑バグる(Nullなので普通は0)
- その4:人のコードが読めない
自明。「ここでif文が~」なんて言われても理解できません。もはや自然にできた暗号レベルなので、人のコードを理解しようなんて思わない方がいいです。そもそもif文とかfor文自体普通に書けないけど。 - その5:数字のコピーも大変
この言語では、基本的に数字を保存したままの処理が難しいです。
この言語で使用する"[","]"はwhile文を意味するのですが(また別の時に説明します。今回はそう言う意味だと思っててください)、このwhile文を終わらせるには必ず数字を0にしないといけません。
イメージ
31 00 00 00 .....
↓
31 31 00 00 ....
にしたい
(BF)
[処理A(隣に数字をコピーする)]
イメージ
31 00 00 00 .....
↑ここの数字が0でない限り処理Aを実行します
.......
while文が終わった時
00 31 00 00 ....
↑元あった場所からはデータが消えてしまう
もちろん対策はあるのですが、少なくとも気軽に"tmp=a"のようにコピーが出来ないと言うのは大きな問題ですね。
この言語のメリット
ありません。強いて言うならチューリングテープというプログラミングの原点の考えに非常に似ているので、その勉強になることと、いかにC++やPythonが書きやすく偉大かを嫌というほど理解させてくれます。†C++やPythonは偉大†
いや、ほんと割り算のライブラリとか、256までの出力ライブラリ自作なの意味不明ですから・・・
最後に
マジでただの愚痴ですね、これ。本当はもう少し進めて「本当はできる複数桁の出力!」なんて記事出そうと思ったのですがあまりにも長くなりそうなので次回にします。
この言語はとても面白いので、ぜひ挑戦してみてね。
+++++++++[>++++++++<-]>++++.<+++++++++[>++<-]>+++++++.<+++++++++[>+<-]>++++++.<+++++++++[>--------<-]>-----.<+++++++++[>++++++++<-]>++++.<+++++++++[>---------<-]>--.<+++++++++[>+++++++<-]>++++.+++++.-------.<+++++++++[>+<-]>++..-------.<+++++++++[>+<-]>.-------.--.<+++++++++[>-------<-]>-----.