Нарисуй Лестницу Дьявола

46

В Чертова лестница представляет собой фрактал как функции , связанные с множеством Кантора.

введите описание изображения здесь

Ваша задача - воспроизвести эту забавную функцию - в искусстве 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.

счет

Это код-гольф, поэтому выигрывает решение с наименьшим количеством байтов.

Sp3000
источник

Ответы:

7

Пиф, 30

jb_u+G+*leGd*HNu+N+^3hTNUQ]1]k

Это программа, которая принимает данные из STDIN и использует метод grc для поиска множества Кантора. Использует символ "для отображения кривой.

Попробуйте это онлайн здесь.

Объяснение:

Я объясню код в двух частях, во-первых, генерация канторного набора:

u+N+^3hTNUQ]1
u        UQ]1         : reduce( ... , over range(input), starting with [1])
 +N                   : lambda N,T: N + ...
   +^3hTN             : 3 ** (T+1) + N   (int + list in pyth is interpreted as [int] + list)

И форматирование вывода:

jb_u+G+*leGd*HN    ]k
jb_                    : "\n".join(reversed(...)
   u               ]k  : reduce(lambda G,H: ... , over cantor set, starting with [""])
    +G+*leGd           : G + len(G[-1]) * " " + ...
            *HN        : H * '"'

Обратите внимание, что в pyth N = '"' по умолчанию.

оборота FryAmTheEggman
источник
32

J ( 73 68 58 41 39 38 35 34 знака)

Поразмыслив над проблемой в течение некоторого времени, я нашел совершенно другой способ генерирования паттерна Лестницы Дьявола. Старый ответ, включая его объяснение, был удален. Вы можете просмотреть редакции этого ответа, чтобы выяснить, как это было.

Этот ответ возвращает массив заготовок и острых предметов, представляющих лестницу дьявола.

