Brainf*ckで足し算ができる電卓を作ってみた

# はじめに
こんにちは！Life is Tech!でメンターをしているえーえすです！
今回は[Life is Tech ! Kanto Advent Calendar 2022](https://qiita.com/advent-calendar/2022/life-is-tech-kanto)の10日目！昨日はGeekさんの[F1激アツ記事](https://qiita.com/kota_geek/items/7b6d2b7e3e3e0fb90007)でしたね！F1めっちゃみてみたくなりました！！

さて、僕はこのアドカレにこれ含めて3記事を投稿するんですが、他2記事がすっごい真面目なんです。だからこそ、**この記事くらいはふざけたい**!ということで！！
### Brainf*ckで足し算ができる電卓を作ってみました！！
すっっっっっっごい頑張ったので是非読んでいただけると嬉しいです。

# Brainf*ckって何？
Brainf*ckは、**たった8文字しか使えないプログラミング言語**です。は？？って感じでしょうから、使える文字の一覧を載せておきます。

|文字|意味|
|-|-|
|>|ポインタをインクリメント|
|<|ポインタをデクリメント|
|+|今いるポインタの値をインクリメント|
|-|今いるポインタの値をデクリメント|
|[|今いるポインタの値が0なら、対の]にジャンプ|
|]|今いるポインタの値が0でないなら、対の[にジャンプ|
|.|今いるポインタに入力を1バイト分取り込む|
|,|今いるポインタの値を出力|

Brainf*ckでは、**Int型の配列が用意されており、その要素にポインタを用いてアクセスできる**といった感じに思っていただければ大丈夫です。詳しい内容は[こちらの記事](https://qiita.com/saba383810/items/39e20b11c71b3dfd2589)などが超絶参考になります。（なんと環境設定の話までしてくれています）数学に詳しい方なら、**チューリングマシン**とよく似たものだと思っていただければ大体のイメージがつくかと思います。

# 今回使わせていただいた環境
今回は[Try It Online](https://tio.run/#)を使わせていただきました。~~なんでBrainfuckまで使えるの~~

# やってみよう！
さて、この程度の軽い解説でも理解することはできたんじゃ無いかなと思います。ということで**実際に書いてみましょう**。最初は定番の「Hello, world!」から。
入力・出力は**char型として扱われる**ので、例えばHを出力したければ今いるポインタの値を72にすればいいということです。

```brainfuck
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
+++++++++++++++++++++++++++++.
+++++++..
+++.
-------------------------------------------------------------------.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++.
--------.
+++.
------.
--------.
-------------------------------------------------------------------.
```
実行結果↓
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/81ca6d4c-1d07-08eb-21c4-1b9c846b0433.png">
できた！

また、[]を用いることで反復を多少楽にすることができます。

```brainfuck
++++++++[->+++++++++<]>.<+++++[->+++++<]>++++.+++++++..+++.<+++++++++[->---------<]>++.<+++++++++[->+++++++++<]>++++++.--------.+++.------.--------.<++++++++[->--------<]>---.
```
…さあ、こういう言語です。名前通り頭がクソになります。楽しくなってきましたね。


僕はこの言語を使って足し算を実装してみたくなりました。そこで今流行りのChatGPTに作り方を聞いてみたんですよ。そしたら**できません**って返ってきたんです。作るしかねぇよなぁ！！！！

# 足し算を作ってみよう
最初に思い浮かぶのはこんな実装です。

2つのポインタに数を格納
↓
片方にもう片方のポインタの値をうつす
↓
出力

ここで、もう片方のポインタの値をうつす際、'0'のASCII値、48が余分に足されてるので、48引いてみたらいい感じになりそうですね。

```brainfuck
,>,  //(0)、(1)に数を格納
[<+>-]  //(1)が0になるまで(1)をインクリメント、(0)をデクリメント
<------------------------------------------------  //(0)から48を引く
.  //出力
```
また、入力も1バイトごとに読み込まれるので「1+1」のようにかけませんね。「11」と書くしかありません。

実行結果
↓
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/f5a9e189-1d70-2c3a-57a6-a161348ce521.png">

**これにて一応1+1=2ができました**！！
…
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/a2f91719-798e-5966-411f-95148c186178.png">
…??
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/6df6f951-2779-2651-5425-876b7c064137.png">

…そう。勘の言い方ならお気づきでしょうが、これでは**繰り上がりのある計算や2桁以上の計算ができない**わけです。電卓として致命的ですね？？

# ちゃんと足し算電卓を作ろう
先に謝らなければならないことがあります。この電卓は未完成で、**桁数の大きい数を先に入力しないとぶっ壊れます**。~~アドカレ間に合わなかったので許してください~~

さて、方針です。

+で区切った2つの数字を桁ごとに格納
↓
1つ目の入力の方に桁ごとに数を足していく
↓
繰り上がりの処理をする
↓
出力

格納まではよかった。その後が、ほんとに、地獄だった。


# 完成品
こちらとなっております。

```brainfuck
-------------------------------------------[+++++++++++++++++++++++++++++++++++++++++++>,-------------------------------------------]
>
>,[>,]
<

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

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

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

>>>>>[.>]
```

ちゃんと計算ができます。**なんなら普通の電卓よりでかい桁でもできる**。
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2823873/e32331d6-3d01-c7d6-b22a-6bf8002b85db.png">

# なにをしているのか
今回の製作で気づいたことは、**[]をうまく使えば世界が変わる**ということです。こいつらをうまく使って**if文のような条件分岐**だったり**例外処理のつじつま合わせ**などをすることができてしまうんです。（これ全部自分で考えたんですよ？？？褒めて欲しい）

```brainfuck
-------------------------------------------[+++++++++++++++++++++++++++++++++++++++++++>,-------------------------------------------]
>
>,[>,]
<
```
ここの上1行で「入力が+になるまで入力、>」、その後の行で、「合わせて2つ空白を開け、入力が\0になるまで入力、>」をしています。]が呼ばれる時にいるポインタの値が0であるかどうか、というのをうまく使っています。

```
[
[->+<]
>[<<[<]<[<]<+>>[>]>[>]>-]
<<[<]<[<]<[->+<]
>------------------------------------------------
[>]>[>]<
]
```

ここでは、「うまく空白を開けながら一桁ごとに足し合わせ、保存」というのをやってますね。[<]とか[>]とかで**次の空白まで飛んでいける**わけですから、これがすっごい便利だった。データの保存は**0をうまく挟みながらまとめる**という感じでやってるのもわかっていただけると嬉しいな。

```brainfuck
<[<]<[[->+<]<]
```

ここで1つ目の入力の数で、足し合わされなかった分の桁を、足した後保存してあるところに合流させてます。

```brainfuck
>>[>]<
[
-----------------------------------------------
[<]<++++++++++
[
-
>>[>]>+>>+<<
<<-[>>-<]>>[<<<[<]<[-]>>[>]>>->]
<<<<[<]<
]
>>[>]>>>>[>]<[<]<<<[[>>>>[-]<<<<[>>>>+<<<<-]]<+>]
>>>>+++++++++++++++++++++++++++++++++++++++++++++++
<<<<+<-[+>->]>[<+++++++++++++++++++++++++++++++++++++++++++++++++>->>]
<<<
]
```

ここで繰り上がり処理をしています。特に5+5みたいに入力のない桁に繰り上がるときの処理がもうほんとにむずかった……いい処理がきっとあるんでしょうが、これを思いついたのが天才。すごい俺。
要するに`if(x>9)`みたいな条件を作ってるんですが、これがほんとにむずかしい。不等号ってこんなにもむずかったんですね………

```brainfuck
>>>>>[.>]
```
最後に全部の桁を出力して、完成！！

# おわりに
もうね、ほんとに大変だった。一晩寝たらこのコードがなんだったのかもうわからなくなってるんですよ。読めない。だから辛い。でも全てを理解して完成した時はほんとに嬉しかった。すごくいい経験でした。
こんな最高の言語、Brainf*ckですが、世界にはやっぱり[えげつない人々](https://github.com/fabianishere/brainfuck)がおりまして、**BrainfuckでBrainfuckのコンパイラを書く**みたいな、え、もうなんなんそれみたいなことやってる人がいたり。世界は広い。
ちなみにこの言語、チューリング完全だそうで、要するに**どんなコードでも実行できます**。みんなもやってみてね！

さてさて明日12/11のアドカレはこすさんの記事です！！とっても面白そうなので楽しみにしています！！！