Фрактал двійкового дерева


25

Сьогоднішня задача - намалювати бінарне дерево настільки прекрасного як цей приклад:

                               /\
                              /  \
                             /    \
                            /      \
                           /        \
                          /          \
                         /            \
                        /              \
                       /                \
                      /                  \
                     /                    \
                    /                      \
                   /                        \
                  /                          \
                 /                            \
                /                              \
               /\                              /\
              /  \                            /  \
             /    \                          /    \
            /      \                        /      \
           /        \                      /        \
          /          \                    /          \
         /            \                  /            \
        /              \                /              \
       /\              /\              /\              /\
      /  \            /  \            /  \            /  \
     /    \          /    \          /    \          /    \
    /      \        /      \        /      \        /      \
   /\      /\      /\      /\      /\      /\      /\      /\
  /  \    /  \    /  \    /  \    /  \    /  \    /  \    /  \
 /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\  /\
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

Вам буде введено додатне ціле число як вхідне. Цей вхід - висота дерева . Наведений вище приклад має висоту шість.

Ви можете надіслати або повну програму, або функцію, і ви можете використовувати будь-який із наших методів вводу-виводу за замовчуванням . Наприклад, друк дерева, повернення рядка з новими рядками, повернення масиву 2d char, збереження дерева у файл тощо.

Додаткові пробіли в кожному рядку дозволені.

Ось кілька прикладів входів та відповідних результатів:

1:
/\

2:
 /\
/\/\

3:
   /\
  /  \
 /\  /\
/\/\/\/\

4:
       /\
      /  \
     /    \
    /      \
   /\      /\
  /  \    /  \
 /\  /\  /\  /\
/\/\/\/\/\/\/\/\

5:
               /\
              /  \
             /    \
            /      \
           /        \
          /          \
         /            \
        /              \
       /\              /\
      /  \            /  \
     /    \          /    \
    /      \        /      \
   /\      /\      /\      /\
  /  \    /  \    /  \    /  \
 /\  /\  /\  /\  /\  /\  /\  /\
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

На жаль, вихід зростає експоненціально, тому важко показати більші приклади. Ось посилання на вихід для 8.

Як завжди, це проблема з , тому застосовуються стандартні лазівки і намагайтеся написати найкоротшу програму якою б мовою ви не обрали.

Щасливого гольфу!


Чи можуть бути пробіли, щоб зробити всі лінії однакової довжини?
xnor

@xnor Так, це добре.
DJMcMayhem

Відповіді:


5

Python 2, 77 байт

S=s=i=2**input()
while s:print S/s*('/'+' '*(s-i)+'\\').center(s);i-=2;s/=s/i

Друкується з пробілами, які закінчуються помилкою.

Я взяв цей код з мого подання на виклик, який я поставив на Anarchy Golf , плюс однобайтне покращення, знайдене xsot. Значення із твердим кодом було змінено на 2**input().

Ідея полягає в тому, що кожен рядок виводу є сегментом, скопійованим один або кілька разів. Половина після вхідного розбиття має одну копію кожного сегмента, чверть після наступного розбиття - дві копії тощо, до останнього рядка з багатьма сегментами /\.

Кожен сегмент мав /і \з пробілами між ними, а також на зовнішній стороні від майданчика до потрібної довжини. Зовнішня прокладка робиться за допомогою center.

Змінна sвідслідковує потоки з кожного сегмента, а кількість сегментів становить S/sтак, що загальна ширина - це ширина дерева S. Номер рядка iвідлічується на 2, і кожного разу, коли значення sйого наполовину, відбувається розщеплення, а ширина сегмента наполовину. Це робиться через вираз s/=s/i. Коли iдосягається 0, це дає помилку, яка припиняє програму.

Оскільки anagolf дозволяє лише подати програми, я не досліджував можливості рекурсивної функції, яка, на мою думку, є коротшою.



4

Полотно , 11 байт

