😺

BrainFuckでHello Worldする

2024/09/06に公開

BrainFuck

BrainFuckは、1993年にUrban Müllerによって開発された、極めてシンプルで難解なプログラミング言語です。
BrainFuckは教育的な目的やプログラミングの楽しみとして使われることが多く、実際のソフトウェア開発に使われることはほとんどありません。

なぜBrainFuckを触るのか

なぜなら、触っててパズル的な楽しさがあるからです。
無理やりソフトウェア開発者にとってもメリットを出すとすれば、コンピュータサイエンスの基礎を深めるためにチューリングマシンについて学ぶ助けになると思います。
BrainFuckのメモリテープとポインタの動きは、チューリングマシンのテープとヘッドの動きに直接対応します。このため、BrainFuckのプログラムを書くことで、チューリングマシンの動作原理を実践的に理解することができます。

BrainFuckでできること

BrainFuckには8つの命令しかありません。これらの命令はシンプルで、メモリのポインタ移動と入力・出力の基本操作だけを行います。
8つの命令は以下の通りです:
> : メモリポインタを右に1つ移動
< : メモリポインタを左に1つ移動
+ : 現在のメモリセルの値を1増加
- : 現在のメモリセルの値を1減少
. : 現在のメモリセルの値をASCIIコードとして出力
, : 入力から1バイトを読み込み、現在のメモリセルに保存
[ : 現在のメモリセルの値が0の場合、対応する]までジャンプ
] : 現在のメモリセルの値が0でない場合、対応する[に戻る

たとえば、アルファベットのAを表示するとしたら、AのASCIIコードは65なので
メモリに65を格納してそれを表示することになります。以下がそれを実現するコードです

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.

1行目で現在のメモリセルの値を65回インクリメントし、2行目で現在のメモリセルの値の数字をASCIIコードとみなして出力します。
ちなみに見やすくするために改行を入れていますが、無くても動きます。

実際にPlayGroundが用意されているので触ったほうがわかりやすいと思います。
以下にリンクを貼っておきます。
https://esolangpark.vercel.app/ide/brainfuck

Hello world

では「Hello World」を出力してみます。
それぞれの文字のASCIIコードは以下です

H: 72
e: 101
l: 108
l: 108
o: 111
(スペース): 32
W: 87
o: 111
r: 114
l: 108
d: 100

これをBrainFuckで書くと以下のようになります。
>はメモリポインタを右に一つ移動する命令です。

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.>
++++++++++++++++++++++++++++++++
.>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.>
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.>
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
.>

繰り返し処理

上記のコードでも動くのですが、+がひたすら羅列されているのはちょっと気持ち悪いです。
例えば、pythonではstr = "*" * 65のように表現できますがBrainFuckにはできません。
なのでBrainFuckでは
65(10 * 6 + 5)のような考え方をします。

  1. 現在のメモリセルの値をインクリメントする
  2. 1.を10回繰り返す (+++++++++)
  3. 1., 2. を6回繰り返す(++++++)
  4. 現在のメモリセルの値を5回インクリメントする(+++++)
    こうすれば、登場する+の回数は21回のみになります。

この繰り返し処理を実現するのが[]です。
[]は必ずペアで使う必要があります。
[は現在のメモリセルの値が0だった場合は対応する]まで進み、0以外だった場合は次の命令へ進みます。
]は現在のメモリセルの値が0だった場合は次の命令に進み、0以外だった場合は対応する[まで進みます。

以下のコードは、現在のメモリセルの値が0の場合[]内の+は実行されず、メモリセルの値は1になる

[+]+.

以下のコードは、現在のメモリセルの値が0以外(1)の場合、[]内の処理は実行されますが、無限ループになります。
なぜなら[に来た時に1なので[]内の処理に入りますが、]に来たときにメモリセルの値が0ではないので[まで戻ります。そして、以降メモリの値は0になることはないので永遠にこれを繰り返します。

+[+]+.

そのためループの条件を管理するためのメモリポインタを用意する必要があります。
メモリポインタ0: ループする回数を管理するメモリセル
メモリポインタ1: 実際に使用するデータ格納用のメモリセル

+++++               ← メモリポインタ0にループする回数5を記録
[                   ← ループ開始
  >                 ← メモリポインタ1に移動
  ++                ← ループ内の処理(2回インクリメント)
  <-                ← メモリポインタ0に移動しデクリメント(繰り返し回数を1減らす)
]                   ← メモリポインタ0の値が0だったらループ終了

以上で2回インクリメント x 5回繰り返しでメモリポインタ1のメモリセルの値は10になります。
さて、それではこの要領で65を作ってみます。

++++++               ← メモリポインタ0にループする回数6を記録
[                    ← メモリポインタ0の値が0以外だったらループ開始
  >                  ← メモリポインタ1に移動
  ++++++++++         ← ループ内の処理(10回インクリメント)
  <-                 ← メモリポインタ0に移動しデクリメント
]                    ← メモリポインタ0の値が0だったらループ終了
>                    ← メモリポインタ1に移動
+++++                ← 5回インクリメント

.で現在のメモリセルの値を出力してAの完成です。複数の文字を出力するときは次の文字の準備のために右にメモリポインタを移動しておきます>

最後に、改行はダサいので省きます。

++++++[>++++++++++<-]>+++++.>

かっこいいHello World

同様に「Hello World」すべてを記述すると以下のようになります。

+++++++[>++++++++++<-]>++.>          H: 72
++++++++++[>++++++++++<-]>+.>        e: 101
++++++++++[>++++++++++<-]>++++++++.> l: 108
++++++++++[>++++++++++<-]>++++++++.> l: 108
+++++++++++[>++++++++++<-]>+.>       o: 111
++++++++[>++++<-]>.>                (スペース): 32
++++++++[>++++++++++<-]>+++++++.>    W: 87
+++++++++++[>++++++++++<-]>+.>       o: 111
+++++++++++[>++++++++++<-]>++++.>    r: 114
++++++++++[>++++++++++<-]>++++++++.> l: 108
++++++++++[>++++++++++<-]>.          d: 100

最後に、改行はダサいので除きます。

+++++++[>++++++++++<-]>++.>++++++++++[>++++++++++<-]>+.>++++++++++[>++++++++++<-]>++++++++.>++++++++++[>++++++++++<-]>++++++++.>+++++++++++[>++++++++++<-]>+.>++++++++[>++++<-]>.>++++++++[>++++++++++<-]>+++++++.>+++++++++++[>++++++++++<-]>+.>+++++++++++[>++++++++++<-]>++++.>++++++++++[>++++++++++<-]>++++++++.>++++++++++[>++++++++++<-]>.>

Discussion