誰かがこれを私に送って、それがBrainfuckのハローワールドであると主張しました(そして私はそう願っています...)
++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
私はポインタを動かし、ものを増やしたり減らしたりすることで動作する基本を知っています...
まだ知りたいのですが、実際にどのように機能しますか?そもそも画面に何かを印刷する方法は?テキストをどのようにエンコードしますか?まったくわからない...
Brainfuckを理解するには、0
で初期化されたセルの無限配列を想像する必要があります。
...[0][0][0][0][0]...
Brainfuckプログラムが起動すると、任意のセルを指します。
...[0][0][*0*][0][0]...
ポインターを右に移動すると>
は、ポインターをセルXからセルX + 1に移動します
...[0][0][0][*0*][0]...
セル値+
を増やすと、以下が得られます:
...[0][0][0][*1*][0]...
セル値を再度増加すると+
が得られます:
...[0][0][0][*2*][0]...
セル値-
を減らすと、次のようになります:
...[0][0][0][*1*][0]...
ポインターを左に移動すると<
ポインターをセルXからセルX-1に移動します
...[0][0][*0*][1][0]...
文字を読み取るには、コンマ,
を使用します。それは:標準入力から文字を読み取り、その10進数ASCIIコードを実際のセルに書き込みます。
ASCIIテーブル を見てください。たとえば、!
の10進コードは33
ですが、a
は97
です。
BFプログラムのメモリが次のようになっていると想像してみましょう。
...[0][0][*0*][0][0]...
標準入力がa
を表すと仮定すると、コンマ,
演算子を使用する場合、BFが行うことはa
decimal ASCII code 97
をメモリに読み取ります。
...[0][0][*97*][0][0]...
あなたは一般的にそのように考えたいと思うが、真実はもう少し複雑です。真実は、BFは文字ではなくバイト(そのバイトが何であれ)を読み取ることです。例を示しましょう:
Linuxで
$ printf ł
プリント:
ł
これは特定のポリッシュキャラクターです。この文字は、ASCIIエンコードではエンコードされません。この場合、UTF-8エンコードであるため、コンピューターのメモリで複数バイトを使用していました。 16進ダンプを作成することで証明できます。
$ printf ł | hd
以下を示します:
00000000 c5 82 |..|
ゼロはオフセットされます。 82
が最初で、c5
がł
を表す2番目のバイトです(読み取る順序で)。 |..|
は、この場合には不可能なグラフィカルな表現です。
さて、シングルバイトを読み取るBFプログラムへの入力としてł
を渡すと、プログラムメモリは次のようになります。
...[0][0][*197*][0][0]...
なぜ197
なのか? 197
10進数はc5
16進数です。おなじみのようですか?もちろん。 ł
の最初のバイトです!
文字を印刷するには、ドット.
を使用します:実際のセル値を10進数ASCIIコードのように扱うと仮定して、対応する文字を標準出力に出力します。
BFプログラムのメモリが次のようになっていると想像してみましょう。
...[0][0][*97*][0][0]...
ここでドット(。)演算子を使用すると、BFが行うのはprintです:
a
ASCIIのa
10進コードは97
であるためです。
たとえば、次のようなBFプログラム(97プラス2ドット):
++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++++ ..
指すセルの値を最大97まで増やし、2回印刷します。
ああ
BFループは、ループ開始[
とループ終了]
で構成されます。条件が実際のセル値であるC/C++の場合のように思えます。
以下のBFプログラムをご覧ください:
++[]
++
は、実際のセル値を2回インクリメントします。
...[0][0][*2*][0][0]...
[]
はwhile(2) {}
に似ているため、無限ループです。
このループを無限にしたくないとしましょう。たとえば、次のことができます。
++[-]
そのため、ループがループするたびに、実際のセル値が減ります。実際のセル値が0
ループになると:
...[0][0][*2*][0][0]... loop starts
...[0][0][*1*][0][0]... after first iteration
...[0][0][*0*][0][0]... after second iteration (loop ends)
有限ループのさらに別の例を考えてみましょう。
++[>]
この例は、ループが開始されたセルでループを終了する必要がないことを示しています。
...[0][0][*2*][0][0]... loop starts
...[0][0][2][*0*][0]... after first iteration (loop ends)
ただし、開始した場所で終了するのは良い習慣です。どうして ?ループが開始した別のセルを終了する場合、セルポインターがどこにあるかを推測できないためです。正直に言うと、この方法はBrainfuckをBrainfuckより少なくします。
Wikipedia には、コードのコメントバージョンがあります。
+++++ +++++ initialize counter (cell #0) to 10
[ use loop to set the next four cells to 70/100/30/10
> +++++ ++ add 7 to cell #1
> +++++ +++++ add 10 to cell #2
> +++ add 3 to cell #3
> + add 1 to cell #4
<<<< - decrement counter (cell #0)
]
> ++ . print 'H'
> + . print 'e'
+++++ ++ . print 'l'
. print 'l'
+++ . print 'o'
> ++ . print ' '
<< +++++ +++++ +++++ . print 'W'
> . print 'o'
+++ . print 'r'
----- - . print 'l'
----- --- . print 'd'
> + . print '!'
> . print '\n'
質問に答えるために、,
および.
文字がI/Oに使用されます。テキストはASCIIです。
Wikipedia の記事もさらに詳しく説明しています。
最初の行は、0から10回インクリメントするだけで
a[0] = 10
を初期化します。2行目のループは、配列の初期値を効果的に設定します。a[1] = 70
(72に近い、ASCIIコード文字 'H')、a[2] = 100
(101または 'e'に近い)、a[3] = 30
(32に近い、スペースのコード)、およびa[4] = 10
(改行)。ループは、ループに毎回、それぞれa[1]
、a[2]
、a[3]
およびa[4]
に7、10、3、および1を追加することにより機能します。合計でセル(a[1]=70
などを与える)。ループが終了すると、a[0]
はゼロになります。>++.
はポインターをa[1]
に移動し、70を保持し、それに2を加算し(72を生成し、これは大文字HのASCII文字コードです)、出力します。次の行は、配列ポインターを
a[2]
に移動し、それに1を追加して、101を生成し、小文字の 'e'を出力します。「l」は「e」の後の7番目の文字であるため、「ll」を出力するために
+++++++
にさらに7が追加され(a[2]
)、結果が2回出力されます。「o」は「l」に続く3番目の文字であるため、
a[2]
はさらに3回インクリメントされ、結果を出力します。プログラムの残りの部分も同じように進みます。スペースと大文字については、異なる配列セルが選択され、必要に応じて増分または減分されます。
印刷する内容をどのように知るかという質問に答えるために、印刷が行われるコードの右側にASCII値の計算を追加しました。
> just means move to the next cell
< just means move to the previous cell
+ and - are used for increment and decrement respectively. The value of the cell is updated when the increment/decrement happens
+++++ +++++ initialize counter (cell #0) to 10
[ use loop to set the next four cells to 70/100/30/10
> +++++ ++ add 7 to cell #1
> +++++ +++++ add 10 to cell #2
> +++ add 3 to cell #3
> + add 1 to cell #4
<<<< - decrement counter (cell #0)
]
> ++ . print 'H' (ascii: 70+2 = 72) //70 is value in current cell. The two +s increment the value of the current cell by 2
> + . print 'e' (ascii: 100+1 = 101)
+++++ ++ . print 'l' (ascii: 101+7 = 108)
. print 'l' dot prints same thing again
+++ . print 'o' (ascii: 108+3 = 111)
> ++ . print ' ' (ascii: 30+2 = 32)
<< +++++ +++++ +++++ . print 'W' (ascii: 72+15 = 87)
> . print 'o' (ascii: 111)
+++ . print 'r' (ascii: 111+3 = 114)
----- - . print 'l' (ascii: 114-6 = 108)
----- --- . print 'd' (ascii: 108-8 = 100)
> + . print '!' (ascii: 32+1 = 33)
> . print '\n'(ascii: 10)
Brainfuckその名前と同じ。それは8文字のみを使用します> [ . ] , - +
-quickestプログラミング言語学習するですが難易度実装および理解する。…。そして、最終的にあなたの脳をf * ckingすることになります。
配列に値を保存します:[72] [101] [108] [111]
まず、配列のセル1を指すポインター:
>
ポインタを1つ右に移動します
<
ポインタを左に1移動します
+
セルの値を1インクリメントします
-
要素の値を1インクリメントします
.
現在のセルの値を出力します。
,
は現在のセルに入力を取ります。
[ ]
ループ、3カウントの+++ [-]カウンターbczの前に3 '+'があり、-カウント変数を1値だけデクリメントします。
セルに保存される値はascii値です。
上記の配列を参照してください:[72] [101] [108] [108] [111] ASCII値に一致する場合、Hello writternであることがわかります。
おめでとうございます! BFの構文を学習しました
——-その他 ———
最初のプログラム、つまりHello Worldを作成しましょう。その後、この言語で名前を書くことができます。
+++++ +++++[> +++++ ++ >+++++ +++++ >+++ >+ <<<-]>++.>+.+++++ ++..+++.++.+++++ +++++ +++++.>.+++.----- -.----- ---.>+.>.
細分化:
+++++ +++++[> +++++ ++
>+++++ +++++
>+++
>+
<<<-]
4つのセル(>の数)の配列を作成し、次のような10のカウンターを設定します。—-psuedoコード-
array =[7,10,3,1]
i=10
while i>0:
element +=element
i-=1
カウンタ値はセル0に格納され、>セル1に移動すると値が+7更新され、>セル2に移動すると前の値に10ずつ増加する、など….
<<<
はセル0に戻り、その値を1減らします
したがって、ループ完了後、配列があります:[70,100,30,10]
>++.
1番目の要素に移動し、その値を2(2つの「+」)増やしてから、そのASCII値の文字(「。」)を印刷します。たとえば、Pythonの場合:chr(70 + 2)#prints 'H'
>+.
2番目のセルの増分値1に移動して値100 + 1になり、値を印刷( '。')します。つまり、chr(101)chr(101)#prints 'e'となり、次のピースに>または<がなくなり、現在の値を取得します最新の要素とそれへの増分のみ
+++++ ++..
したがって、最新の要素= 101、101 + 7で2回印刷します(2つの「..」があるため)chr(108)#prints l
for i in array:
for j in range(i.count(‘.’)):
print_value
———それはどこで使用されますか? ——-
これはプログラマーに挑戦するために作られた単なる冗談言語であり、実際にはどこでも使用されていません。
あなたが求めているのは、Brainfuckがすべてのコードで何をすべきかをどのように知っているかだと思います。 Pythonなどの高レベル言語で記述されたパーサーがあり、コード内のドットの意味または追加記号の意味を解釈します。
したがって、パーサーはコードを1行ずつ読み取り、>記号があると言って、メモリの場所を進める必要があります。コードは、(そのメモリの内容)==>、memlocation = + memlocation (メモリ位置のコンテンツ)== "。"の場合、同様に高レベル言語で記述され、印刷(メモリ位置のコンテンツ)。
これで解決することを願っています。 tc