7 , 410 символов, 154 байта в кодировке 7, 0 букв = оценка 154
55104010504200144434451510201304004220120504005434473340353241135014335450302052254241052253052244241052335452241114014241310052340435303052335442302052335500302052335430302052313340435303135014243241310335514052312241341351052302245341351525755102440304030434030421030442030424030455733413512410523142410523030523112411350143355142410523414252410523102410523002410523413342411145257551220304010420030455741403
Попробуйте онлайн!
В вызове, который не любит использовать буквы, какой язык лучше использовать, чем язык, состоящий только из цифр?
Это полная программа, которая завершается сбоем, так что в stderr есть посторонний вывод, но stdout верен.
объяснение
Программа 7 на своей первой итерации просто помещает в стек несколько элементов (поскольку из 12 команд, существующих в 7, только 8 из них могут быть представлены в исходной программе, а эти 8 предназначены для написания кода поместить определенные структуры данных в стек). Эта программа не использует 6
команду (которая является самым простым способом создания вложенных структур, но в остальном не стремится буквально появиться в исходной программе), поэтому только 7
команды определяют структуру; 7
помещает новый пустой элемент в верхнюю часть стека (тогда как команды 0
… 5
просто добавляются в верхнюю часть стека). Таким образом, мы можем добавить пробел в программу, чтобы показать ее структуру:
551040105042001444344515102013040042201205040054344 7
33403532411350143354503020522542410522530522442410523354522411140142413100523
40435303052335442302052335500302052335430302052313340435303135014243241310335
514052312241341351052302245341351525 7
55102440304030434030421030442030424030455 7
33413512410523142410523030523112411350143355142410523414252410523102410523002
41052341334241114525 7
551220304010420030455 7
41403
Элементы в конце программы помещаются последними, поэтому они находятся на вершине стека в начале второй итерации. На этой итерации и на всех последующих итерациях интерпретатор 7 автоматически делает копию вершины стека и интерпретирует ее как программу. Литерал 41403
выдвигает (не-литеральный, живой код) 47463
(7 имеет 12 команд, но только у 8 из них есть имена, поэтому я использую жирный шрифт, чтобы показать код, и не жирный, чтобы показать литерал, который генерирует этот код, то есть например, 4
это команда, которая добавляет 4
к верхнему элементу стека). Итак, программа, которая запускается на второй итерации, такова 47463
. Вот что это делает:
47463
4 Поменяйте местами два верхних элемента стека, добавьте пустой элемент между ними
7 Добавьте пустой элемент стека в верхнюю часть стека
4 Поменяйте местами два верхних элемента стека, добавьте пустой элемент между ними
6 Определите, какие команды будут генерировать верхний элемент стека;
добавить это к элементу ниже (и вытолкнуть старую вершину стека)
3 Выведите верхний элемент стека, вставьте элемент ниже
Это легче понять, если мы посмотрим, что происходит со стеком:
- ... d Ĉ б а
47463
(код для запуска: 47463
)
- ... d с б опорожнить а (код для запуска: )
47463
7463
- ... d с б опорожнить в пустой (код для запуска: )
47463
463
- ... d с б пустой пустой пустой а (код для запуска: )
47463
63
- ... d с б пустой пустой « в » (код для запуска: )
47463
3
- … D c b пусто (код для запуска: пусто )
47463
Другими словами, мы берем верхнюю часть стека a , выясняем, какой код, скорее всего, его сгенерировал, и выводим этот код. Интерпретатор 7 автоматически выталкивает пустые элементы из верхней части стека в конце итерации, поэтому мы в итоге получаем 47463
обратную вершину стека, как в исходной программе. Должно быть легко увидеть, что происходит дальше: мы в конечном итоге перелистываем каждый элемент стека один за другим, выводим их все до тех пор, пока стек не опустится и программа не выйдет из строя. Итак, мы в основном создали простой цикл вывода, который просматривает исходный код программы, чтобы определить, что выводить (мы не выводим структуры данных, которые были помещены в стек нашей 0
…5
команды, мы вместо этого воссоздаем, какие команды были использованы, посмотрев, какие структуры были созданы, и вывеся их). Таким образом, первая часть данных выводится 551220304010420030455
(исходный код, который генерирует элемент стека второй сверху), вторая - 3341351…114525
(исходный код, который генерирует элемент стека третий сверху) и так далее.
Очевидно, однако, что эти части исходного кода не выводятся в незашифрованном виде. 7 содержит несколько разных предметно-ориентированных языков для кодирования вывода; после выбора языка, специфичного для домена, он остается в использовании до тех пор, пока не будет явно очищен, но если еще не выбран ни один из языков, первая цифра в коде вывода определяет, какой из языков использовать. В этой программе используются только два языка: 551
и 3
.
551
это довольно просто: в основном это старый код Бодо / телетайпа, используемый для передачи букв по телетайпам в виде 5-битного набора символов, но измененный, чтобы сделать все буквы строчными. Итак, первый кусок кода, который будет выводиться, декодируется следующим образом:
551 22 03 04 01 04 20 03 04 55
c a SP e SP n a SP reset output format
Как видно, мы подгоняем каждый символ в две восьмеричные цифры, что является довольно приличным коэффициентом сжатия. Пары цифр в диапазоне 0-5 дают нам 36 возможностей, в отличие от 32 возможностей, которые нужны Бодо, поэтому оставшиеся четыре используются для специальных команд; в этом случае, 55
в конце очищается запомненный выходной формат, что позволяет нам использовать другой формат для следующей части вывода, которую мы производим.
3
Концептуально даже проще, но с изюминкой. Основная идея состоит в том, чтобы взять группы из трех цифр (опять же, в диапазоне 0-5, так как это те цифры, для которых мы можем гарантировать, что мы можем воссоздать исходный исходный код из его выходных данных), интерпретировать их как трехзначные число в базе 6, и просто выведите его как байт в двоичном виде (что позволяет нам выводить многобайтовые символы в желаемом выводе, просто выводя несколько байтов). Однако поворот заключается в том, что в базе 6 имеется только 216 трехзначных чисел (с возможными ведущими нулями), но 256 возможных байтов. 7 обходит это, связывая числа от 332₆ = 128₁₀ и выше до двух разных байтов; 332
может выводить либо байт 128 или 192, 333
либо байт 129 или 193 и т. д., до 515
которых выводится либо байт 191, либо 255.
Как программа узнает, какую из двух возможностей вывести? Для 520
явного управления этим можно использовать тройки цифр сверху вниз, но в этой программе нам не нужно: 7 по умолчанию выбирает все неоднозначные байты таким образом, чтобы вывод был действительным UTF-8! Оказывается, что всегда есть только один способ сделать это, поэтому, пока мы хотим UTF-8 (и мы делаем в этом случае), мы можем просто оставить это двусмысленным, и программа все равно работает.
Конец каждого из 3…
разделов - это 525
, который сбрасывает выходной формат, позволяя нам вернуться к 551
следующему разделу.
a
s - или нет, в зависимости от того, сколько букв, которые потребуются, потому что 20 символов - это действительно большое наказание (хотя, когда все остальное оценивается байтами, это не совсем хорошо определено ...)!