Краткая история языков программирования 2D: 16 (+2) лет
v19977/2{@{{4{\_______>/02&&&#???? * P+++++1P1P-1P+1E * *
\'\02'oo100@n590@n; * * *
>"8991",,,;5-;,@ * * *
* * * *
\ * ++++++++++++++++++++++++ ++++++++++++++++++++++++ ++O--OO++++++++OX******* *
* #2018O@ * * * * * * *
* * * * * * * *
* * * * * * * *
* **** **** * **** **** * **** **** * **** *****
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * *
* * * **** * * * * **** * * * * **** * * * * ****
* * * * * * * * * * * * * * * *
R"2014"; ***** ******* ****** ******* ****** ******* ****** *******
x
x%"2010"x
x
$'main' \/\/\/\
\-[2005]o-# \++++++\
/++++++/
\++++++\
/++++++/
\/\/\/\++.--..+++.#
S1^2^2^6^8MAOUOAOOF
/K:0:1:@
> "7102"4&o@
| }+++++[>++++++++++<-]>.--..++++++.@
Я упоминал, что мне нравятся двумерные языки программирования?
Язык, на котором (предположительно, см. Последний раздел) все началось. В Befunge вы можете перенаправить поток управления с помощью <v>^
, но теперь вездесущих зеркал еще \
и /
не было. Интерпретатор Befunge, используемый на Anarchy Golf, игнорирует неизвестные команды. Мы можем использовать это, чтобы отличить семью Befunge от семьи> <>. Следовательно, код, выполняемый Befunge, таков:
v
\
>"8991",,,;5-;,@
"8991"
Раздвигает отдельные символы в стек. ,,,
печатает первые три из них. Тогда ;
неизвестен (который мы будем использовать, чтобы отличить его от Befunge 98), 5-
превращает 8
в a 3
и ,
печатает, что также до @
завершения программы.
Написание этой части решения заняло у меня, вероятно, столько же времени, сколько и написание всех остальных и сборка их вместе ...
Верд знает только два символа: пробел и все остальное. Указатель инструкции пытается следовать по пути, образованному непробельными символами, начиная по диагонали из верхнего левого угла и всегда стараясь идти как можно более прямым. Изгибы в пути формируют фактические инструкции (с степенями поворота, определяющими, какую инструкцию выполнить). Итак, код, который видит Wierd:
v1997 * * *
' * * *
8 * * *
* * * *
* ++++++++++++++++++++++++ ++++++++++++++++++++++++ ++O--OO++++++++OX******* *
* * * * * * * *
* * * * * * * *
* * * * * * * *
* **** **** * **** **** * **** **** * **** *****
* * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * *
* * * **** * * * * **** * * * * **** * * * * ****
* * * * * * * * * * * * * * * *
***** ******* ****** ******* ****** ******* ****** *******
1997
На самом верху на самом деле не выполняется, но Wierd позволяет нам читать его из исходного кода, который является намного короче , чем пытаться строить коды символов для себя четырех цифр (даже если он не похож на него .. .). Я не хочу ломать всю эту штуку, но вы можете ясно видеть четыре повторяющихся раздела. Это то, что мы сначала сохраняем 1
в стеке, а затем каждый из этих четырех разделов увеличивает это 1
, а затем разветвляет. Нижняя ветвь отталкивает другую1
, получает исходный символ в этих координатах и печатает его, тогда как верхняя ветвь перенаправляется в следующий раздел. Вы можете удивиться, почему концы путей так неоправданно длинны, но это потому, что когда Wierd достигает конца пути, он пытается перейти к соседнему пути, прежде чем решить, что он должен завершить текущую ветвь. Чтобы избежать этого, нам нужно отодвинуть эти концы достаточно далеко от любого другого кода.
Befunge получил довольно известное обновление в 1998 году с очень строгой спецификацией, которая может быть обобщена на произвольные измерения (и я думаю, что также на произвольные топологии). Тем не менее, он в значительной степени обратно совместим с Befunge, что позволяет довольно легко объединить их воедино. В этом Befunge все еще не было зеркал, поэтому выполненный путь такой же, как и в Befunge 93:
v
\
>"8991",,,;5-;,@
Разница в том, что Befunge 98 не игнорирует ;
. Вместо этого он действует как комментарий, в котором все команды до следующей ;
игнорируются. Таким образом, мы не уменьшаем это 8
до 3
и печатаем 1998
как есть.
2001: космический од ... пинг-понг
2001 год - год Пита, но я действительно не хотел полиглотировать файл изображения со всеми остальными программами, так что это менее известный 2D-язык. Кажется, у него довольно много функций (которые мы не собираемся использовать). Спасибо Sp3000 за поиск оригинального переводчика (который является единственной неработающей ссылкой в архивной версии официального сайта).
PingPong несколько необычен тем, что в нем есть только зеркала и нет <v>^
перенаправителей. Таким образом, он перемещается v19977
в начало, а затем попадает в зеркало, которое оборачивает его на дно. Соответствующий код тогда:
v19977/
...
/K:0:1:@
...
Фактический код довольно прост: K
нажимает 20
, цифры нажимают сами, :
выводят целое число и @
завершают программу.
Это первый язык, где все становится немного проще, потому что SNUSP поддерживает явную точку входа. Эта точка входа помечена $
. Судя по некоторым статьям о esolangs, этот язык вдохновил несколько других, но, к сожалению, в конце концов, это всего лишь производная от Brainfuck. Тем не менее, я думаю, что способ установки текущей ячейки на 48 является довольно аккуратным (и был украден из статьи esolangs). Вот соответствующая часть кода:
$'main' \/\/\/\
\++++++\
/++++++/
\++++++\
/++++++/
\/\/\/\++.--..+++.#
Это 24 +
с, и зеркала отправляют IP через каждый ровно дважды.
По какой - то причине, этот язык действительно есть <^>
редиректоры , но вместо обычного v
он использует %
. Следовательно это только перемещается через первую строку. Соответствующий код:
v19977/2{@{{4{\
Для начала нажимаем несколько цифр, выполняем деление. Затем 2{
печатает 2
, @
очищает стек. {{
печатает два (неявных) 0
с. 4{
печатает 4
и \
завершает программу.
2005 был трудным выбором. Ни один другой год я не нашел так много 2D-языков, и есть ADJUST и Archway, оба из которых начинаются в нижнем левом углу (что сделало бы их легким дополнением). Хотя мне нравится Rail, и поскольку он имеет явную точку входа, добавить его тоже не сложно. Железная дорога ищет линию, начинающуюся с, $'main'
и начинает двигаться на юго-восток от $
. Это означает, что соответствующий код:
$'main'
\-[2005]o-#
The \
и -
являются просто треками (без операций). [2005]
Строковый литерал , который o
печатает до того #
завершает программу.
Двумерный Brainfuck. В этом году есть еще один интересный язык, называемый черным, который начинается с координаты (3,3)
(на основе 1), что также сделало бы интересным использование этого в полиглоте. Я не мог найти переводчика, хотя. Так что вместо этого нам придется работать с другой BF-производной ...
Интересно, что он не форматирует сетку в строки с переводами строк, как большинство других 2D-языков. Вместо этого |
используется в качестве разделителя строк. Так как я не использовал |
другие языки, я мог бы просто поставить |
в последнюю строку, что делает всю остальную часть программы одной строкой, что касается BF.js. Соответствующий код - это (превращение |
в реальный перевод строки):
v19977/2{...
}+++++[>++++++++++<-]>.--..++++++.@
BF.js не использует ни <v>^
зеркал. Единственный способ перенаправить поток управления - {}
это повернуть направление IP на 90 °. Таким образом, эти скобки перемещают IP на вторую строку. Остальная часть представляет собой простое решение Brainfuck (не особенно удачное), которое устанавливает ячейку в 50
(кодовую точку 2
), а затем печатает 2006
, немного сдвигая значение. @
завершает программу
В этом году я действительно хотел использовать DOBELA, которая использует несколько точек входа и выглядит как любовь детей Fission и Ziim . К сожалению, я не смог заставить переводчика работать. Итак, вот еще одна производная от BF (последняя, обещаю).
В отличие от последнего, этот знает как <v>^
и зеркала, так что соответствующий код:
v
\'\
8
\ * ++++++++++++++++++++++++ ++++++++++++++++++++++++ ++O--OO++++++++OX
У этого нет обычного []
цикла в стиле BF (вместо этого вам нужно сформировать реальный 2D-цикл), поэтому я просто решил жестко закодировать его, 50
так как в любом случае у меня было множество символов подряд от Wierd. Обратите внимание, что '
и 8
игнорируются, *
это условный батут, который мы можем игнорировать, и O
это Брейнфак .
. Завершает X
программу.
Вероятно, самый популярный Fungeoid (кроме самого Befunge), по крайней мере, вокруг этих частей. > <> имеет <v>^
и зеркала, и строковые литералы, поэтому исполняемый код такой:
v
\'\02'oo100@n590@n;
Строковый литерал в основном служит для пропуска того, что \
мы использовали для BrainSpace 1.0, но пока мы на нем, мы могли бы также нажать первые два символа. oo
печатает их. Затем 100
толкает три цифры, @
толкает верхнюю вниз и n
печатает нижнюю 0
. Мы делаем то же самое снова, с помощью 590
которого печатает 9
. Если вам интересно, почему я не просто печатаю 2009
как есть, дождитесь 2015 года. ;
Завершает программу.
Этот был прост, потому что он имеет явную точку входа в %
. Однако этот создает 4 IP-адреса во всех направлениях (я полагаю, отсюда и название языка), и нам нужно избавиться от 3 из них. Вот соответствующий код:
x
x%"2010"x
x
Ну, да. (В Cardinal строковый режим печатает напрямую, а не помещает символы в стек.)
Другой язык с явной точкой входа ( Дэвид Кэтт, который создал несколько других очень хороших esolangs), на этот раз в S
. Это делает соответствующий код этой частью:
S1^2^2^6^8MAOUOAOOF
RunR немного интересен, потому что большинство операций работают с своего рода регистром, и значения должны быть явно перемещены в стек для двоичных операций. Цифры устанавливают значения регистров для себя и ^
помещают текущий регистр в стек. Затем M
происходит умножение (значение регистра в разрядах, извлеченное из стека), U
вычитание, A
сложение, O
вывод. F
завершает программу
Как и Wierd, Ropy пытается следовать разделам непробельных символов, но здесь изгибы не определяют команды. Фактически получается, что Ropy больше похож на мой собственный Лабиринт в том смысле, что выбранное направление зависит от вершины стека. Однако нам не нужно беспокоиться об этом здесь, потому что Ропи просто движется вдоль первой строки:
v19977/2{@{{4{\_______>/02&&&#????
Есть много вещей, которые мы можем игнорировать вплоть до >
. Все, что нам нужно знать, это то, что вершина стека в этот момент будет a, 4
а там будет 2
ниже.
>
дублирует 4
, /
деление превращая его в 1
. Тогда мы нажимаем 02
. &&&
соединяет четыре верхних числа стека в обратном порядке, давая 2012
. #
выводит это. ????
просто очищает стек, потому что в противном случае вершина стека также выводится.
Одна точка интереса является то , что второй 7
в 19977
добавляли из тягучей. /
Подразделение в тягучей делает top / second
(противоположность обычному порядку на многих языках стековых), где 7 / 9
дал бы 0
. Если бы у нас был ноль на вершине стека, Ropy делал бы какие-то дикие вещи со своим направлением движения, поэтому нам нужно подтолкнуть другого, 7
чтобы убедиться, что вершина стека остается положительной, а Ropy продолжает двигаться на восток.
С его точными точками входа, это легко. RDLU
создайте атомы (указатели инструкций) в соответствующем направлении, поэтому соответствующий бит будет следующим:
R"2014";
Обратите внимание, что U
в исходном коде также есть a , но этот атом в конечном итоге попадает в один из *
from от Wierd, что завершает программу (и этот атом занимает намного больше времени, чем R
необходимо для печати 2014
).
Более мощная производная от Sp3000> <>. Он в значительной степени обратно совместим с> <>, поэтому исполняемый код по-прежнему:
v
\'\02'oo100@n590@n;
Тем не менее, направление вращения @
было изменено, что является стандартным приемом для различения> <> и Gol> <> в полиглотах, поэтому этот выводится 15
вместо 09
. Отсюда и странности во второй половине программы.
CSL довольно интересен тем, что команды не выполняются сразу. Вместо этого каждая команда помещается в командном стек и e
и E
может быть использована для выполнения команд от него. Соответствующий код становится:
v19977/2{@{{4{\_______>/02&&&#???? * P+++++1P1P-1P+1E
Таким образом, E
исполняется весь стек команд, что означает, что материал перед ним выполняется в обратном порядке. Нам нужно только взглянуть на *
:
1+P1-P1P1+++++P*
Они 1
помещают себя в стек данных. +
и -
уменьшение / приращение. P
печатает вершину стека. Затем *
пытается умножить два верхних значения стека. Тем не менее, стек пуст, поэтому это завершает программу.
На этом этапе мы попадаем на языки, которые были выпущены после публикации этого задания, поэтому я не особо рассчитываю их на балл, тем более, что я создал их сам (но не с учетом этого вызова). Тем не менее, у них есть некоторая новая семантика перемещения IP, которая позволила легко вписать их в полиглот, а также добавить что-то интересное в эту витрину двумерных языков.
Алиса была разработана, чтобы быть многофункциональным Fungeoid. Одним интересным отличием для большинства (но не всех) других 2D-языков является то, что IP может перемещаться либо ортогонально, либо по диагонали. Переключение между ними также меняет семантику почти всех команд в языке. Кроме того, Алиса поддерживает как традиционные <^>v
регуляторы направления, так и \/
зеркала, но зеркала в Алисе имеют уникальное поведение (что позволяет легко привести IP Алисы к пока неиспользованной части кода).
В то время как большинство языков рассматривают \
и /
как если бы они были зеркалами под углом 45 °, а IP - как отраженный от него луч света, Алиса рассматривает их как имеющие угол 67,5 ° (который ближе к углу фактических глифов косой черты) и IP также перемещается через зеркало (отсюда и название языка). Благодаря этому углу зеркала переключаются между движениями в ортогональном или диагональном направлениях. Кроме того, в то время как в обычном режиме (то есть, когда IP движется по диагонали), сетка не переворачивается, а вместо этого IP отскакивает от краев (тогда как в кардинальном режиме она оборачивается).
В общем, код, выполняемый Алисой, следующий:
v19
\ \
...
> "7102"4&o@
...
IP начинается в верхнем левом углу как обычно, v
отправляет его на юг. Теперь \
IP отражает перемещение на северо-запад, где он сразу же отскакивает от левого края сетки (и вместо этого перемещается на северо-восток). 1
можно игнорировать, IP отскакивает от верхнего края, чтобы двигаться дальше на юго-восток. Мы попали в другую, \
которая отражает IP севера. 9
также может быть проигнорировано, а затем IP-адрес переходит в нижнюю часть сетки. Через пару строк мы перенаправим его на восток >
для удобства. Затем "7102"
выдвигает кодовые точки 2017
, 4&o
печатает эти четыре символа и @
завершает программу.
Wumpus - это первый двумерный язык в треугольной сетке, который делает движение в коде совершенно другим (и снова позволяет легко найти неиспользуемую часть кода). Поэтому вместо того, чтобы думать о каждом персонаже в сетке как о маленьком квадрате, вы должны думать о них как о чередующихся треугольниках вверх и вниз. Верхний левый угол - это всегда восходящий треугольник.
У Wumpus нет таких регуляторов, как у него <^>v
, но у него есть зеркала \/
. Однако из-за треугольной сетки они работают не так, как большинство других языков. IP отражается от них, как луч света (как обычно), но вы должны думать, что они имеют угол 60 °. Таким образом, IP, движущийся на восток, в конечном итоге будет двигаться вдоль северо-западной оси сетки.
Как еще одно отличие от большинства других языков, края сетки не переносятся, но вместо этого IP отскакивает от краев (как если бы эти краевые ячейки содержали соответствующие зеркала). Еще одна забавная маленькая деталь в том, что диагонали через треугольную сетку на самом деле похожи на лестницы в исходном коде.
Имея это в виду, код, выполняемый Wumpus, выглядит следующим образом (где я заменил пробелы .
на ясность:
v19977/
02
89
..
..
.....*...#2018O@
Это v19977
просто мусор, который мы можем игнорировать. /
отправляет IP на северо-запад, где он 977
снова проходит (справа), отскакивая от верхнего края. Затем IP перемещается на юго-запад через 2089
кучу пробелов, прежде чем он достигнет левого края, чтобы снова отразиться на восток. *
тоже мусор. Затем, наконец, #2018
нажимает 2018
, O
печатает его и @
завершает программу.
Недостающие годы
Наконец, некоторые заметки о годах, которые я не освещал.
Исследуя 2D-языки, чтобы найти подходящие по годам языки, которые можно было бы использовать в полиглоте, я обнаружил, что вопреки распространенному мнению, Befunge не был первым 2D-языком. Похоже, что этот титул принадлежит компании Biota, которая была создана в 1991 году. К сожалению, у языка нет вывода, поэтому я не смог использовать его для этой задачи.
Насколько я могу судить, 2D-языки не были созданы в 1992 и 1995 годах. Осталось несколько лет, которые я не освещал:
- 1994: Orthagonal был создан независимо от Befunge. Языки семантически очень похожи на самом деле, но Orthagonal фактически не выкладывает исходный код в 2D. Вместо этого каждая строка является
(x, y, instruction)
кортежем. Я даже получил спецификацию языка и оригинальный интерпретатор от создателя Джеффа Эплера, но в итоге тот факт, что синтаксис не является 2D, сделал язык непригодным для этого полиглота.
- 1996: Orthogonal , был создан преемник Orthagonal (созданный кем-то другим), но для целей этого полиглота возникают те же проблемы, что и для Orthagonal.
- 1999: Единственный язык, который я смог найти, был клеточный автомат Криса Пресси REDGREEN . К сожалению, в отличие от своего предшественника RUBE, у него, похоже, нет семантики ввода / вывода.
- 2000: есть еще один сотовый автомат Криса Пресси, который называется noit o 'mnain worb, но у него также нет ввода / вывода. Есть также Numberix, который я не пытался запустить, и я не уверен, будет ли он игнорировать не шестнадцатеричные символы в исходном коде.
- 2002: есть Clunk без I / O и ZT, чья языковая спецификация ужасает меня.
- 2007: я нашел три языка здесь. Zetaplex основан на изображениях (так что нет), и RubE On Conveyor Belts, похоже, требует заголовка с довольно строгим форматом, который мог бы испортиться в первой строке программы. Есть также Cellbrain от Quintopia, но, похоже, он требует особого заголовка.
- 2013: Опять я нашел три языка. Рыбалка может быть возможна при хорошей реструктуризации, но для начала потребуется программа с действующим доком. Quipu , по памяти, слишком строг в своем синтаксисе, чтобы разрешить много полиглотов. И Рыба-меч - еще один член семьи> <>, но, к сожалению, я не смог найти переводчика. В противном случае, это, вероятно, было бы довольно легко добавить.
Если кому-то интересно, вот полный список реализованных 2D-языков, отсортированный по годам, насколько я мог их найти (на момент публикации этого ответа). Если что-то отсутствует в этом списке, пожалуйста, дайте мне знать в чате, так как я был бы действительно заинтересован в полном списке.