Використовуйте третій стек
Якщо ви прочитали заголовок, ви можете трохи розгубитися. Напевно, у Brain-Flak є лише два стеки? Однак я запевняю вас, що він існує, і це один з найпотужніших, якщо не найпотужніший інструмент для письма та гольфу Brain-Flak.
Що таке "Третя стека"?
Кожна програма Brain-Flak так чи інакше використовує третій стек, але більша частина використання продовжується за лаштунками, і часто корисно просто ігнорувати факт його існування. Кожна дужка в програмі або додає, або видаляє один елемент із стеку. Три відкритих дужки ([<
всі додають елемент у стек, а їх три кон'югати )]>
видаляють елемент із стека. Значення елемента на стеці - це значення поточного обсягу програми та використання nilads певним чином модифікує це значення. Близькі дужки )
мають унікальну функцію переміщення елемента з третього стеку до поточного стеку; поштовх.
Сподіваємось, це вам стає зрозумілим. Третій стек - це якийсь стек, який запам'ятовує повернені значення коду, які вже були виконані. Давайте розглянемо приклад простої програми, яка відстежує два нормальних стеки та Третій стек.
Приклад
Ми пройдемо наступну програму. Ця програма підштовхується -3, 1, -2
до стеку.
(([()()()])(()))
Починаємо з трьох відкритих дужок, які всі просувають нуль до третьої стеки.
Наші стеки зараз виглядають так: Третій стек знаходиться праворуч, а активний стек має ^
під ним:
0
0
0 0 0
^
(([()()()])(()))
^
Зараз у нас є три ()
нилади. Вони не роблять нічого для звичайних двох стеків, проте кожен додає по одній до вершини Третьої стеки, роблячи наші стеки схожими:
3
0
0 0 0
^
(([()()()])(()))
^
Зараз ми стикаємося з тим, ]
як було сказано перед тим, як закриті дужки видаляють елемент з Третього стеку, але він ]
має функцію віднімання елемента, який він видаляє, у верхній частині стека. Таким чином, наші нові стеки будуть виглядати так:
-3
0 0 0
^
(([()()()])(()))
^
Це має сенс; [...]
чи заперечення так ]
має відняти вниз.
Тепер ми повинні виконати a )
. Як ви, напевно, пам'ятаєте, )
це місце в програмі, де матеріал пересувається до стеку, тому ми будемо переміщувати верхню частину Третього стеку до поточної стеки, крім того, ми додамо -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, але при правильному використанні це робить різницю між пристойним і дивовижним, коли справа стосується гольфу.
Шпаргалку
Ось перелік операцій та те, як вони впливають на Третій стек
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