BrainF ** k、396 391バイト
>+>>++++[-<++++++++>]->,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-<+[-<+]->>+[-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>[[->+]->>+<<<+[-<+]->]>+[-<->[[->+]->+>>+<<<<+[-<+]->]<+>->+[->+]->>[->+<]>+>++++++++++>>-<<[-<-[>>]<]<->>>+[-<<<+>>>[-<->]<+++++++++>>>+]++++++++[-<++++<++++++>>]<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]>.>.[-]<[-]<<<[->+<]<<+[-<+]>+]>>[-]<<<-<+[-<+]->>+]
これをやろうという誘惑に抵抗できませんでした。少なくとも三角形は尖った側が下です。
入力は、数字の文字列の後に単一の改行が続くようになります。
出力には、すべての行に単一の末尾スペースが含まれます。
例:
$ bf sd.bf
010
0 1 0
1 1
2
$ bf sd.bf
123456
1 2 3 4 5 6
3 5 7 9 1
8 2 6 0
0 8 6
8 4
2
$ bf sd.bf
9245322
9 2 4 5 3 2 2
1 6 9 8 5 4
7 5 7 3 9
2 2 0 2
4 2 2
6 4
0
説明
機能的な観点からコードを説明するのはかなり難しいため、代わりに、さまざまな時点でテープの状態の観点からコードを見ることができます。ここでの核となる考え方は、出力する三角形が、ループの反復ごとにサイズが1ずつ縮小する(BFの場合は)密集した配列として初期化されるということです。別の重要な考えは255
、テープで検索できる「プレースホルダー」を示すために使用することです。
初期化
これが最も簡単な手順です。プログラムの開始時に、次を実行します。
>+>>++++[-<++++++++>]->
これにより、テープは次の状態に強制されます(>N<
テープ上のポインターの位置を示します)
[ 0 1 32 255 >0< 0 0 ...]
ここの最初の数字は「バッファ」の場所です。長期的に使用するつもりはありませんが、少しの操作を簡単にし、データをコピーするのに役立ちます。
2番目の数字は、各行の最初に出力するスペースの数で、最初の行の後に始まります。最初の行には先行スペースはありません。
3番目の数字は、出力するスペース文字です。
4番目の数値はプレースホルダー255であるため、比較的簡単にこの位置に戻ることができます。
入力
この位置から、すべての文字を読み取ります。このステップの終わりに、次の状況になることを願っています。
[ 0 1 32 255 a b c d e f ... >255< 0 0 ... ]
where a b c d e f ...
は、入力された数字の文字列を示します(改行ではありません)。
次の方法でこれを実現します。
,----------[++++++++++.>>++++++++[-<++++<------>>]<.,----------]-
これにはいくつかのニュアンスがあります。まず、取得した各文字を出力し、その後にスペースを出力します。次に、ASCII値をテープにコピーするのではなく、実際の数字をコピーします。第三に、改行を入力したときに停止し、その時点で適切な場所に置いておきます。
入力がであるとし6723
ます。次に、最初のを読むと、6
テープは次のようになります。
[ 0 1 32 255 >54< 0 0 ...]
でこの値が10
(ASCII改行)と等しくないことを確認します,----------[++++++++++
。次に、値を出力し、入力値から48を減算し、その隣の値に32を同時に加算して続行します(>>++++++++[-<++++<------>>]<
)。ここに残ります。
[ 0 1 32 255 6 >32< 0 ...]
このプロセス全体で、入力の右側のすべての数字が0であると仮定できることに注意してください。これは、右側の値を使用して6 * 8
and を計算する場合、以前の状態を台無しにする危険がないことを意味します4 * 8
。
次に、生成したスペース文字を出力し、新しい入力を取得して、そこで計算したスペースを削除します。最終的に、入力は255
改行で終了し、ループは終了し、改行があった場所を残します(,----------]-
)。これは、テープをナビゲートするために使用する2番目のプレースホルダー文字です。シナリオのこの時点で、テープは次のとおりです。
[ 0 1 32 255 6 7 2 3 >255< 0 0 ... ]
計算
これが機能する方法は、255
プレースホルダー間の数字のリストがループの反復ごとに1つずつ縮小することです。1桁しか残っていない場合は、終了してすぐに停止する必要があります(この時点で、そのリストのすべての数字が既に出力されているため、再度出力することを心配する必要はありません)。
次のトリックを使用して、最初の255
プレースホルダーに移動します<+[-<+]-
。これにより、左側のテープを効果的に検索し、255
間に何も変更しません。ポインターを移動したので、終了条件を確認できます。リストに1桁しかない場合、右側の2スペースのセルにはが保持され255
ます。したがって、それをチェックしてループを開始します。>>+[-<<
ループの最初のステップは、改行を出力することです。最初のセル(バッファセル)に移動し、10を追加して出力します。次のステップは、すべての先行スペース文字を出力することです。それらを出力した後、先頭のスペースの数のカウントを増やします。これらの手順は、次の手順で実行されます。
-<<<<<++++++++++.[-]>[-<+>>.<]<[->+<]>+>>>
この状態のままになります:
[ 0 2 32 255 >6< 7 2 3 255 0 0 0 0 0 0 ]
次のステップでは、リストの最初の値をコピーし、2番目のプレースホルダーを過ぎ255
ます。
[[->+]->>+<<<+[-<+]->]
基本的には、プレースホルダー間を行き来することでこれを行い255
、ここに残ります:
[ 0 2 32 255 >0< 7 2 3 255 0 6 0 0 ... ]
ここで、ループを開始し、リストの残りを繰り返し、ヒットすると停止し255
ます:>+[-<
この時点では、左端の数字は常に0です。したがって、それらが大好きな255
ので、そこにプレースホルダーをポップして、リスト内の自分の場所に戻ることができます。次のステップは、リストの2番目の場所を、2番目のplaceholderを過ぎて、最初の場所を移動した場所を囲む場所に移動すること255
です。これらの手順は、次の手順で実行されます。
->
[[->+]->+>>+<<<<+[-<+]->]
ここから離れます:[ 0 2 32 255 255 >0< 2 3 255 7 6 7 0 ]
今、6
と7
は両方とも、計算が行われる場所に移動されました。7
リストの次の番号にも必要になるため、2つのコピーが必要です。が7
直後に255
この目的を果たしますが、他方7
は計算によって消費されます。
最初に、2桁を追加します。
<+>->+[->+]->>
[->+<]>
ここを離れる:
[ 0 2 32 255 0 255 2 3 255 7 0 >13< 0 ]
次のステップの組み合わせは最も複雑です。指している数値が10より大きいかどうかを確認する必要があります。10より大きい場合は、を減算し10
ます。実際には、10を減算0
し、減算のいずれかの時点でヒットするかどうかを確認します。存在する場合10
、後で追加し直します。この最後に、10を法とする合計が必要です。
Prepare a 10 to the right
+>++++++++++
Leave yet another 255 for a loop condition later
>>-<<
If the number is greater than 10 end up one space to the left
else one space to the right
[-<-[>>]<]<->
Check if the previous 255 is two spaces to the right and if it is
add 10 back to our sum--we've subtracted too much
>>+[-<<<+>>>[-<->]<+++++++++>>>+]
この時点で、目標を達成しました。10を法とする合計があります!また、数が10より大きいかどうかに関係なく、ここで終了します。
[ 0 2 32 255 0 255 2 3 255 7 0 3 0 0 >0< ]
次の目標は、この新しい合計を出力し、それにスペースを空けて、リストに戻すことです。これはすべて、これまでの255
ホッピングと48
合計への追加手法を使用して行われているため、詳しくは説明しません。
++++++++[-<++++<++++++>>]
<<<[-<<<<+[-<+]-<+>>+[->+]->>>>+<]
>.>.
そして私たちはここにいます:[ 0 2 32 255 3 255 2 3 255 7 0 0 51 >32< ]
追加の255
3
リスト内の場所を失わないように、新しく注入された後にプレースホルダーしてください。この時点で、合計とそのスペースを出力しているので、クリーンアップして、このループの次の反復が機能する状態に戻す必要があります。私たちは、クリアする必要がある51
と32
、細胞を移動し7
、我々は、最初からやり直すことができるように右に一度、そして私たちのリストのプレースホルダに移動します。
[-]<[-]<<<[->+<]<<+[-<+]
今、私たちはここにいます:[ 0 2 32 255 3 >0< 2 3 255 0 7 0 ... ]
次の繰り返しのためにまさにそこにいたいところです。255をチェックして先に進みましょう!(>+]
)
ループから脱落すると、前のリストの合計で構成されるまったく新しいリストが作成されます。最初は、次のようになります。
[ 0 2 32 255 3 9 5 0 >0< ]
次に、新しいリストでそのプロセス全体を繰り返したいので255
、左に下に進んで最初からやり直します!を少しクリーンアップして>>[-]<<
から、プレースホルダーを削除する必要があります<-
。その後、入力後とまったく同じ場所にいるので、同じチェックを行うことで逃げることができます:<+[-<+]->>+
、およびboom!完全なループができました!必要なのは右角かっこだけで、終了時にはすべてを出力しているので、完了です]
。