Не могу увидеть лес за ключами

16

Напишите программу или функцию, которая принимает непустой список целых чисел в любом удобном формате, например, 4, 0, -1, -6, 2или [4 0 -1 -6 2].

Распечатайте или верните строку, которая отображает список в виде художественного леса ASCII, где каждое число становится деревом пропорциональной высоты. Каждое дерево занимает четыре столбца текста в выводе следующим образом:

  • Целое положительное число N становится деревом, основание которого __|_и вершина ^ с N слоями / \между ними.

    Например, когда N = 1, дерево

      ^
     / \
    __|_
    

    когда N = 2 дерево

      ^
     / \
     / \
    __|_
    

    когда N = 3 дерево

      ^
     / \
     / \
     / \
    __|_
    

    и так далее.

  • Отрицательное целое число N становится таким же, как соответствующее положительное дерево, за исключением того, что вертикальная черта находится между косыми чертами вместо пробела.

    Например, когда N = -1, дерево

      ^
     /|\
    __|_
    

    когда N = -2 дерево

      ^
     /|\
     /|\
    __|_
    

    когда N = -3 дерево

      ^
     /|\
     /|\
     /|\
    __|_
    

    и так далее.

  • Когда целое число равно 0, технически нет дерева, просто пустое пространство из четырех подчеркиваний:

    ____
    

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

Например, вывод для 4 0 -1 -6 2будет

              ^
             /|\
  ^          /|\
 / \         /|\
 / \         /|\  ^
 / \      ^  /|\ / \
 / \     /|\ /|\ / \
__|_______|___|___|__

Обратите внимание, что у шаблонов дерева всегда есть начальный столбец пустого пространства, но необходимо добавить подчеркивание, чтобы дополнить правую часть последнего дерева.

Также:

  • Конечные пробелы на любых строках хороши, но не должно быть лишних начальных пробелов.
  • Начальные символы новой строки не допускаются (самое высокое дерево должно касаться вершины сетки выходного текста), и допускается только до одного завершающего символа новой строки.
  • Список может содержать любые целые числа от -250 до 250 включительно. Обработка более высоких деревьев не требуется.

Самый короткий код в байтах побеждает.

Больше примеров

3:

  ^
 / \
 / \
 / \
__|__

-2:

  ^
 /|\
 /|\
__|__

0:

_____

0, 0:

_________

0, 1, 0:

      ^
     / \
______|______

0, -1, 2, -3, 4:

                  ^
              ^  / \
          ^  /|\ / \
      ^  / \ /|\ / \
     /|\ / \ /|\ / \
______|___|___|___|__
Кальвин Хобби
источник

Ответы:

6

Pyth, 48 байтов

j_.t+sm.i,J\_?d++\|sm?>d0\ \|d\^Jms+Jmkd"/\\"QJd

Попробуйте онлайн: демонстрация или тестовый набор

Слишком ленив для полного объяснения. Вот только краткий обзор:

Сначала я генерирую столбцы. Итак, изображение:

      ^ 
  ^  /|\
 / \ /|\
__|___|__

генерируется как:

