3番目のスタックを使用する
タイトルを読んでいると、少し混乱するかもしれません。Brain-Flakには2つのスタックしかありませんか?しかし、私はそれが存在することを保証します。それは、Brain-Flakを書いたりゴルフしたりするのに最も強力ではないにしても、最も強力なツールの1つです。
「サードスタック」とは何ですか?
すべてのBrain-Flakプログラムは何らかの方法で3番目のスタックを使用しますが、ほとんどの使用は舞台裏で行われ、多くの場合、存在するという事実を単に無視することが有用です。プログラム内の各括弧は、スタックから1つの項目を追加または削除します。3つの開いた中括弧は([<
すべてスタックにアイテムを追加し、3つの共役は)]>
すべてスタックからアイテムを削除します。スタック上のアイテムの値は、プログラムの現在のスコープの値であり、niladsを使用すると、特定の方法でこの値が変更されます。閉じ括弧に)
は、要素を3番目のスタックから現在のスタックに移動する独自の機能があります。プッシュ。
うまくいけば、これはあなたに明らかになってきています。3番目のスタックは、既に実行されたコードの戻り値を記憶するある種のスタックです。2つの通常のスタックと3番目のスタックを追跡する単純なプログラムの例を見てみましょう。
例
次のプログラムについて説明します。このプログラム-3, 1, -2
はスタックにプッシュします。
(([()()()])(()))
3つの開いたブレースから開始します。これらはすべて、3番目のスタックにゼロをプッシュします。
スタックは次のようになります。3番目のスタックが右側にあり、アクティブなスタックがその^
下にあります。
0
0
0 0 0
^
(([()()()])(()))
^
現在、3つの()
niladがあります。これらは通常の2つのスタックには何もしませんが、それぞれ3つ目のスタックの最上部に1つずつ追加して、スタックを次のようにします。
3
0
0 0 0
^
(([()()()])(()))
^
さて、]
前に述べたように、閉じブレースは3番目のスタックからアイテムを削除します]
が、スタックのトップから削除する要素を減算する機能を持っています。したがって、新しいスタックは次のようになります。
-3
0 0 0
^
(([()()()])(()))
^
意味あり; [...]
否定を行うため、]
下向きに減算する必要があります。
次に、を実行する必要があり)
ます。おそらく思い出す)
ように、スタック内に何かがプッシュされるプログラム内の場所なので、3番目のスタックのトップを現在のスタックに移動し、さらに-3
3番目のスタックの次の要素に追加します。
-3 0 -3
^
(([()()()])(()))
^
ここでも、3つの開いたブレースの1つに遭遇するので、3番目のスタックに別の要素を追加します。
0
-3 0 -3
^
(([()()()])(()))
^
前に言ったよう()
に、3番目のスタックの最上部を1つ増やします。
1
-3 0 -3
^
(([()()()])(()))
^
そして)
、3番目のスタックの上部をアクティブスタックに移動し、下に追加します
1
-3 0 -2
^
(([()()()])(()))
^
最後)
は3番目のスタックをアクティブスタックに移動し、3番目のスタックには追加する要素が残っていないため、他には何もしません。
-2
1
-3 0
^
(([()()()])(()))
^
プログラムが終了したので、終了して出力します。
この例は、3番目のスタックが何であり、何であるかをユーザーに理解してもらうことを目的としています。すべての操作が含まれているわけではありませんが、各操作がそれ自体で何をしているのかを理解できることを願っています。まだ苦労している場合は、この回答の最後に「チートシート」を掲載しています。
OK、それで何?
さて、これでサードスタックは理解できましたが、「だから何?」「サードスタック」と呼ばなくても、すでに使用していましたが、サードスタックの観点から考えると、ゴルフにどのように役立ちますか。
問題を見てみましょう。あなたは数の三角形を取りたいです。これは、nより小さいすべての数値の合計です。
1つのアプローチは、オフスタック上にアキュムレーターを作成し、カウントダウンしながらアキュムレーターを追加することです。これにより、次のようなコードが作成されます。
(<>)<>{(({}[()])()<>{})<>}{}<>({}<>)
オンラインでお試しください!
このコードは非常にコンパクトであり、もっと小さくすることはできないと思うかもしれません。しかし、3番目のスタックの観点からアプローチすると、これは非常に非効率的であることが明らかになります。アキュムレータをオフスタックに配置する代わりに、aを使用して3番目のスタックに配置し、(
使用する最後に取得することができます)
。もう一度すべての数値をループしますが、今回は、Third Stackをインクリメントするために多くのことをする必要はありません。プログラムがそれを行います。これは次のようになります。
({()({}[()])}{})
オンラインで試す
このコードは、以前に作成したかなりよくゴルフされたバージョンの半分以下のサイズです。実際、コンピューター検索により、このプログラムがこのタスクを実行できる最短のプログラムであることが証明されています。このプログラムは「すべての実行の合計」アプローチを使用して説明できますが、サードスタックアプローチを使用して説明すると、はるかに直感的で明確になると思います。
3番目のスタックはいつ使用しますか?
Brain-Flakで新しい問題の作業を開始するときはいつでも、サードスタックを念頭に置いてこれをどのように行うかを自分で考える必要があります。ただし、一般的な経験則として、あるタイプのアキュムレーターを追跡する必要がある場合、または積算合計がある場合は、2つの実際のスタックではなく、3番目のスタックに置くことをお勧めします。
3番目のスタックの使用を検討することをお勧めする別の機会は、他の2つのスタックに値を保存するスペースがない場合です。これは、2つの既存のスタックで操作を行っており、どこにあるかを追跡せずに後で使用するために値を保存する場合に特に役立ちます。
3番目のスタックの制限
Third Stackは多くの点で非常に強力ですが、独自の制限と欠点があります。
まず、特定のポイントでの3番目のスタックの最大スタック高さがコンパイル時に決定されます。つまり、スタック上の一定量のスペースを使用する場合は、プログラムを作成するときにそのスペースを割り当てる必要があります。
次に、3番目のスタックはランダムアクセスではありません。つまり、最上位の値以外の値に対して操作を実行することはできません。さらに、スタック上の値を移動することはできません(最初の2つの要素を入れ替えるなど)。
結論
Third Stackは強力なツールであり、すべてのBrain-Flakユーザーにとって不可欠だと思います。Brain-Flakでプログラミングに慣れるには多少の慣れが必要であり、シフトが必要ですが、適切に使用すると、ゴルフに関してはまともなものと驚くべきものとの違いが生じます。
カンニングペーパー
以下に操作のリストと、それらがサードスタックに与える影響を示します。
Operation | Action
====================================================
(,[,< | Put a zero on top of the Third Stack
----------------------------------------------------
) | Add the top of the Third Stack to the
| second element and move it to the
| active stack
----------------------------------------------------
] | Subtract the top of the Third Stack
| from the second element and pop it
----------------------------------------------------
> | Pop the top of the Third Stack
----------------------------------------------------
() | Add one to the top of the Third Stack
----------------------------------------------------
{} | Pop the top of the active stack and
| add it to the top of the Third Stack
----------------------------------------------------
[] | Add the stack height to the Third
| Stack
----------------------------------------------------
<>,{,} | Nothing