В Чертова лестница представляет собой фрактал как функции , связанные с множеством Кантора.
Ваша задача - воспроизвести эту забавную функцию - в искусстве ASCII!
вход
Единственное целое число n >= 0
, указывающее размер вывода. Ввод может быть дан через STDIN, аргумент функции или аргумент командной строки.
Выход
ASCII-арт-исполнение лестницы дьявола по размеру n
, либо возвращено в виде строки, либо напечатано в STDOUT. Конечные пробелы в конце каждого ряда в порядке, но начальные пробелы - нет. При желании вы можете распечатать один завершающий символ новой строки.
Для размера 0
, вывод просто:
x
(При желании вы можете использовать любой другой печатный символ ASCII, кроме пробела, вместо x
.)
По размеру n > 0
мы:
- Возьмите вывод размера
n-1
и растяните каждую строку в три раза - Рифл между рядами одного
x
с - Сдвиньте строки вправо, чтобы
x
в каждом столбце было ровно по одному , а позиции первыхx
минимальны при уменьшении со строками.
Например, вывод для n = 1
:
x
xxx
x
Чтобы получить выходные данные n = 2
, мы растягиваем каждую строку в три раза:
xxx
xxxxxxxxx
xxx
Рифл между рядами синглов x
:
x
xxx
x
xxxxxxxxx
x
xxx
x
Сдвиг вправо:
x
xxx
x
xxxxxxxxx
x
xxx
x
В качестве другого примера, здесь есть n = 3
.
счет
Это код-гольф, поэтому выигрывает решение с наименьшим количеством байтов.
(,],~3^#@~.)@]
вместо(1,[:,1,"0~3*])
сохранения 1 байт. И если вы согласны с!
выводом charu:32+
вместо' #'{~
сохранения другого.#\
вместо того , чтобыi.@#
и вы обгонять APL! :)n-1
не дляn
.Гексагония , 217 байт
Это было очень весело. Спасибо за публикацию этого вызова.
Полное раскрытие: язык (Hexagony) не существовал на момент публикации данного вызова. Тем не менее, я не изобрел его, и язык не был предназначен для этой задачи (или любой другой конкретной задачи).
Выложены шестиугольно:
Программа на самом деле не использует
#
инструкцию, поэтому я использовал этот символ, чтобы показать, какие ячейки действительно не используются.Как работает эта программа? Это зависит. Хотите короткую версию или длинную?
Краткое объяснение
Чтобы проиллюстрировать, что я подразумеваю под «линией» и «сегментом» в следующем объяснении, рассмотрим это разделение предполагаемого результата:
При этом объяснено, что программе соответствует следующий псевдокод:
Длинное объяснение
Пожалуйста, обратитесь к этой цветовой кодовой схеме пути.
Выполнение начинается в верхнем левом углу. Последовательность инструкций
){2'"''3''"2}?)
выполняется (плюс несколько избыточных отмен, как"{
и т. Д.), Следуя по довольно запутанному пути. Начнем с указателя инструкции № 0, выделенного красным. На полпути мы переключаемся на # 1, начиная с правого верхнего угла и окрашиваемого в зеленый лес. Когда IP # 2 начинается с василькового цвета (в центре справа), расположение памяти таково:Во всей программе ребра, обозначенные 2a и 2b , всегда будут иметь значение
2
(мы используем их для вычисления 2ⁿ⁺¹ и деления на 2 соответственно), а ребро, обозначенное 3 , всегда будет3
(мы используем это для вычисления 3ⁱ).Мы вступаем в бизнес, когда вступаем в наш первый цикл, выделенный васильковым синим. Этот цикл выполняет инструкции
(}*{=&}{=
для вычисления значения 2ⁿ⁺¹. Когда цикл завершается, выбирается седло-коричневый путь, который приводит нас к указателю №3. Этот IP просто балансирует вдоль нижнего края на запад в желто-золотом цвете и вскоре передает управление IP # 4.Путь фуксии указывает, как IP # 4, начиная с нижнего левого угла, быстро переходит к уменьшающей строке , устанавливает ch в
32
(символ пробела) и переходит в (новое значение) строку . Это связано с ранним декрементом, что мы фактически начинаем с 2ⁿ⁺¹ − 1 и в конечном итоге испытываем последнюю итерацию со значением 0. Затем мы входим в первый вложенный цикл.Мы обратим наше внимание на ветвящееся индиго, где после краткого уменьшения значения seg мы видим, что ch обновляется,
x
только если seg теперь равен нулю. После этого n устанавливается на line-seg, чтобы определить фактическое число сегмента, в котором мы находимся. Сразу же мы входим в другой цикл, на этот раз в светлом цвете томата.Здесь мы выясняем, сколько раз n (текущий номер сегмента) можно разделить на 2. Пока модуль дает нам ноль, мы увеличиваем i и делим n на 2. Когда мы удовлетворены, n больше не делится таким образом , мы разветвляемся на сланцево-серый, который содержит два цикла: сначала он увеличивает значение 3 до степени i, которую мы вычислили, а затем выводит ch много раз. Заметьте, что первый из этих циклов содержит
[
инструкция, которая переключает управление на IP # 3 - тот, который раньше делал только шаги по нижнему краю. Тело цикла (умножение на 3 и уменьшение) выполняется одиноким IP # 3, заключенным в бесконечный темно-оливково-зеленый цикл по нижнему краю кода. Точно так же второй из этих сланцевых серых циклов содержит]
инструкцию, которая активирует IP # 5 для вывода ch и декремента, показанного здесь темно-индийским красным цветом. В обоих случаях эти указатели инструкций, захваченные в сервитуте, послушно выполняют одну итерацию за раз и возвращают управление обратно к IP # 4 только для того, чтобы подождать, пока их служба будет вызвана снова. Серый шифер, тем временем, воссоединяется со своими братьями цвета фуксии и индиго.Когда seg неизбежно достигает нуля, петля индиго выходит на зеленую дорожку газона, которая просто выводит символ новой строки и быстро сливается обратно в фуксию, чтобы продолжить цикл строки . За последней итерацией цикла строки лежит короткий соболиный путь окончательного завершения программы.
источник
Python 2, 78
Начиная со списка
L=[1]
, мы дублируем его и вставляем следующую степень 3 в середине, что приводит к[1, 3, 1]
. Это повторяется,n
чтобы дать нам длину строк для лестницы дьявола. Затем мы печатаем каждую строку с пробелами.источник
APL, 38
Пример:
Объяснение:
источник
GNU sed, 142
Не самый короткий ответ, но его седь!
Поскольку это sed (никакой нативной арифметики), я берусь за свободу с правилом «Одно целое число n> = 0, указывающее размер вывода» . В этом случае входное целое число должно быть строкой
1
s, длина которой равна n. Я думаю, что это «указывает» размер вывода, даже если он не является прямым числовым эквивалентом n. Таким образом, для n = 2 входная строка будет11
:Похоже, это завершается экспоненциальной временной сложностью O (c n ), где c составляет около 17. n = 8 заняло у меня около 45 минут.
В качестве альтернативы, если требуется, чтобы число n было введено точно, тогда мы можем сделать это:
sed, 274 байта
Выход:
источник
Python 2, 81
Версия программы (88)
Число х в
n
1-й индексируемой строке равно 3 степени (индекс первого установленного битаn
, начиная с lsb).источник
Python 2, 74
Рекурсивный подход. Чертова лестница размером $ n $ разделена на три части
n-1
, длина которой равна3**n - 2**n
x
', длины3**n
n-1
, длина которой3**n - 2**n
Обратите внимание, что общая длина трех частей равна
3*(3**n) - 2*(2**n)
или3**(n+1) - 2**(n+1)
, что подтверждает индукцию.Необязательная переменная
s
хранит смещение текущих частей, которые мы печатаем. Сначала мы возвращаемся к левой ветви с большим смещением, затем печатаем центральную линию, затем делаем правую ветвь с текущим смещением.источник
CJam,
363533 байтаВот еще один подход CJam (я не смотрел на код оптимизатора, поэтому не знаю, сильно ли он отличается):
Это использует
0
для кривой. В качестве альтернативы (используя трюк с grc)который использует
x
.Проверьте это здесь.
объяснение
Основная идея состоит в том, чтобы сначала сформировать массив со строками, как
А затем пройти через этот список, предварительно добавив нужное количество пробелов.
Другая версия работает аналогично, но создает массив длин, например
И затем превращает это в строки
x
s в окончательной карте.источник
Дьялог АПЛ, 34 персонажа
Используя подход grc. Рисует лестницу с
⌹
(домино) символами и принимает ввод от стандартного ввода. Это решение предполагает⎕IO←0
.⎕
Принять вход от стандартного ввода.⌽⍳1+⎕
- последовательность чисел от⎕
нуля до (например3 2 1 0
)3*⌽⍳1+⎕
- три в силу этого (например27 9 3 1
)(⊢,,)/3*⌽⍳1+⎕
- предыдущий результат свернут справа от молчаливой функции,⊢,,
которая равна dfn, дающему{⍵,⍺,⍵}
длину шага лестницы дьявола согласно подходу grc.{⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕
длины шагов преобразуются в шаги.(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕
что само классифицирован, как в моем решении J . Обратите внимание, что результат⊖
уже переворачивается правильно.' ⌹'[(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕]
цифры заменены пробелами и домино.источник
Руби, 99
Другой ответ на мой другой, вдохновленный ответом FUZxxl
FUZxxl отмечает, что числа х соответствуют числу факторов 2 индекса. например, для n = 2 мы имеем следующую факторизацию:
Я использую более простой способ извлечения этих степеней 2:
i=m&-m
что дает последовательность1 2 1 4 1 2 1
и т. Д. Это работает следующим образом:m-1
то же самое, что иm
в его старших значащих битах, но младший бит 1 становится нулем, а все нули справа становятся единицами.Чтобы иметь возможность И это с оригиналом, мы должны перевернуть биты. Есть разные способы сделать это. Один из способов - вычесть это из
-1
.Тогда общая формула
m& (-1 -(m-1))
упрощаетm&(-m)
Пример:
Вот код: новые строки подсчитываются, отступы не нужны и поэтому не учитываются, как мой другой ответ. Это немного длиннее, чем мой другой ответ из-за неуклюжего преобразования из базы 2:
1 2 1 4 1 2 1 etc
в базу 3:1 3 1 9 1 3 1 etc
(есть ли способ избежать этогоMath::
?)источник
Рубин,
14099Мой второй в истории код на Ruby и мое первое нетривиальное использование языка. Предложения приветствуются. Число байтов исключает начальные пробелы для отступов, но включает в себя новые строки (кажется, что большинство новых строк не могут быть удалены, если они не заменены хотя бы пробелом).
Ввод осуществляется путем вызова функции. Выходные данные - это массив строк, которые ruby удобно выводит в стандартный вывод как разделенный новой строкой список с одним
puts
.Алгоритм просто
new iteration
=previous iteration
+extra row of n**3 x's
+previous iteration
. Однако естьмногоизрядное количество кода просто получить начальные пробелы в выходном справа.Редактировать: Руби, 97
При этом используется аналогичный, но другой подход к построению числовой таблицы из всех чисел х, требуемых в массиве,
a
как описано выше, но затем к созданию таблицы строк. Таблица строк строится в массиве в обратном направлении,c
используя довольно странныйunshift
метод для добавления к существующему массиву.В настоящее время этот подход выглядит лучше - но только на 2 байта :-)
источник
for m in(0..n-1)do ... end
наn.times{|m|...}
.n.times
и я наверняка запомню это. Этоend
тоже исключает ! Однако в этом случае мне было интересно, еслиfor m in (1..n)
может быть лучше, чтобы избежать(m+1)
. Есть ли более короткий способ написать это?for
длинный, главным образом потому, что вы вынуждены использоватьend
(вы можете заменить наdo
новую строку или на;
). Для1..n
вас можно использовать1.upto(n){|m|...}
. Мне нравится внешний вид,(1..n).each{|i|...}
но он немного длиннее, чем при использованииupto
. И обратите внимание, что итерация по вызовуeach
илиupto
не просто короче, но и более идиоматичный Ruby.1.upto(n)
это так! С этим и несколькими ненужными скобками у меня уже 120. Я думаю, что ниже 100 возможно, я опубликую пересмотренный код позже.Haskell, 99 символов
Функция
d
:источник
q
и выполнив ихq x=x
в пустом списке. Кроме того, кажется, что круглые скобкиiterate...[1]
не нужны.PHP - 137 байт
Я использую здесь тот же трюк, что и GRC . Вот негольфированная версия:
источник
3**$i
-> похоже на PHP 5.6. Вы должны указать это. Это несовместимо практически с каждой установкой PHP. Чтобы сэкономить вам несколько байтов, вы должны начать с того,$r=str_repeat;
и где у вас есть эта функция, вы можете заменить ее$r
, сэкономив вам 2 байта. Кроме того,$r('x',$v)
может быть,$r(x,$v)
и это будет работать нормально (обратите внимание, что я уже заменил имя функции на переменную). Кроме того, я полагаю, что++$i<=$n
это можно переписать, чтобы$n>++$i
сэкономить еще один байт.function f($n){$r=str_repeat;$a=[1];while($n>++$i)$a=array_merge($a,[3**$i],$a);foreach($a as$v){$o=$r(' ',$s).$r(x,$v)."\r$o";$s+=$v;}echo$o;}
(вместо того, чтобы иметь эту уродливую новую\r
строку, я добавил escape-последовательность внутри строки в двойных кавычках, с переменной$o
внутри нее. Таким образом,"\r$o"
имеет тот же счетчик байтов, что и''.$o
тот, с символом новой строки, опущенным на последний и дает тот же результатwhile
должно быть$n>$i++
для того, чтобы это сокращение работало должным образом.$r=str_repeat
трюк. Я думал только о том$r='str_repeat';
, что не было сохранения ни одного байта. Неопределенная константа - тоже хороший трюк, молодец;). Новая строка на один байт меньше записи\n
, поэтому я сохранил ее, но я использовал двойные кавычки, чтобы избежать конкатенации с$0
. Еще раз спасибо !3 ** $i
я бы сказал, что у вас ужасный синтаксис. Вы можете обратиться к этому исправлению. Я говорю только об этом, а не о том,[1]
что оно пришло из PHP5.4, который довольно «старый». 1 год назад я бы попросил вас уточнить это. Сегодня я прошу вас просто указать (в очень короткой строке), что определяет это. Говоря о коде, у вас все еще есть тот,++$i<=$n
который можно заменить на$n>$i++
. Мне пришлось преобразовать весь ваш код в PHP5.3, чтобы проверить его. Что было больно. Но я вижу, что вы съели 7 байт до сих пор.С 165
Вот тот же код, распакованный и слегка очищенный:
Это основано на той же идее, что и решение проблемы FUZxxl, - использовать явную, а не неявную форму для строк. Объявление j устанавливает его в 2 ^ (n + 1), а первый цикл while вычисляет k = 3 ^ (n + 1); тогда l = 3 ^ (n + 1) -2 ^ (n + 1) - общая ширина лестницы (это не так уж сложно доказать). Затем мы пройдемся по всем числам r от 1 до 2 ^ (n + 1) -1; для каждого, если он делится (точно) на 2 ^ n, тогда мы планируем печатать s = 3 ^ n 'X. l корректируется, чтобы убедиться, что мы начинаем с правильного места: мы пишем l пробелов и s 'X, а затем перевод строки.
источник
(*p)()=putchar;
в начале, чтобы позвонитьputchar
какp
. Я думаю, что это должно работать.CJam,
46 43 41 39 3635 байтОБНОВЛЕНИЕ с использованием другого подхода сейчас.
Старый подход:
Довольно наивно и долго, но с чего-то начать.
Я добавлю объяснение, как только я играю в гольф.
Попробуйте онлайн здесь
источник
Ява,
271269 байтИспользует метод grc.
Отступ:
Любые предложения приветствуются.
2 байта благодаря mbomb007
источник
b.size()>0
вместо!b.isEmpty()
, сохраняя 2 байта.Perl, 62
Сначала вычисляется результат итеративно без начальных пробелов. Затем добавляет их перед каждой строкой в соответствии с количеством
x
символов в оставшейся части строки.источник
JavaScript (ES6) 104
106 118Редактировать Удалена рекурсивная функция, список '*' для каждой строки получается итеративно, с битами и степенями 3 (как во многих других ответах)
Внутри цикла многострочная строка строится снизу вверх, сохраняя счет ведущих пробелов для добавления в каждой строке
Первая попытка удалена
Рекурсивная функция R создает массив с номером '*' для каждой строки. Например, R (2):
[1, 3, 1, 9, 1, 3, 1]
этот массив сканируется для построения многострочной строки снизу вверх, сохраняя текущий счет начальных пробелов для добавления в каждой строке
Тест в консоли Firefox / FireBug
Выход
источник
R - 111 символов
Простая реализация, итеративное построение массива и его медленное уничтожение.
Использование:
источник
n
n=scan()
,x
чтобы использовать его в качестве курсора, и при этом вам не нужноif(n)
. Кроме того, разрывы строк считаются символом, я думаю.x
. Не уверен насчет того,if(n)
однако. Я добавил эту часть, чтобы разобраться с деломn=0
.if(n)
Затем возвращаетсяF
и , следовательно , возвращает одинx
. Если я удаляю его,n=0
дает нежелательные результаты. Новое здесь, поэтому не знал о переносах строк. Включено сейчас!a=0
и запустите цикл,x in 0:n
он также работает для n = 0. Тогда вы можете опуститьif(n)
.