/║╶╷[l\;∔↔║

Спробуйте тут!

Пояснення:

/║          push `/\` ("/" palindromized so this is a Canvas object)
  ╶╷[       repeat input-1 times
     l        get the width of the ToS
      \       create a diagonal that long
       ;∔     prepend that to the item below
         ↔    reverse the thing horizontally
          ║   and palindromize it horizontally

3

Haskell , 140 138 135 байт

e n=[1..n]>>" "
n!f=(e n++).(++e n)<$>f
f 0=[]
f n=1!f(n-1)++['/':e(2*n-2)++"\\"]
b n|n<2=f 1|t<-b$n-1,m<-2^(n-2)=m!f m++zipWith(++)t t

Спробуйте в Інтернеті! Дзвінок за допомогою b 5, повертає список рядків.

Досить використання друку:

*Main> putStr . unlines $ b 5
               /\
              /  \
             /    \
            /      \
           /        \
          /          \
         /            \
        /              \
       /\              /\
      /  \            /  \
     /    \          /    \
    /      \        /      \
   /\      /\      /\      /\
  /  \    /  \    /  \    /  \
 /\  /\  /\  /\  /\  /\  /\  /\
/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\

(деякі) Пояснення:

  • e nстворює рядок nпробілів
  • n!fпрокладає кожен рядок у списку рядків fз nпробілами зліва та справа
  • f nмалює «пік» в nпо 2nпрямокутнику
  • b n малює двійкове дерево, об'єднуючи два менших дерева і центрирує над ними новий пік

Редагувати: -3 байти завдяки Zgarb!


Думаю, 1!f(n-1)і m!f mслід зберегти пару байтів.
Згарб

@Zgarb Дякую за те, що вказали, що правила пріоритету іноді стають заплутаними.
Лайконі

2

J , 49 43 42 байт

' /\'{~(|.,-)"1@(=@i.@#,-)^:(<:`(,:@,&*-))

Це визначає дієслово, яке приймає число і повертає двовимірний масив символів. Спробуйте в Інтернеті!

Пояснення

Спочатку будую матрицю значень -1, 0 і 1, повторюючи допоміжне дієслово, а потім замінюю числа символами. Допоміжне дієслово будує праву половину наступної ітерації, потім відображає її горизонтально, щоб створити решту. У наступному поясненні ,з'єднують 2D масиви вертикально та 1D масиви по горизонталі.

