Намалюйте сходи диявола


46

У Чортові сходи являє собою фрактал як функції , пов'язані з безліччю Кантора.

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

Ваше завдання - повторити цю функціональну функцію - в мистецтві ASCII!

Вхідні дані

Єдине ціле число n >= 0, що вказує на розмір виводу. Введення може бути надано через STDIN, аргумент функції або аргумент командного рядка.

Вихід

ASCII-мистецтво відтворення сходів Чорта за розміром n, або повернене у вигляді рядка, або надруковане на STDOUT. Пробіли в кінці кожного ряду добре, але провідні пробіли - ні. Ви необов'язково можете надрукувати один зворотний рядок.

Що стосується розміру 0, то вихід:

x

(За бажанням, ви можете використовувати замість пробілу будь-який інший символ ASCII для друку, крім пробілу x.)

Щодо розміру n > 0, ми:

  • Візьміть вихідний розмір n-1і розтягніть кожен ряд в три рази
  • Стрілка між рядами одинарних xs
  • Зсуньте рядки вправо, щоб 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.

Оцінка балів

Це код-гольф, тому рішення в найменших байтах виграє.

Відповіді:


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 = '"' за замовчуванням.


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- рейвел (тобто аргумент з його структурою згорнувся у вектор) попереднього результату. Це потрібно, тому що 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замінюються на #, тобто

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

    результат, який ми хочемо.


Всередині циклу живлення (,],~3^#@~.)@]замість цього (1,[:,1,"0~3*]) зберігається 1 байт. І якщо ви все в порядку з !як вихідний графік, u:32+а не ' #'{~зберігаєте ще один.
randomra

#\ замість, i.@#і ви наздоганяєте APL! :)
randomra

Ваше друге рішення не працює, тому що знадобиться обмеження, але я знайшов інший спосіб перемогти APL.
FUZxxl

Новий вихід - сходи для n-1не для n.
randomra

@ випадкова Ага ... це гавно. Дозвольте мені побачити, чи можна це виправити.
FUZxxl

26

Шестикутник , 217 байт

Це було надзвичайно весело. Дякуємо, що опублікували цей виклик.

Повне розкриття: мови (Гексагонія) не існувало під час опублікування цього виклику. Однак я цього не вигадав, і мова не була розроблена для цього виклику (або будь-якого іншого конкретного виклику).

){_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, починаючи в нижньому лівому кутку , протікає швидко , щоб декремент лінію , встановлену ч до 32(символу пробілу) і SEG до (новому значенням) лінії . Через раннє зменшення ми фактично починаємо з 2ⁿ⁺¹ − 1 і врешті-решт відчуваємо останню ітерацію зі значенням 0. Потім вводимо перший вкладений цикл.

Звернемо свою увагу на розгалужене індиго, де після короткого декрету о SEG , ми бачимо , ч оновлена xтільки якщо сегментний тепер дорівнює нулю. Після цього n встановлюється рядок - seg, щоб визначити фактичну кількість сегмента, в якому ми знаходимося. Одразу вводимо ще одну петлю, цього разу в яскравому кольорі помідора.

Тут ми з'ясуємо, скільки разів n (поточний номер сегмента) можна розділити на 2. Поки модуль дає нам нуль, ми збільшуємо i і ділимо n на 2. Коли ми задоволені, n більше не є таким чином дільним ми розширитися в сірий шифер, який містить дві петлі: спочатку вона піднімає 3 до сили I ми вирахували, а потім виводить сп , що у багато разів. Зауважте, що перша з цих циклів містить a[інструкція, яка перемикає контроль на IP №3 - та, яка раніше робила лише кроки дитини по нижньому краю. Тіло петлі (множення на 3 і декрементація) виконується самотнім IP №3, ув'язненим у нескінченний темно-оливковий зелений цикл уздовж нижнього краю коду. Аналогічно, друга з цих шиферних сірих петель містить ]інструкцію, яка активує IP №5 для виведення ch і зменшення, показані тут темно-індійським червоним кольором. В обох випадках ці покажчики Інструкції, захоплені сервітутом, слухняно виконують по одній ітерації за один раз і повертають контроль до IP # 4, лише щоб запропонувати момент, коли їх послуга знову буде викликана. Тим часом сірий шифер знову приєднується до своїх братів Фуксія та Індіго.

Коли seg неминуче досягає нуля, петля індиго виходить на газонний зелений шлях, який просто виводить символ нового рядка і негайно зливається назад у фуксію, щоб продовжити цикл лінії . Поза остаточною ітерацією лінії контуру лежить короткий соболий Ebon шлях кінцевого завершення програми.


8
Тепер це просто очевидне старомодне божевілля.
FUZxxl

21