' #'{~1(]|.@=@#~[:,3^q:)2}.@i.@^>:

Вот ответ, разделенный на две части в явном виде:

f =: 3 : '|. = (, 3 ^ 1 q: y) # y'
g =: 3 : '(f }. i. 2 ^ >: y) { '' #'''

объяснение

Подход немного другой, так что наблюдайте и удивляйтесь.

  1. >: 3 - три приращенных, то есть

    4
    
  2. 2 ^ >: 3 - два к степени трех приращены, то есть

    16
    
  3. i. 2 ^ >: 3- первые 2 ^ >: 3целые числа, то есть

    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    
  4. }. i. 2 ^ 4- первые 2 ^ >: 3целые числа, обезглавленные, то есть

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
    

    Давайте назовем эту последовательность s; мы входим fсейчас.

  5. 1 q: s- показатели степени 2 в простом разложении каждого элемента s. В общем, x q: yдает таблицу показателей для первых xпростых чисел в простом разложении y. Это дает:

    0
    1
    0
    2
    0
    1
    0
    3
    0
    1
    0
    2
    0
    1
    0
    
  6. 3 ^ 1 q: s - три в степень этих показателей, то есть

     1
     3
     1
     9
     1
     3
     1
    27
     1
     3
     1
     9
     1
     3
     1
    
  7. , 3 ^ 1 q: s- ravel (то есть аргумент с его структурой, свернутой в вектор) предыдущего результата. Это необходимо, потому что q:вводит нежелательную трейлинг-ось. Это дает

     1 3 1 9 1 3 1 27 1 3 1 9 1 3 1
    
  8. (, 3 ^ 1 q: s) # s- каждый элемент sреплицируется так же часто, как и соответствующий элемент в предыдущем результате, то есть

    1 2 2 2 3 4 4 4 4 4 4 4 4 4 5 6 6 6 7 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 8 9 10 10 10 11 12 12 12 12 12 12 12 12 12 13 14 14 14 15
    
  9. = (, 3 ^ 1 q: s) # s - самостоятельная классификация предыдущего результата, то есть матрица, в которой каждая строка представляет один из уникальных элементов аргумента, каждый столбец представляет соответствующий элемент аргумента, а каждая ячейка представляет, равны ли элементы строки и столбца, это,

    1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0
    0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
    
  10. |. = (, 3 ^ 1 q: s) # s - предыдущий результат перевернулся вдоль вертикальной оси.

  11. (|. = (, 3 ^ 1 q: s) # s) { ' #'- элементы предыдущего результата, используемые в качестве индексов в массиве ' #', поэтому 0заменяются  и 1заменяются #, то есть

                                                                    #
                                                                 ### 
                                                                #    
                                                       #########     
                                                      #              
                                                   ###               
                                                  #                  
                       ###########################                   
                      #                                              
                   ###                                               
                  #                                                  
         #########                                                   
        #                                                            
     ###                                                             
    #      
    

    результат, которого мы хотим.

FUZxxl
источник
Внутри силовой петли (,],~3^#@~.)@]вместо (1,[:,1,"0~3*]) сохранения 1 байт. И если вы согласны с !выводом char u:32+вместо ' #'{~сохранения другого.
Рандомра
#\ вместо того , чтобы i.@#и вы обгонять APL! :)
randomra
Ваше второе решение не работает, потому что потребуется ограничение, но я нашел другой способ победить APL.
FUZxxl
Новый выход - лестница для n-1не для n.
Рандомра
@randomra Ах ... это дерьмо. Дай мне посмотреть, можно ли это исправить.
FUZxxl
26

Гексагония , 217 байт

Это было очень весело. Спасибо за публикацию этого вызова.

Полное раскрытие: язык (Hexagony) не существовал на момент публикации данного вызова. Тем не менее, я не изобрел его, и язык не был предназначен для этой задачи (или любой другой конкретной задачи).

){_2"_{\"{{""}"{'2//_.\><*\"\/_><[\]/3\'\_;|#__/(\2\'3_'}(#:|{$#{>_\//(#={/;01*&"\\_|[##={|}$_#></)]$_##|){*_.>.(/?#//~-="{}<_"=#/\}.>"%<.{#{x\"<#_/=&{./1#_#>__<_'\/"#|@_|/{=/'|\"".{/>}]#]>(_<\'{\&#|>=&{{(\=/\{*'"]<$_

Выложены шестиугольно:

        ) { _ 2 " _ { \ "
       { { " " } " { ' 2 /
      / _ . \ > < * \ " \ /
     _ > < [ \ ] / 3 \ ' \ _
    ; | # _ _ / ( \ 2 \ ' 3 _
   ' } ( # : | { $ # { > _ \ /
  / ( # = { / ; 0 1 * & " \ \ _
 | [ # # = { | } $ _ # > < / ) ]
$ _ # # | ) { * _ . > . ( / ? # /
 / ~ - = " { } < _ " = # / \ } .
  > " % < . { # { x \ " < # _ /
   = & { . / 1 # _ # > _ _ < _
    ' \ / " # | @ _ | / { = /
     ' | \ " " . { / > } ] #
      ] > ( _ < \ ' { \ & #
       | > = & { { ( \ = /
        \ { * ' " ] < $ _

Программа на самом деле не использует #инструкцию, поэтому я использовал этот символ, чтобы показать, какие ячейки действительно не используются.

Как работает эта программа? Это зависит. Хотите короткую версию или длинную?

Краткое объяснение

Чтобы проиллюстрировать, что я подразумеваю под «линией» и «сегментом» в следующем объяснении, рассмотрим это разделение предполагаемого результата:

segments →
 │   │ │         │ │   │x   lines
─┼───┼─┼─────────┼─┼───┼─     ↓
 │   │ │         │ │xxx│
─┼───┼─┼─────────┼─┼───┘
 │   │ │         │x│
─┼───┼─┼─────────┼─┘
 │   │ │xxxxxxxxx│
─┼───┼─┼─────────┘
 │   │x│
─┼───┼─┘
 │xxx│
─┼───┘
x│

При этом объяснено, что программе соответствует следующий псевдокод:

n = get integer from stdin

# Calculate the number of lines we need to output.
line = pow(2, n+1)

while line > 0:
    line = line - 1

    # For all segments except the last, the character to use is spaces.
    ch = ' ' (space, ASCII 32)

    # The number of segments in each line is
    # equal to the line number, counting down.
    seg = line

    while seg > 0:
        seg = seg - 1

        # For the last segment, use x’s.
        if seg = 0:
            ch = 'x' (ASCII 120)

        # Calculate the actual segment number, where the leftmost is 1
        n = line - seg

        # Output the segment
        i = pow(3, number of times n can be divided by 2)
        i times: output ch

    output '\n' (newline, ASCII 10)

end program

Длинное объяснение

Пожалуйста, обратитесь к этой цветовой кодовой схеме пути.

Путь исполнения

Выполнение начинается в верхнем левом углу. Последовательность инструкций ){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 неизбежно достигает нуля, петля индиго выходит на зеленую дорожку газона, которая просто выводит символ новой строки и быстро сливается обратно в фуксию, чтобы продолжить цикл строки . За последней итерацией цикла строки лежит короткий соболиный путь окончательного завершения программы.

Timwi
источник
8
Теперь это просто старомодное безумие.
FUZxxl
21

Python 2, 78

L=[1]
i=3
exec"L+=[i]+L;i*=3;"*input()
while L:x=L.pop();print' '*sum(L)+'x'*x

Начиная со списка L=[1], мы дублируем его и вставляем следующую степень 3 в середине, что приводит к [1, 3, 1]. Это повторяется, nчтобы дать нам длину строк для лестницы дьявола. Затем мы печатаем каждую строку с пробелами.

GRC
источник
20

APL, 38

⊖↑'x'/⍨¨D,⍨¨0,¯1↓-+\D←{1,⍨∊1,⍪3×⍵}⍣⎕,1

Пример:

      ⊖↑'x'/⍨¨D,⍨¨0,¯1↓-+\D←{1,⍨∊1,⍪3×⍵}⍣⎕,1
⎕:
      2
                  x
               xxx 
              x    
     xxxxxxxxx     
    x              
 xxx               
x   

Объяснение:

⊖↑'x'/⍨¨D,⍨¨0,¯1↓-+\D←{1,⍨∊1,⍪3×⍵}⍣⎕,1

                                     ⎕       ⍝ read a number from the keyboard
                       {           }⍣ ,1      ⍝ apply this function N times to [1]
                               3×⍵           ⍝ multiply each value by 3
                           ∊1,⍪               ⍝ add an 1 in front of each value
                        1,⍨                  ⍝ add an 1 to the end
                     D←                      ⍝ store values in D (lengths of rows)
                   +\                        ⍝ get running sum of D
                  -                          ⍝ negate (negative values on / give spaces)
             0,¯1↓                           ⍝ remove last item and add a 0 to the beginning
                                             ⍝ (each row needs offset of total length of preceding rows)   
         D,⍨¨                                ⍝ join each offset with each row length
   'x'/⍨¨                                    ⍝ get the right number of x-es and spaces for each row
 ↑                                           ⍝ make a matrix out of the rows
⊖                                            ⍝ mirror horizontally 
Мэринус
источник
Это хорошее решение.
FUZxxl
20
Мне нравится, что объяснение кода выглядит как Лестница Дьявола.
Алекс А.
Я нашел еще более короткое решение APL.
FUZxxl
14

GNU sed, 142

Не самый короткий ответ, но его седь!

s/$/:/
:l
s/x/xxx/g
s/:/:x:/g
tb
:b
s/^1//
tl
s/:x/X/g
s/^/:/
:m
s/.*:([Xx]+)Xx*:$/&\1:/
tm
:n
s/([ :])[Xx](x*Xx*)/\1 \2/g
tn
s/:/\n/g
s/X/x/g

Поскольку это sed (никакой нативной арифметики), я берусь за свободу с правилом «Одно целое число n> = 0, указывающее размер вывода» . В этом случае входное целое число должно быть строкой 1s, длина которой равна n. Я думаю, что это «указывает» размер вывода, даже если он не является прямым числовым эквивалентом n. Таким образом, для n = 2 входная строка будет 11:

$ echo 11 | sed -rf devils-staircase.sed

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

$ 

Похоже, это завершается экспоненциальной временной сложностью O (c n ), где c составляет около 17. n = 8 заняло у меня около 45 минут.


В качестве альтернативы, если требуется, чтобы число n было введено точно, тогда мы можем сделать это:

sed, 274 байта

s/[0-9]/<&/g
s/9/8Z/g
s/8/7Z/g
s/7/6Z/g
s/6/5Z/g
s/5/4Z/g
s/4/3Z/g
s/3/2Z/g
s/2/1Z/g
s/1/Z/g
s/0//g
:t
s/Z</<ZZZZZZZZZZ/g
tt
s/<//g
s/$/:/
:l
s/x/xxx/g
s/:/:x:/g
tb
:b
s/^Z//
tl
s/:x/X/g
s/^/:/
:m
s/.*:([Xx]+)Xx*:$/&\1:/
tm
:n
s/([ :])[Xx](x*Xx*)/\1 \2/g
tn
s/:/\n/g
s/X/x/g

Выход:

$ echo 2 | sed -rf devils-staircase.sed

                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x

$ 
Цифровая травма
источник
7
Это действительно круто.
FUZxxl
8

Python 2, 81

def f(n,i=1,s=0):
 if i<2<<n:q=3**len(bin(i&-i))/27;f(n,i+1,s+q);print' '*s+'x'*q

Версия программы (88)

def f(n,s=0):
 if n:q=3**len(bin(n&-n))/27;f(n-1,s+q);print' '*s+'x'*q
f((2<<input())-1)

Число х в n1-й индексируемой строке равно 3 степени (индекс первого установленного бита n, начиная с lsb).

feersum
источник
8

Python 2, 74

def f(n,s=0):
 if~n:B=3**n;A=s+B-2**n;f(n-1,A+B);print' '*A+'x'*B;f(n-1,s)

Рекурсивный подход. Чертова лестница размером $ 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хранит смещение текущих частей, которые мы печатаем. Сначала мы возвращаемся к левой ветви с большим смещением, затем печатаем центральную линию, затем делаем правую ветвь с текущим смещением.

XNOR
источник
6

CJam, 36 35 33 байта

Вот еще один подход CJam (я не смотрел на код оптимизатора, поэтому не знаю, сильно ли он отличается):

L0sl~{{3*0s}%0s\+}*{1$,S*\+}%W%N*

Это использует 0для кривой. В качестве альтернативы (используя трюк с grc)

LLl~){3\#a1$++}/{1$,S*\'x*+}%W%N*

который использует x.

Проверьте это здесь.

объяснение

Основная идея состоит в том, чтобы сначала сформировать массив со строками, как

["0" "000" "0" "000000000" "0" "000" "0"]

А затем пройти через этот список, предварительно добавив нужное количество пробелов.

L0sl~{{3*0s}%0s\+}*{1$,S*\+}%W%N*
L                                 "Push an empty string for later.";
 0s                               "Push the array containing '0. This is the base case.";
   l~                             "Read and evaluate input.";
     {           }*               "Repeat the block that many times.";
      {    }%                     "Map this block onto the array.";
       3*                         "Triple the current string.";
         0s                       "Push a new zero string.";
             0s\+                 "Prepend another zero string.";
                   {       }%     "Map this block onto the result.";
                    1$            "Copy the last line.";
                      ,S*         "Get its length and make a string with that many spaces.";
                         \+       "Prepend the spaces to the current row.";
                             W%   "Reverse the rows.";
                               N* "Join them with newlines.";

Другая версия работает аналогично, но создает массив длин, например

[1 3 1 9 1 3 1]

И затем превращает это в строки xs в окончательной карте.

Мартин Эндер
источник
6

Дьялог АПЛ, 34 персонажа

Используя подход grc. Рисует лестницу с (домино) символами и принимает ввод от стандартного ввода. Это решение предполагает ⎕IO←0.

' ⌹'[(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕]
  • Принять вход от стандартного ввода.
  • ⌽⍳1+⎕- последовательность чисел от нуля до (например 3 2 1 0)
  • 3*⌽⍳1+⎕- три в силу этого (например 27 9 3 1)
  • (⊢,,)/3*⌽⍳1+⎕- предыдущий результат свернут справа от молчаливой функции, ⊢,,которая равна dfn, дающему {⍵,⍺,⍵}длину шага лестницы дьявола согласно подходу grc.
  • {⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕ длины шагов преобразуются в шаги.
  • (∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕что само классифицирован, как в моем решении J . Обратите внимание, что результат уже переворачивается правильно.
  • ' ⌹'[(∪∘.=⊖){⍵/⍳≢⍵}⊃(⊢,,)/3*⌽⍳1+⎕] цифры заменены пробелами и домино.
FUZxxl
источник
4

Руби, 99

Другой ответ на мой другой, вдохновленный ответом FUZxxl

FUZxxl отмечает, что числа х соответствуют числу факторов 2 индекса. например, для n = 2 мы имеем следующую факторизацию:

1 =1
2 =1 * 2
3 =3
4 =1 * 2 * 2
5 =5
6 =3 * 2
7 =7

Я использую более простой способ извлечения этих степеней 2: i=m&-mчто дает последовательность 1 2 1 4 1 2 1и т. Д. Это работает следующим образом:

m-1то же самое, что и mв его старших значащих битах, но младший бит 1 становится нулем, а все нули справа становятся единицами.

Чтобы иметь возможность И это с оригиналом, мы должны перевернуть биты. Есть разные способы сделать это. Один из способов - вычесть это из -1.

Тогда общая формула m& (-1 -(m-1)) упрощаетm&(-m)

Пример:

          100   01100100
100-1=     99   01100011
-1-99=   -100   10011100
100&-100=   4   00000100

Вот код: новые строки подсчитываются, отступы не нужны и поэтому не учитываются, как мой другой ответ. Это немного длиннее, чем мой другой ответ из-за неуклюжего преобразования из базы 2: 1 2 1 4 1 2 1 etcв базу 3: 1 3 1 9 1 3 1 etc(есть ли способ избежать этого Math::?)

def s(n)
  a=[]
  t=0
  1.upto(2*2**n-1){|m|i=3**Math::log(m&-m,2)
    a.unshift" "*t+"x"*i 
    t+=i}
  puts a
end
Уровень реки St
источник
3

Рубин, 140 99

Мой второй в истории код на Ruby и мое первое нетривиальное использование языка. Предложения приветствуются. Число байтов исключает начальные пробелы для отступов, но включает в себя новые строки (кажется, что большинство новых строк не могут быть удалены, если они не заменены хотя бы пробелом).

Ввод осуществляется путем вызова функции. Выходные данные - это массив строк, которые ruby ​​удобно выводит в стандартный вывод как разделенный новой строкой список с одним puts.

Алгоритм просто new iteration= previous iteration+ extra row of n**3 x's+ previous iteration. Однако есть много изрядное количество кода просто получить начальные пробелы в выходном справа.

def s(n)
  a=["x"]
  1.upto(n){|m|t=" "*a[0].length
    a=a.map{|i|t+" "*3**m+i}+[t+"x"*3**m]+a}
  puts a
end

Редактировать: Руби, 97

При этом используется аналогичный, но другой подход к построению числовой таблицы из всех чисел х, требуемых в массиве, aкак описано выше, но затем к созданию таблицы строк. Таблица строк строится в массиве в обратном направлении, cиспользуя довольно странный unshiftметод для добавления к существующему массиву.

В настоящее время этот подход выглядит лучше - но только на 2 байта :-)

def s(n)
  a=c=[]
  (n+1).times{|m|a=a+[3**m]+a}
  t=0
  a.each{|i|c.unshift" "*t+"x"*i
    t+=i}
  puts c
end
Уровень реки St
источник
1
Вы можете заменить for m in(0..n-1)do ... endна n.times{|m|...}.
Омар
@ Омар Спасибо, завтра попробую. Вы не поверите, сколько усилий потребовалось, чтобы запустить его из-за постоянных синтаксических ошибок. Я не знал, как получить доступ к переменной итерации, n.timesи я наверняка запомню это. Это endтоже исключает ! Однако в этом случае мне было интересно, если for m in (1..n)может быть лучше, чтобы избежать (m+1). Есть ли более короткий способ написать это?
Уровень Река St
1
forдлинный, главным образом потому, что вы вынуждены использовать end(вы можете заменить на doновую строку или на ;). Для 1..nвас можно использовать 1.upto(n){|m|...}. Мне нравится внешний вид, (1..n).each{|i|...}но он немного длиннее, чем при использовании upto. И обратите внимание, что итерация по вызову eachили uptoне просто короче, но и более идиоматичный Ruby.
Омар
@ Спасибо еще раз, 1.upto(n)это так! С этим и несколькими ненужными скобками у меня уже 120. Я думаю, что ниже 100 возможно, я опубликую пересмотренный код позже.
Уровень Река St
3

Haskell, 99 символов

d=q.((iterate((1:).(>>=(:[1]).(*3)))[1])!!)
q[]=[];q(a:r)=sum r&' '++a&'x'++'\n':q r
(&)=replicate

Функция d:

λ: putStr $ d 3
                                                                x
                                                             xxx
                                                            x
                                                   xxxxxxxxx
                                                  x
                                               xxx
                                              x
                   xxxxxxxxxxxxxxxxxxxxxxxxxxx
                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x
MtnViewMark
источник
Все эти скобки! Неужели нет способа обойтись с меньшими затратами?
FUZxxl
Вы можете потерять байт, поменяв местами уравнения qи выполнив их q x=xв пустом списке. Кроме того, кажется, что круглые скобки iterate...[1]не нужны.
Згарб
3

PHP - 137 байт

function f($n){for($a=[];$i<=$n;array_push($a,3**$i++,...$a))$r=str_repeat;foreach($a as$v){$o=$r(' ',$s).$r(x,$v)."
$o";$s+=$v;}echo$o;}

Я использую здесь тот же трюк, что и GRC . Вот негольфированная версия:

function staircase($n)
{
    $lengthsList = [];
    for ($i = 0; $i <= $n; ++$i) {
        array_push($lengthsList, 3 ** $i, ...$lengthsList);
    }

    $output = '';
    $cumulatedLength = 0;
    foreach ($lengthsList as $length)
    {
        $output = str_repeat(' ', $cumulatedLength) . str_repeat('x', $length) . "\n" . $output;
        $cumulatedLength += $length;
    }

    echo $output;
}
Черная дыра
источник
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++для того, чтобы это сокращение работало должным образом.
Исмаэль Мигель
@IsmaelMiguel PHP 5.6 - последняя версия PHP, мне не нужно больше ничего говорить. Я не виноват, что почти все используют старую версию, а большинство использует устаревшую. Спасибо за $r=str_repeatтрюк. Я думал только о том $r='str_repeat';, что не было сохранения ни одного байта. Неопределенная константа - тоже хороший трюк, молодец;). Новая строка на один байт меньше записи \n, поэтому я сохранил ее, но я использовал двойные кавычки, чтобы избежать конкатенации с $0. Еще раз спасибо !
Blackhole
Это будет хорошо смотреться только на вас. Если бы я не знал об этом, 3 ** $iя бы сказал, что у вас ужасный синтаксис. Вы можете обратиться к этому исправлению. Я говорю только об этом, а не о том, [1]что оно пришло из PHP5.4, который довольно «старый». 1 год назад я бы попросил вас уточнить это. Сегодня я прошу вас просто указать (в очень короткой строке), что определяет это. Говоря о коде, у вас все еще есть тот, ++$i<=$nкоторый можно заменить на $n>$i++. Мне пришлось преобразовать весь ваш код в PHP5.3, чтобы проверить его. Что было больно. Но я вижу, что вы съели 7 байт до сих пор.
Исмаэль Мигель
3

С 165

#define W while
f(n){int i=n+1,j=1<<i,k=1,l,r,s,t;W(i--)k*=3;l=k-j;W(--j){r=j,s=1;W(!(r%2))r/=2,s*=3;l-=s;t=l;W(t--)putchar(32);W(++t<s)putchar(88);putchar('\n');}}

Вот тот же код, распакованный и слегка очищенный:

int f(int n) {
    int i=n+1, j=1<<i, k=1;
    while (i--) k*=3;
    int l=k-j;
    while (--j) {
        int r=j,s=1;
        while (!(r%2))
            r/=2, s*=3;
        l-=s;
        int t=l;
        while (t--) putchar(' ');
        while (++t<s) putchar('X');
        putchar('\n');
    }
}

Это основано на той же идее, что и решение проблемы 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, а затем перевод строки.

Стивен Стадницки
источник
определить W для; while и опустить int для сохранения некоторых символов.
FUZxxl
также t = l- = s для некоторой экономии.
FUZxxl
@FUZxxl Я попробовал оба из них, но хотя C по-прежнему допускает неявные типы для функций, он не разрешает их при объявлении переменных даже с «классическими» флагами (по крайней мере, в GCC). И я попробовал #define W, хотя и, похоже, это не заботилось об этом, хотя, возможно, я ошибся в определении.
Стивен Стадницки
хм ... я думаю, вы можете опустить тип только в глобальной переменной. Это не приносит вам много. Вы можете попытаться добавить (*p)()=putchar;в начале, чтобы позвонить putcharкак p. Я думаю, что это должно работать.
FUZxxl
2

CJam, 46 43 41 39 36 35 байт

L0ri),(a*+_W%(;+{3\#'x*+_,S*}%$1>N*

ОБНОВЛЕНИЕ с использованием другого подхода сейчас.


Старый подход:

]ri){3f*_,)"x"a*\]z:+}*_s,f{1$,U+:U-S*\N}

Довольно наивно и долго, но с чего-то начать.

Я добавлю объяснение, как только я играю в гольф.

Попробуйте онлайн здесь

оптимизатор
источник
Кажется, нужно немного поработать. Не работает должным образом для n = 4, 5, 17. Отображены строки в левом формате риффлов х в верхней части. При n = 17 он выводил код на экран и заполнял дно буквами x.
DavidC
1
@DavidCarraher Для 4, 5 я думаю, что это просто перенос строки. Если вы скопируете вывод в текстовый редактор без переноса строк, это будет хорошо для меня.
Sp3000
Хорошо. Я знаю, видите.
DavidC
2

Ява, 271 269 ​​байт

Использует метод grc.

import java.util.*;String a(int a){List<Integer>b=new ArrayList<>();int c=-1,d=1;for(;c++<a;b.add(d),b.addAll(b),b.remove(b.size()-1),d*=3);String f="";for(;b.size()>0;f+="\n"){d=b.remove(b.size()-1);for(int g:b)for(c=0;c<g;c++)f+=' ';for(c=0;c<d;c++)f+='x';}return f;}

Отступ:

import java.util.*;
String a(int a){
    List<Integer>b=new ArrayList<>();
    int c=-1,d=1;
    for(;c++<a;b.add(d),b.addAll(b),b.remove(b.size()-1),d*=3);
    String f="";
    for(;b.size()>0;f+="\n"){
        d=b.remove(b.size()-1);
        for(int g:b)
            for(c=0;c<g;c++)
                f+=' ';
        for(c=0;c<d;c++)
            f+='x';
    }
    return f;
}

Любые предложения приветствуются.

2 байта благодаря mbomb007

Номер один
источник
Вы можете использовать b.size()>0вместо !b.isEmpty(), сохраняя 2 байта.
mbomb007
1

Perl, 62

#!perl -p
eval's/x+/$&$&$&
x/g,s/\d*/x
/;'x++$_;s/x+/$"x$'=~y!x!!.$&/ge

Сначала вычисляется результат итеративно без начальных пробелов. Затем добавляет их перед каждой строкой в ​​соответствии с количеством xсимволов в оставшейся части строки.

nutki
источник
1

JavaScript (ES6) 104 106 118

Редактировать Удалена рекурсивная функция, список '*' для каждой строки получается итеративно, с битами и степенями 3 (как во многих других ответах)
Внутри цикла многострочная строка строится снизу вверх, сохраняя счет ведущих пробелов для добавления в каждой строке

F=n=>{
  for(i=a=s='';++i<2<<n;a=s+'*'.repeat(t)+'\n'+a,s+=' '.repeat(t))
    for(t=u=1;~i&u;u*=2)t*=3;
  return a
}

Первая попытка удалена

Рекурсивная функция R создает массив с номером '*' для каждой строки. Например, R (2): [1, 3, 1, 9, 1, 3, 1]
этот массив сканируется для построения многострочной строки снизу вверх, сохраняя текущий счет начальных пробелов для добавления в каждой строке

F=n=>
(R=n=>[1].concat(...n?R(n-1).map(n=>[n*3,1]):[]))(n)
.map(n=>a=' '.repeat(s,s-=-n)+'*'.repeat(n)+'\n'+a,a=s='')
&&a 

Тест в консоли Firefox / FireBug

F(3)

Выход

                                                                *
                                                             ***
                                                            *
                                                   *********
                                                  *
                                               ***
                                              *
                   ***************************
                  *
               ***
              *
     *********
    *
 ***
*
edc65
источник
1

R - 111 символов

Простая реализация, итеративное построение массива и его медленное уничтожение.

n=scan()
a=1
if(n)for(x in 1:n)a=c(a,3^x,a)
for(A in a){cat(rep(' ',sum(a)-A),rep('x',A),'\n',sep='');a=a[-1]}

Использование:

> source('devil.r')
1: 2
2: 
Read 1 item
                  x
               xxx
              x
     xxxxxxxxx
    x
 xxx
x
koekenbakker
источник
Хороший вопрос, изменил мой код так, чтобы он n
принимал
1
Вы экономите 8 байтов, читая из STDIN. n=scan(),
Алекс А.
Вам не нужно объявлять, xчтобы использовать его в качестве курсора, и при этом вам не нужно if(n). Кроме того, разрывы строк считаются символом, я думаю.
freekvd
Спасибо, ты прав x. Не уверен насчет того, if(n)однако. Я добавил эту часть, чтобы разобраться с делом n=0. if(n)Затем возвращается Fи , следовательно , возвращает один x. Если я удаляю его, n=0дает нежелательные результаты. Новое здесь, поэтому не знал о переносах строк. Включено сейчас!
koekenbakker
Если вы установите a=0и запустите цикл, x in 0:nон также работает для n = 0. Тогда вы можете опустить if(n).
freekvd