@0@6000000@5
}0&0&0&0&0
>0@6&3
\\--\/&2
@0/\@4\/&1!!
@4@1..@2@5@3
IIIIIIIIIIII
FF&1FF&2FF&3
@1OO@2OO@3OO
:I
}1..}10001F7
=9&1++..&1&0
&0}0&1&0{1{1
{>\/{0//
:O
}0
+Z
+C
{0
Он работает только для значений до 256, поскольку Marbelous - это 8-битный язык.
Как это устроено
Marbelous - это двумерный язык со значениями, представленными 8-битными шариками, которые падают на одну ячейку на каждом тике, если какое-либо устройство не предотвращает их падение. Эта Marbelous программа состоит из 3 досок; давайте начнем с самого простого:
:O
}0
+Z
+C
{0
:Oявляется названием доски (если быть точным, O является именем и: сообщает интерпретируемому, что эта строка является именем. Давая доскам имя, другие доски могут вызывать их
}0как устройство ввода, это можно рассматривать как аргумент этой функции. Эта ячейка будет заменена входным мрамором (значением) при вызове функции.
+Zдобавляет 35 к любому мрамору, который проходит над ним и позволяет ему проваливаться. +Cделает то же самое, но только добавляет 12. {0является выходной ячейкой Когда шарик достигнет этой ячейки, функция выйдет и вернет значение в этом устройстве вывода.
Итак, все вместе, эта доска принимает одно значение, а затем добавляет 47 к нему. Для нас это означает, что он превращает любое однозначное число в ascii-код цифры -1 (это, конечно, также будет работать для 10).
:I
}1 .. }1 00 01 F7
=9 &1 ++ .. &1 &0
&0 }0 &1 &0 {1 {1
{> \/ {0 //
Эта доска выглядит немного сложнее. Вы должны быть в состоянии идентифицировать :Iкак название платы и заметили некоторые устройства ввода и вывода. Вы заметите, что у нас есть два разных устройства ввода, }0и }1. Это означает, что эта функция принимает 2 входа. Вы также заметите, что есть два экземпляра }1устройства. При вызове функции обе эти ячейки будут содержать одно и то же значение. Устройство }0ввода находится прямо над \/устройством, оно действует как мусорная корзина и удаляет любой мрамор, который падает на него немедленно.
Давайте посмотрим, что происходит с одним из шариков, вставленных в плату }1устройствами ввода:
}1
=9 &1
&0
{>
Он упадет на первый тик и ударит =9устройство. Это сравнивает значение мрамора с 9 и позволяет мрамору провалиться, если утверждение выполнено =9до конца. Мрамор толкается вправо, если нет. &0и &1синхронизаторы. Они держатся за шарики, которые падают на них, пока все другие &nсинхронизаторы также не будут заполнены. Как вы можете ожидать, это условно вызовет другое поведение на некоторой другой части доски.
}1 00 01 F7
++ .. &1 &0
&1 &0 {1 {1
{0 //
Если я скажу вам, что ++это инкрементор, вы уже должны быть в состоянии сказать, чем будут заполнены различные синхронизаторы. Слева &1будет входное значение }1+ 1, &0рядом с ним будет 0 ( 00это языковой литерал, представленный в шестнадцатеричном формате). Второй &1будет содержать значение 1, а правое &0заполнено значением F7, которое вычитает 9 из значения, поскольку сложение в Marbelous равно по модулю 256.
// является дефлектором, который толкает любой мрамор влево, а не дает ему упасть.
Соединение всего этого дает вам следующее: если мрамор }1равен 9, &0синхронизаторы заполняются. Это приведет к тому, что значение 0 попадет на {0выход и F7(или -9) на {1выход. Если }1не 9, {0будет заполнено }1+ 1 и {0будет содержать 1. Существует также {>устройство, это специальный вывод, который выводит мрамор рядом с доской вместо нее. Это будет заполнено, }1если оно будет равно 9.
@0 @6 00 00 00 @5
}0 &0 &0 &0 &0
>0 @6 &3
\\ -- \/ &2
@0 /\ @4 \/ &1 !!
@4 @1 .. @2 @5 @3
II II II II II II
FF &1 FF &2 FF &3
@1 OO @2 OO @3 OO
Хорошо, теперь для большого. Эта доска не имеет явного имени, так как это основная доска файла. Его неявное имя Mb. Вы должны быть в состоянии распознать некоторые клетки. Есть устройство ввода, некоторые языковые литералы ( 00а FF). Есть несколько синхронизаторов и есть дефлектор. давайте пройдемся по этой части за частью.
@0 @6
}0 &0
>0 @6
\\ --
@0 /\ @4
Таким образом, входное значение (вход командной строки, поскольку это основная плата) начинается со второй ячейки сверху, где }0находится. Он упадет и достигнет >0устройства, которое является другим устройством сравнения. любой мрамор больше 0 проваливается, любой другой мрамор сдвигается вправо. (поскольку переменные Marbelous не имеют знака, только ровно 0 будут сдвинуты вправо). Этот мрамор нулевого значения затем попадет в @6устройство. Это портал, который переносит мрамор на другой соответствующий портал, в данном случае прямо над ним. Затем шарик 0 достигнет &0синхронизатора и вызовет некоторые вещи в другом месте.
Если мрамор не равен 0, он падает, отклоняется вправо от \\ударов, --которые уменьшают его на единицу, а затем падает на /\клонера. Это устройство берет мрамор и выводит одну его копию справа и одну слева. Левый @0переместится вверх к другому, где мрамор снова пройдет ту же последовательность. Левый будет взят в другом месте. Это дает нам цикл, который уменьшает ввод командной строки один раз за цикл и запускает некоторое поведение в каждом цикле, пока не достигнет 0. Затем запускается другое поведение.
Давайте посмотрим, что происходит с мрамором, вставленным в @4каждую петлю.
@4 @1 .. @2 @5 @3
II II II II II II
FF &1 FF &2 FF &3
@1 OO @2 OO @3 OO
Здесь есть 3 языковых литерала ( FF), которые сразу попадут в порталы. Эти порталы перенесут их на три IIустройства. IIотносится к доске, которую :Iмы определили ниже по файлу. Так как :Iимеет 2 разных устройства ввода, его представление на другой плате должно иметь ширину 2 ячейки. Поскольку у нас есть 6 ячеек II, мы можем сказать, что у нас есть 3 экземпляра этой функции на доске.
Мраморы FF(или 256, или -1, если хотите) будут находиться во входных ячейках :Iфункции в ожидании, пока не будет достаточно входного мрамора для запуска функции (еще одного). Вот где @4вступает портал. Копия уменьшенного ввода командной строки падает там в каждом цикле. Это активирует крайнюю левую :Iдоску. Изначально со значениями 256 (или -1) и любым другим значением ввода командной строки было -1. Левый мрамор будет помещен в }0устройства :Iдоски, а правый - в }1. Если вы вспомните, что сделала эта доска, вы сможете сказать, к чему это привело. Он выведет увеличенную версию правого входа на левом выходе (и он превратит 9 в 0, а не 10) и выведет 1 или -9 справа.
Увеличенное значение будет перенесено порталом обратно в правую входную ячейку, а значение справа попадет в синхронизатор. Если синхронизатор уже держит мрамор, два мрамора столкнутся. Столкнувшиеся шарики складываются по модулю 256. Таким образом, значения в синхронизаторах сделают следующее: они начинаются пустыми, а затем превращаются в 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, а затем в 1 снова (так как 247 добавляется по модулю 256).
Вы также можете помнить, что шарик выводится вправо, когда входное значение возвращается к 0. Так как :Iдоски находятся рядом друг с другом, эта команда сработает однажды вправо. Это заполнит три синхронизатора значениями, которые на одно больше, чем они должны быть, чтобы быть кратким представлением ввода командной строки, к тому времени, когда это зацикливается до 0.
Вы также можете помнить, что :Oфункция превращает значение в значение ascii цифры, которая представляет значение -1. Выход этих OOячеек будет падать с платы, которая печатает их соответствующие символы ascii в STDOUT.
00 00 00 @5
&0 &0 &0
&3
\/ &2
\/ &1 !!
@5
Так что же происходит, когда мрамор ввода командной строки достигает 0 и заполняет эти &0синхронизаторы? ну, несколько шариков со значением 0 падают и запускают три синхронизатора, которые содержат цифры (+ 1) номера короткого номера в нижней части платы. &3сначала срабатывает, так как содержит самую значимую цифру, затем &2следует &1. Этот мрамор затем телепортируется на другое @5устройство, прежде чем в конечном итоге попасть в !!ячейку, которая завершает доску.
19, 20, 21, 22в десятичном08, 09, 10, 11формате отображается в коротком. Вот почему я так запутался100 -> 89!