Пітон 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раз, щоб дати нам довжину рядків для сходів Диявола. Потім друкуємо кожен рядок, прокладений пробілами.


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

Не найкоротша відповідь, але її sed !:

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

Пітон 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)

Кількість x у n1-му індексованому ряду дорівнює 3 потужності (індекс першого встановленого біта в n, починаючи з lsb).


8

Пітон 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зберігає зміщення поточних деталей, які ми друкуємо. Спочатку повторюємо вниз до лівої гілки з більшим зміщенням, потім друкуємо центральну лінію, а потім робимо праву гілку в поточному зміщенні.


6

CJam, 36 35 33 байт

Ось ще один підхід CJam (я не переглянув код Optimizer, тому не знаю, чи він насправді сильно відрізняється):

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

Діалог APL, 34 символи

Використовуючи підхід grc. Намалює сходи з (доміно) символами та приймає дані від stdin. Це рішення передбачає ⎕IO←0.

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

4

Рубі, 99

Інша відповідь на іншу мою, натхненну відповіддю FUZxxl

FUZxxl зазначає, що числа x відповідають кількості факторів 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.

Щоб мати можливість І це з оригіналом, нам потрібно перевернути біти. Існують різні способи зробити це. Один із способів - це відняти його -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

3

Рубі, 140 99

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

Введення здійснюється за допомогою виклику функції. Вихід - це масив рядків, який рубін зручно скидає на stdout у вигляді списку, розділеного новим рядком, з єдиним 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

При цьому використовується аналогічний, але різний підхід побудови числової таблиці всіх чисел x, необхідних для масиву 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

1
Ви можете замінити for m in(0..n-1)do ... endна n.times{|m|...}.
Омар

@Omar Спасибі, я спробую це завтра. Ви б не повірили, скільки зусиль потрібно, щоб це запустити через постійні синтаксичні помилки. Я не знав, як отримати доступ до змінної ітерації, n.timesі я точно пам’ятаю це. Це також усуває end! Однак з цього приводу мені було цікаво, чи for m in (1..n)може бути краще, щоб уникнути цього (m+1). Чи є коротший спосіб написання цього?
Рівень р. Св.

1
forдовгий, головним чином, тому що ви змушені використовувати end(ви можете замінити doнову лінію або на ;). Для 1..nможна використовувати 1.upto(n){|m|...}. Мені подобається зовнішній вигляд, (1..n).each{|i|...}але він трохи довший, ніж використання upto. І зауважте, що повторення за допомогою дзвінка eachабо uptoне просто коротше, воно також вважає більш ідіоматичним Ruby.
Омар

@ Дякую ще раз 1.upto(n)! З цим і ще кількома непотрібними дужками я вже знижуюсь до 120. Я думаю, що нижче 100 можливе, переглянутий код опублікую пізніше.
Рівень річки Св.

3

Хаскелл, 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

Усі ці дужки! Чи справді немає способу обійтись з меншим?
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всередині дворядкового рядка зі змінною $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's. l налаштовано, щоб переконатися, що ми починаємо з правильного місця: пишемо l пробіли та s 'X, потім новий рядок.


визначте W to; в той час як і пропустіть 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. Відображаються ліворуч відформатовані рядки рушниць x у верхній частині. З n = 17 він скинув код на екран і заповнив дно x.
DavidC

1
@DavidCarraher Для 4, 5 я думаю, що це лише обгортання рядків. Якщо ви скопіюєте висновок у текстовий редактор без упаковки рядків, для мене це виглядає нормально.
Sp3000

Гаразд. Я знаю, бачу.
DavidC

2

Java, 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

Перл, 62

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

Спочатку обчислюють результат ітераційно без провідних пробілів. Потім додає їх перед кожним рядком відповідно до кількості xсимволів у решті рядка.


1

JavaScript (ES6) 104 106 118

Редагувати Вилучена рекурсивную функцію, список «*» для кожного рядка виходять итеративно, пораючись з битами і повноваженнями 3 (як і в багатьох інших відповідях)
Всередині циклу многострочного рядок buuilt від низу до верху, утримуючи поточний рахунок провідних пробілів, які потрібно додати в кожному рядку

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)

Вихід

                                                                *
                                                             ***
                                                            *
                                                   *********
                                                  *
                                               ***
                                              *
                   ***************************
                  *
               ***
              *
     *********
    *
 ***
*

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

Добрий момент, змінив мій код, щоб він взяв nаргумент з командного рядка
koekenbakker

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

0

Рубі, 93

f=->n{s,p,k=[1],1;n.times{s=s+[p=p*3]+s};k=s.dup;k.each{m=s.pop;puts' '*s.reduce(0,:+)+?x*m}}

При цьому використовується той же підхід, що і grc.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.