' /\'{~(|.,-)"1@(=@i.@#,-)^:(<:`(,:@,&*-))  Input is n.
                          ^:(            )  Iterate this verb
                             <:             n-1 times
                               `(       )   starting from
                                    ,&*-    the array 1 -1 (actually sign(n), sign(-n))
                                 ,:@        shaped into a 1x2 matrix:
                                             Previous iteration is y.
                      #                      Take height of y,
                   i.@                       turn into range
                 =@                          and form array of self-equality.
                                             This results in the identity
                                             matrix with same height as y.
                       ,-                    Concatenate with -y, pad with 0s.
       (    )"1@(        )                   Then do to every row:
        |.,-                                 Concatenate reversal to negation.
' /\'{~                                     Finally index entry-wise into string.

1

JavaScript (ES6), 105 байт

f=n=>n<2?"/\\":" "+f(n-1).split`/`[0].replace(/|/g,"$`$'$'/$`$`\\$'$'$` \n")+f(n-1).replace(/.*/g,"$&$&")

Працює, будуючи результат рекурсивно з базового випадку /\. Нижня половина - це лише попередній випадок, у якому кожен рядок дублювався. Верхня половина була трохи хитрішою; це виглядає так, ніби ви хочете взяти попередній випадок і зберегти лише дві сторони, але вам також доведеться турбуватися про набивання струн, щоб подвоїти ширину, тому натомість я роблю кілька магій регулярного виразів. Беручи провідні пробіли з попереднього випадку і розділяючи їх у кожній точці, я можу розглянути пробіли до і після цієї точки. У кожному матчі пробіли перед збільшенням на 1 та пробіли після зменшення на 1; це можна використовувати для позиціонування /та\у правильних місцях. Тут також додаються нові рядки та накладки; це турбується про всі прокладки, за винятком пробілу на кожному рядку та провідного місця на першому рядку, який я повинен додати вручну. (Провідні пробіли в наступних рядках надходять із відповідного рядка).


1

Вугілля деревне , 12 байт

FN«→↗⌈X²⊖ι‖M

Спробуйте в Інтернеті! Посилання на багатослівну версію коду. Пояснення:

 N              Input as a number
F «             Loop over implicit range
   →            Move right (because mirroring moves the cursor)
         ι      Current index
        ⊖       Decremented
      X²        Power of 2
     ⌈          Ceiling
    ↗           Draw diagonal line
          ‖M    Mirror image

Довжини рядків дорівнюють 1, 1, 2, 4, 8 ... 2 ^ (N-2), тому незручний розрахунок.



0

Пакетна, 218 байт

@echo off
set/a"n=1<<%1"
set s=set t=
%s%/\
set l=for /l %%i in (2,1,%n%)do call
%l% %s% %%t%% 
%l%:l
:l
echo %t%
set/an-=1,m=n^&n-1
%s%%t: /=/ %
%s%%t:\ = \%
if %m% neq 0 exit/b
%s%%t:/ =/\%
%s%%t: \=/\%

Примітка: рядок 6 закінчується пробілом. Працює, щоразу переміщуючи гілки вліво і вправо, за винятком рядків, які знаходяться на відстані 2 n від кінця, і в цьому випадку гілки замість цього розщеплюються.


0

Хакс, 181 байт

function g(n):String return(n-=2)==-1?"/\\":[for(y in 0...1<<n)[for(x in 0...4<<n)x+y+1==2<<n?"/":x-y==2<<n?"\\":" "].join("")].concat([for(y in g(n+1).split("\n"))y+y]).join("\n");

Або з додатковим пробілом:

function g(n):String
  return
    (n -= 2) == -1
    ? "/\\"
    : [ for (y in 0...1 << n)
        [ for (x in 0...4 << n)
          x + y + 1 == 2 << n
          ? "/"
          : x - y == 2 << n
            ? "\\"
            : " "
        ].join("")
      ].concat([ for (y in g(n + 1).split("\n"))
        y + y
      ]).join("\n");

Я деякий час працював над рішенням, яке створило масив просторових символів потрібного розміру спочатку, потім ітеративно поставив роздвоєні контури все нижче і нижче (і більш щільно на кожній ітерації). Однак залишилось 230+ байтів. Підхід тут в значній мірі є підходом Хаскеля @ Лайконі. Я не міг відійти від того :String, що не маю , тому що Haxe недостатньо розумний, щоб визначити, що тип повернення завжди буде String.

Це лише функція, ось повна програма для її тестування:

class Main {
    public static function main(){
        function g(n):String return(n-=2)==-1?"/\\":[for(y in 0...1<<n)[for(x in 0...4<<n)x+y+1==2<<n?"/":x-y==2<<n?"\\":" "].join("")].concat([for(y in g(n+1).split("\n"))y+y]).join("\n");
        Sys.println(g(Std.parseInt(Sys.args()[0])));
    }
}

Покладіть вище Main.hx, компілюйте зhaxe -main Main.hx -neko frac.n та протестуйте neko frac.n 4(замініть 4на потрібний порядок).


0

PHP, 188 байт

Інтернет-версія

function f($l,$r=0,$m=1){global$a;for(;$i<$l;$i++)$i<$l/2?$a[$i+$r]=str_repeat(str_pad("/".str_pad("",2*$i)."\\",2*$l," ",2),$m):f($l/2^0,$r+$l/2,2*$m);}f(2**$argv[1]/2);echo join("\n",$a);

Розширено

function f($l,$r=0,$m=1){
global$a;    
for(;$i<$l;$i++)    
$i<$l/2
    ?$a[$i+$r]=str_repeat(str_pad("/".str_pad("",2*$i)."\\",2*$l," ",2),$m)
    :f($l/2^0,$r+$l/2,2*$m);
}
f(2**$argv[1]/2);
echo join("\n",$a);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.