Используйте третий стек
Если вы прочитали название, вы можете быть немного смущены. Конечно, в Brain-Flak есть только два стека? Тем не менее, я вас уверяю, что он существует и является одним из самых мощных, если не самым мощным инструментом для написания и игры в гольф Brain-Flak.
Что такое «третий стек»?
Каждая программа Brain-Flak так или иначе использует третий стек, но большая часть использования происходит за кулисами, и часто полезно просто игнорировать тот факт, что он существует. Каждая скобка в программе либо добавляет, либо удаляет один элемент из стека. Три из открытых фигурных скобок ([<
добавляют элемент в стек, в то время как все три сопряженных )]>
элемента удаляют элемент из стопки. Значение элемента в стеке - это значение текущей области программы, и использование nilads изменит это значение определенным образом. Закрывающая круглая скобка )
имеет уникальную функцию перемещения элемента из третьего стека в текущий стек; толчок
Надеюсь, вам это станет ясно. Третий стек - это своего рода стек, который запоминает возвращаемые значения кода, который уже был выполнен. Давайте рассмотрим пример простой программы, отслеживающей два обычных стека и третий стэк.
пример
Мы пройдемся по следующей программе. Эта программа выталкивает -3, 1, -2
в стек.
(([()()()])(()))
Мы начинаем с трех открытых фигурных скобок, которые все толкают ноль в третий стек.
Теперь наши стеки выглядят так: третий стэк справа, а активный стек ^
под ним:
0
0
0 0 0
^
(([()()()])(()))
^
Теперь у нас есть три ()
нилада. Они ничего не делают с обычными двумя стеками, но каждый добавляет один к вершине третьего стека, делая наши стеки похожими на:
3
0
0 0 0
^
(([()()()])(()))
^
Теперь мы сталкиваемся с тем, что, ]
как указано выше, закрывающие скобки удаляют элемент из третьего стека, но у ]
него есть функция вычитания удаляемого элемента из вершины стека. Таким образом, наши новые стеки будут выглядеть так:
-3
0 0 0
^
(([()()()])(()))
^
Это имеет смысл; [...]
делает отрицание, поэтому ]
следует вычитать вниз.
Теперь мы должны выполнить )
. Как вы, вероятно, помните, )
это место в программе, где вещи помещаются в стек, поэтому мы будем перемещать вершину третьего стека в текущий стек, кроме того, мы добавим -3
элемент к следующему элементу в третьем стеке.
-3 0 -3
^
(([()()()])(()))
^
Еще раз мы сталкиваемся с одной из наших трех открытых фигурных скобок, поэтому мы добавим еще один элемент в наш третий стек.
0
-3 0 -3
^
(([()()()])(()))
^
Как мы уже говорили ранее ()
, вершина нашего третьего стека будет увеличиваться на единицу.
1
-3 0 -3
^
(([()()()])(()))
^
И )
переместит вершину третьего стека в активный стек и добавит вниз
1
-3 0 -2
^
(([()()()])(()))
^
Последний )
перемещает третий стек в активный стек, и поскольку в третьем стеке не осталось элементов для добавления, он больше ничего не делает.
-2
1
-3 0
^
(([()()()])(()))
^
Программа окончена, поэтому мы завершаем и выводим.
Этот пример предназначен для того, чтобы дать вам представление о том, что такое третий стек. Он не включает все операции, но, надеюсь, вы сможете выяснить, что каждая из них делает самостоятельно. Если вы все еще боретесь, я включил «шпаргалку» в нижней части этого ответа, чтобы помочь вам в этом.
Хорошо, и что?
Хорошо, теперь вы понимаете третий стек, но «и что»? Вы уже использовали его, даже если не называли его «третьим стеком», как мышление в терминах третьего стека помогает вам играть в гольф?
Давайте посмотрим на проблему. Вы хотите взять Треугольник числа . Это сумма всех чисел меньше n.
Один из подходов может состоять в том, чтобы создать аккумулятор в оффстаке и добавить к нему по мере обратного отсчета. Это создает код, который выглядит следующим образом:
(<>)<>{(({}[()])()<>{})<>}{}<>({}<>)
Попробуйте онлайн!
Этот код довольно компактен, и можно подумать, что он не может быть намного меньше. Однако если мы подойдем к нему с точки зрения третьего стека, станет ясно, что это крайне неэффективно. Вместо того, чтобы положить наш аккумулятор в офсет, мы можем поместить его в третий стек с помощью a (
и получить его в конце, который мы используем )
. Мы еще раз пройдемся по всем числам, но на этот раз нам не нужно ничего делать, чтобы увеличить наш третий стек, программа делает это для нас. Это выглядит так:
({()({}[()])}{})
Попробуйте онлайн
Этот код меньше половины размера довольно хорошей версии для гольфа, которую мы сделали ранее. Фактически компьютерный поиск доказал, что эта программа является самой короткой из возможных программ, способных выполнить эту задачу. Эта программа может быть объяснена с использованием подхода «сумма всех прогонов», но я думаю, что она намного более интуитивна и понятна, когда объясняется с использованием подхода третьего стека.
Когда я использую третий стек?
В идеале, всякий раз, когда вы начинаете работу над новой проблемой в Brain-Flak, вы должны подумать про себя, как бы я сделал это с учетом Третьего стека. Однако, как общее практическое правило, когда вам нужно отслеживать какой-то тип аккумулятора или иметь промежуточную сумму, будет хорошей идеей попытаться поместить это в свой третий стек вместо двух реальных стеков.
В другой раз, возможно, стоит подумать об использовании вашего третьего стека, когда у вас нет места для хранения какого-либо значения в двух других стеках. Это может быть особенно полезно, когда вы выполняете манипуляции с двумя существующими стеками и хотите сохранить значение для последующего использования без необходимости отслеживать, где оно находится.
Ограничения третьего стека
Третий стек очень силен во многих отношениях, но у него есть свои ограничения и недостатки.
Во-первых, максимальная высота стека для третьего стека в любой заданной точке определяется во время компиляции. Это означает, что если вы хотите использовать объем пространства в стеке, вы должны выделить это пространство при написании программы.
Во-вторых, третий стек - это не произвольный доступ. Это означает, что вы не можете выполнять какие-либо операции с любым значением, кроме самого верхнего значения. Кроме того, вы не можете перемещать значения в стеке (скажем, поменять местами первые два элемента).
Вывод
Третий стек - это мощный инструмент, и я считаю его необходимым для каждого пользователя Brain-Flak. Это требует некоторого привыкания и изменения вашего мышления о программировании в Brain-Flak, но при правильном использовании это делает разницу между приличным и удивительным, когда дело доходит до игры в гольф.
Cheatsheet
Вот список операций и как они влияют на третий стек
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