Я з гордістю представляю ...
<}74}}:23}29}59}}}}}}}:111_}}}}:::::::23_}:111
? @
:" }}_47}_95 3""""""""(
_ : } _ } {=}
2 23_}29_ _ ; : \
0 ; 3 +_( 3_" 60{ .{.{.
"-_95:}}"" 2 0 ) 2 " _ _ {
"" _ : 2 _ ."(; } 3 .{
;_92}_47} : _ 0 = : * ;
: "" 2 {.{{ . -""(
}}:59_}}:::: "";_ . { _ "
} " {.{.{. 32.
}}}_95:}}}}_20-
... мій новий двовимірний лабіринт езолангу! Наведений вище код не є надзвичайно добре гольф (є 161 пробіл та 25 НОП, тому краща компонування може це значно скоротити), але принаймні мені вдалося показати, що мова використовується для нетривіальних завдань. :)
Як це працює
По-перше, короткий огляд мови:
- Лабіринт функціонує на двох стеках, основній та допоміжної , які можуть містити довільні цілі числа. Внизу обох стеків є нескінченна кількість нулів.
- Команди - це окремі символи на 2D сітці, і вони утворюють лабіринт (тобто невідомі символи, зокрема пробіли, - це стіни).
"
це NOP, який не є стіною і може бути корисним для прокладки певних контурів у коді. На відміну від багатьох інших 2D мов краї не обмотуються.
- Покажчик інструкцій (IP) починається з першого символу, який не є стінним (у порядку читання), рухаючись праворуч.
@
припиняє програму.
- Якщо можливо, IP слід за коридорами (також навколо вигинів). Якщо в IP є кілька комірок для переміщення, він, як правило, поверне ліворуч, якщо верхня частина основного стека є негативною, рухайтеся прямо вперед, якщо вона дорівнює нулю, або поверніть праворуч, якщо вона додатна. Коли IP потрапляє на стіну, він змінює напрямок. (Є ще кілька тонкощів, але вони не мають значення для цього коду.) Це єдиний спосіб реалізувати потоки управління.
- Крім арифметичних і маніпулювання командами стека, вихідний код можна змінювати під час виконання за допомогою чотирьох команд,
>v<^
які циклічно зміщуватимуть рядок або стовпчик вихідного коду на одну клітинку. На який рядок чи стовпець впливає, залежить від верхньої частини стека. Якщо власний рядок або стовпець IP буде зміщений, він переміститься зі зрушенням. Це дає можливість переходити з одного краю вихідного коду на інший.
Тепер для цього конкретного завдання, ось загальна ідея алгоритму:
- Підсуньте кінці автомобілів до капотів (тобто
/ \_o oo o
) на допоміжний штабель.
- Прочитайте введення та визначте, чи потрібно натиснути
__
чи /\
далі.
- Просуньте залишок автомобілів (тобто
__ __ _/ \
два провідні місця) на допоміжний штабель.
- Затисніть вхід до максимального значення
20
, давайте назвемо це N .
- Тепер виконайте наступні 3 рази:
- Друкувати N пробілів.
- Роздрукуйте 6 збережених символів.
- Друк 60 - 3 * N пробілів.
- Роздрукуйте 6 збережених символів.
- Друк нового рядка.
Наостанок розглянемо деякі частини коду. IP починається у верхньому лівому куті за командою зсуву сітки. Верхня частина основного стека є 0
(яка використовується як відносний показник), тому перший рядок зміщується вліво, що також переміщує IP в правий кінець сітки. Тепер перший рядок просто виконується справа наліво, що висуває перший набір фіксованих символів на допоміжний стек:
}74}}:23}29}59}}}}}}}:111_}}}}:::::::23_}:111<
Це зміщення рядків корисно для гольфу, коли потрібно починати з великої кількості лінійного коду.
Далі ми читаємо введення та натискаємо правильні капелюшки:
?
:"
_
2
0 ;
"-_95:}}""
"" _
;_92}_47}
Біт ліворуч із трьома НОП посилає негативні результати по верхній гілці та негативні результати по нижній гілці. Справа вони з'єднані назад.
Тепер слідує ще один великий лінійний розділ (який, мабуть, можна було б отримати в гольф за допомогою іншого трюку, який змінює ряд):
}}_47}_95
: }
23_}29_ _
3
2
:
:
:
}}:59_}}::::
}
}}}_95:}}}}
Це штовхає решту автомобілів на допоміжний штабель.
Далі ми обчислюємо min(20, input)
, що схоже на першу гілку:
;
+_(
0 )
2 _
_ 0
"" 2
"";_
"
_20-
Нарешті, у нас є цикл, який тричі працює для друку рядків. Кожна ітерація циклу містить дві невеликі (3x3) петлі для друку пробілів, а також два розділи для друку 6 символів із допоміжного стеку:
@
3""""""""(
_ } {=}
: \
3_" 60{ .{.{.
2 " _ _ {
."(; } 3 .{
= : * ;
{.{{ . -""(
. { _ "
{.{.{. 32.
Один чудовий трюк, на який я хотів би звернути увагу, - .{.{.
це правий край. Це глухий кут, тому крім .
кінцевого кінця код виконується двічі, один раз вперед і один раз назад. Це дає чіткий спосіб скоротити паліндромний код (суперечка полягає в тому, що вам потрібно переконатися, що ІР приймає правильний поворот при повторному виході з тупику).
/ \
на відміну від вниз_ _
?