実用Brainf*ckプログラミング
入門編
KMC1回生 prime(twitter:@_primenumber)
はじめに:Brainf*ckとは
● 命令記号は+-><[].,の8種類だけ!
● 1993年にできた、できるだけコンパイラが小さくなるよう
なプログラミング言語
● 難解になるべくして生まれたわけではない
● 実際、命令記号は読みやすいように選ばれている
● 処理系が作りやすいので、しばしばプログラミングの練習
問題としてBrainf*ckインタプリタの作成をさせたり、派
生言語が作られたりする
言語仕様
● はじめに0で初期化された十分な長さの配列が与えられる
● C言語で言うポインタを操作して動作。最初は0番地
● +/- ポインタの指す値を1増やす/減らす
● >/< ポインタをインクリメント/デクリメントする
● [ ポインタの指す値が非0なら対応する]の直後にジャンプ
● ] ポインタの指す値が0なら対応する[の直後にジャンプ
● . ポインタの指す値を文字として出力する
● , 入力から1バイト読み、ポインタの指す値に代入する
● これら8種類の文字以外については動作は未定義だが、
多くの処理系では無視する
Brainf*ckでできること
● これだけの命令記号で(無限長の配列なら)チューリング
完全
– 他のプログラミング言語でできることなら(理論上)な
んでもできる
● でも実際に実装するのはほぼ無理でしょ?
Brainf*ckでできること
● これだけの命令記号で(無限長の配列なら)チューリング
完全
– 他のプログラミング言語でできることなら(理論上)な
んでもできる
● でも実際に実装するのはほぼ無理でしょ?
→実はある程度のパターンを覚えれば、
わりと実装できる!!!
今日やること
● 入門編なので少しだけ
● 値のクリア・代入、足し算/引き算、値のコピー、掛け
算、スタック
● 最後にこれらを使って実際に動くプログラムを作ります
● 説明の中で省略記号を使います
– ポインタが最初に指している場所を[0]と書き、[n]
でそこからn番地進んだ場所を表す
値のクリア・代入
● 値をクリアしたり代入するとき
● 値のクリア:[0]の値を0にする
● [-]
● 動作:[0]の値が0になるまで1減らす
● 値の代入:[0]の値を5にする
● [-]+++++
● 動作:[0]の値をクリアして5を足す
足し算・引き算
● かなり使う
● 足し算:[0]の値を[1]に足す([0]の値は消える)
[>+<-]
● 動作:「[1]の値を1増やし、[0]の値を1減らす」を[0]が
0になるまで繰り返す
● [1]の値が0なら値の移動になる
● 引き算:[0]の値を[1]から引く
[>-<-]
値のコピー
● 足し算や引き算をするとどちらかの値が消えてしまう
● Brainf*ckではほとんど非破壊的な動作はできない
● →値のコピーが必要
● 値のコピー:[0]の値を[1]にコピー([2]を一時変数とし
て使う)
[>+>+<<-]>>[<<+>>-]
● [0]の値を[1]と[2]に書き込む([0]の値は消える)
● [2]の値を[0]に書き込む([2]の値は消える)
掛け算
● 足し算と値のコピーを繰り返す
● 掛け算:[0]と[1]の積を[2]に書き込む([3]を使う)
[<[>>+>+<<<-]>>>[<<<+>>>-]<<-]
● [0]の値を[2]と[3]に足し、[3]の値を[0]に書き込む
● [1]の値を1減らす
● これを[1]の値が0になるまで繰り返す
● 定数の掛け算は簡単にできる
● 定数の掛け算:[0]の5倍を[1]に入れる
[>+++++<-]
スタック
● そもそもBrainf*ckはデータメモリがそのままスタック
に使える
● スタックに積む
(値を書き込む)>
● スタックから値を取り出す
<(値を使う)
● サンプル:
まずスタックに3つ値を積む
スタックから2つ取り出し積を計算して値を積む
再帰
● 関数の中でその関数自身を呼び出すこと
● うまく使うとプログラムが簡単に書ける
● 実は再帰はスタックを使って書ける!
再帰
● 関数の中でその関数自身を呼び出すこと
● うまく使うとプログラムが簡単に書ける
● 実は再帰はスタックを使って書ける!
● →Brainf*ckはスタックが書ける!!
再帰
● 関数の中でその関数自身を呼び出すこと
● うまく使うとプログラムが簡単に書ける
● 実は再帰はスタックを使って書ける!
● →Brainf*ckはスタックが書ける!!
● →Brainf*ckでは再帰が書ける!!!!
再帰
● 関数の中でその関数自身を呼び出すこと
● うまく使うとプログラムが簡単に書ける
● 実は再帰はスタックを使って書ける!
● →Brainf*ckはスタックが書ける!!
● →Brainf*ckでは再帰が書ける!!!!
● サンプル用意するのがめんどくさい&最後に再帰のプログ
ラムを書くのでサンプルは省きます
ハノイの塔
以下のルールに従ってすべての円盤を右端の杭に移動さ
せられれば完成。
● 3本の杭と、中央に穴の開いた大きさの異なる複数の円盤
から構成される。
● 最初はすべての円盤が左端の杭に小さいものが上になる
ように順に積み重ねられている。
● 円盤を一回に一枚ずつどれかの杭に移動させることがで
きるが、小さな円盤の上に大きな円盤を乗せることはで
きない。
From Wikipedia
ハノイの塔
● ハノイの塔は再帰的な方法で最短で解けることが知られ
ている
● 解法
– 何らかの方法でn-1枚の円盤を左端の杭から中央の杭
に移動させる
– 一番大きな円盤を左端の杭から右端の杭に移動させる
– 何らかの方法でn-1枚の円盤を中央の杭から右端の杭
に移動させる
● これをBrainf*ckで実装しよう!
● 動かすべき円盤とどこからどこに動かすかを出力する
Brainf*ckでハノイの塔
● 擬似コードで書くと
– Hanoi(n,a,b) //n枚の円盤を左端からa番目の杭からb
番目の杭に移動させる
Hanoi(n-1,a,c)
Move(n,a,b)
Hanoi(n-1,c,b)
● cは{1,2,3}のうちaでもbでもない数
● Move(k,a,b)はk枚目の円盤を左端からa番目の杭からb番
目の杭に移動させる
Brainf*ckでハノイの塔
● 「{1,2,3}のうちaでもbでもない数」は、6-a-bで求めら
れる
● 再帰の中でMoveという別の関数を呼ぶのに相当する処理
するのは割と難しい
– Hanoiに引数をひとつ増やしてHanoi(n,s,a,b)とし
て、s=1ならHanoi,s=0ならMoveということにする
● したがって、スタックで実装するときに積むデータの組
はn,s,a,bの四つ組
● スタックに4個ずつ積んだり取り出したりすることで実装
できる
Brainf*ckでハノイの塔
1.最初にスタックに(n,s,a,b)=(n,1,1,3)を積む
2.スタックの一番上の値を読み、s=0なら6に飛ぶ
3.スタックから取り出した値が(n,1,a,b)だったとすると
それを消してスタックに(n-1,1,a,6-a-b),(n,0,a,b),
(n-1,1,6-a-b,b)を積む
4.スタックの一番上の値を読み、(1,*,*,*)でないなら3に
戻る
5.スタックの一番上の値を読み、sを1から0にする
6.スタックから取り出した値を出力する。たとえば
(3,0,1,3)だったらC 1 3を出力する
7.スタックの一番上の値が(0,*,*,*)でないなら2に戻る
実際のコード(4枚Ver.)
>>>>++++>+>+>++
+<<<[>[<-[[>>>>+>>>>+>>>>+<<<<<<<<<<<<-]>[>>>>+>>
>>+>>>>+<<<<<<<<<<<<-]>[>>>>+>>>>+>>>>+<<<<<<<<<<
<<-]>[>>>>+>>>>+>>>>+<<<<<<<<<<<<-]<+++++
+>>+>->>>>>>>[<<<<<<<<<<<<+>>>>>>>>>>>>-]>[<<<<<<
<<<<<<+>>>>>>>>>>>>-]>[<<<<<<<<<<<<->>>>>>>>>>>>-
]>[<<<<<<<<<<<<+<->>>>>>>>>>>>>-]<<<<<[>>+>+<<<-]
>[>+<-]++++++>[<->-]>[<<<+>>>-]<<<<<-]+>-]+++++++
+[>++++++>++++++<<<++++++++>-]>>>>++++[<+++++++
+>-]<<<<<.[-]>>>>.<<.[-]>>.[-]<.[-]++++++++++.
[-]<<<<<<<]
(454bytes)
まとめ
● 一見Brainf*ckで実装するのが難しそうなものでも要素
要素に分解していくとそこまで大変ではない(こともあ
る)
● 今回は入門編でしたがそのうち初級編/中級編/上級編
もやりたいと思います
● 初級編は数値の比較、割り算の商と余り、配列を考えて
います
おまけ
● 最近Brainf*ckでメタプログラミングできる拡張bfmeta
を作りました
● データメモリとプログラムメモリが同一になっていて、
プログラム実行中にそのプログラム自身を書き換えられ
るという仕組み
● それに従い、終了条件をプログラムカウンタの指す値
が0になったら、に変更
● よくある記号を増やしたりただ置き換えたりするクソみ
たいなBrainf*ck拡張と違って、同じ記号でプログラミ
ングするのに、はるかに強力な言語になる
● メタプログラミングあんまりやってないのでどんなこと
をやると楽しいか教えてください
おわり

実用Brainf*ckプログラミング入門編