["_", "_/", "| ^", "_\", "_", "_//", "|||^", "_\\", "_"]

Обратите внимание, что я генерирую только нижнюю часть (все без пробелов). И я также генерирую их снизу вверх. Это сделано довольно просто.

Затем я могу использовать .tметод для добавления пробелов к строкам, чтобы каждая строка имела одинаковую длину. А потом я меняю порядок и печатаю.

Jakube
источник
Как примечание: если это фактический результат, вы, возможно, забыли добавить конечный _(подчеркивание) после последнего дерева.
insertusername здесь
1
@insertusernamehere Спасибо, полностью пропустил трейлинг _ .
Jakube
7

Python 2, 165 байт

a=input()
l=max(map(abs,a))
while l+2:s=' _'[l<0];print(s+s.join((([' ^ ','//| \\\\'[x>0::2],'   '][cmp(abs(x),l)],'_|_')[l<0],s*3)[x==0]for x in a)+s).rstrip();l-=1

Это полная программа, которая принимает список в качестве входных данных. Я все еще играю в гольф в этом ужасном беспорядке.

xsot
источник
4

PHP, 231 277 байт

Эта задача имеет прекрасный результат.

$x=fgetcsv(STDIN);for(;$i<2+max(array_map(abs,$x));$i++)for($j=0;$j<count($x);){$_=$x[$j++];$o[$i].=!$i?$_?'__|_':____:(abs($_)>=$i?0>$_?' /|\\':' / \\':($i-1&&abs($_)==$i-1?'  ^ ':'    '));}echo implode("
",array_reverse($o))."_";

Читает список через запятую (пробелы не обязательны) из STDIN:

$ php trees.php
> 1, 2, 0, -4, 6

Ungolfed

$x=fgetcsv(STDIN);
for(;$i<2+max(array_map(abs,$x));$i++)
    for($j=0;$j<count($x);){
        $_=$x[$j++];
        $o[$i] .= !$i ? $_?'__|_':____
                      : (abs($_)>=$i ? 0>$_?' /|\\':' / \\'
                                     : ($i-1&&abs($_)==$i-1 ? '  ^ ' : '    '));
    }
echo implode("\n",array_reverse($o))."_";

Правки

  • Сохранено 46 байт . Отброшена инициализация массива, заменены if/elseтернарные операторы и перемещены некоторые переменные, чтобы сохранить несколько байтов.
insertusernamehere
источник
2

Рубин, 157 156 153 символов

->h{r=[]
h.map{|i|j=i.abs
r+=[s=?_,?/*j+s,i==0?s:?^+(i>0?' ':?|)*j+?|,?\\*j+s].map{|l|l.rjust(h.map(&:abs).max+2).chars}}
r.transpose.map{|l|l*''}*$/+?_}

Написано только потому, что изначально Array.transposeвыглядело как хорошая идея. Уже нет.

Образец прогона:

2.1.5 :001 > puts ->h{r=[];h.map{|i|j=i.abs;r+=[s=?_,?/*j+s,i==0?s:?^+(i>0?' ':?|)*j+?|,?\\*j+s].map{|l|l.rjust(h.map(&:abs).max+2).chars}};r.transpose.map{|l|l*''}*$/+?_}[[4, 0, -1, -6, 2]]
              ^     
             /|\    
  ^          /|\    
 / \         /|\    
 / \         /|\  ^ 
 / \      ^  /|\ / \
 / \     /|\ /|\ / \
__|_______|___|___|__
manatwork
источник
Сбор кусков в отдельный массив вместо возврата их из первой карты должен позволить избежать использования Reduce.
manatwork
0

C #, 318 байт

Я попытался транспонировать массив. Я не уверен, что это было лучшее решение.

string F(int[]a){int i=a.Length,j,w=i*4+1,h=0;string f="",o=f;for(;i-->0;){j=a[i];f+=","+" _,".PadLeft(j=j>0?j+3:-j+3,'\\')+(j>3?"^"+"|_,".PadLeft(j,a[i]<0?'|':' '):"_,")+" _,_".PadLeft(j+1,'/');h=h<j?j:h;}f="_".PadLeft(h=h>3?h:2,'\n')+f;for(i+=h<3?1:0;++i<h;)for(j=w;j-->0;)o+=f.Split(',')[j].PadLeft(h)[i];return o;}

Отступы и новые строки для ясности:

string F(int[]a)
{
    int i=a.Length,
        j,
        w=i*4+1,
        h=0;
    string f="",o=f;
    for(;i-->0;){
        j=a[i];
        f+=","+" _,".PadLeft(j=j>0?j+3:-j+3,'\\')+(j>3?"^"+"|_,".PadLeft(j,a[i]<0?'|':' '):"_,")+" _,_".PadLeft(j+1,'/');
        h=h<j?j:h;
    }
    f="_".PadLeft(h=h>3?h:2,'\n')+f;
    for(i+=h<3?1:0;++i<h;)
        for(j=w;j-->0;)
            o+=f.Split(',')[j].PadLeft(h)[i];
    return o;
}
Hand-E-Food
источник