20
\$\begingroup\$

Write a program or function that takes in a nonempty list of integers in any reasonable convenient format such as 4, 0, -1, -6, 2 or [4 0 -1 -6 2].

Print or return a string that depicts the list as an ASCII art forest where each number becomes a tree of proportional height. Each tree takes up four columns of text in the output as follows:

  • A positive integer N becomes a tree whose base is __|_ and top is ^ , with N layers of / \ in between.

    For example, when N = 1 the tree is

      ^
     / \
    __|_
    

    when N = 2 the tree is

      ^
     / \
     / \
    __|_
    

    when N = 3 the tree is

      ^
     / \
     / \
     / \
    __|_
    

    and so on.

  • A negative integer N becomes just like the corresponding positive tree except a vertical bar is between the branch slashes instead of a space.

    For example, when N = -1 the tree is

      ^
     /|\
    __|_
    

    when N = -2 the tree is

      ^
     /|\
     /|\
    __|_
    

    when N = -3 the tree is

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

    and so on.

  • When the integer is 0 there is technically no tree, just an empty space of four underscores:

    ____
    

The underscores at the base of each tree must line up in the output, i.e. all the trees must have their bases at the same level. Also, a single underscore is added to the end of the line of underscores after the last tree. This makes it so every tree has an empty column of "air" on either side of it.

As an example, the output for 4 0 -1 -6 2 would be

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

Note how the tree patterns always have a leading column of empty space but an underscore had to be added to pad the right side of the last tree.

Also:

  • Trailing spaces on any lines are fine, but there should be no unnecessary leading spaces.
  • Leading newlines are not allowed (the tallest tree should touch the top of the output text grid) and only up to one trailing newline is allowed.
  • The list may contain any integers from -250 to 250 inclusive. Handling taller trees is not required.

The shortest code in bytes wins.

More Examples

3:

  ^
 / \
 / \
 / \
__|__

-2:

  ^
 /|\
 /|\
__|__

0:

_____

0, 0:

_________

0, 1, 0:

      ^
     / \
______|______

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

                  ^
              ^  / \
          ^  /|\ / \
      ^  / \ /|\ / \
     /|\ / \ /|\ / \
______|___|___|___|__
\$\endgroup\$
0

11 Answers 11

7
\$\begingroup\$

Python 2, 165 bytes

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

This is a full program that accepts a list as input. I'm still golfing this horrid mess.

\$\endgroup\$
6
\$\begingroup\$

Pyth, 48 bytes

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

Try it online: Demonstration or Test Suite

Too lazy for a full explanation. Here just short overview:

I generate the columns first. So the image:

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

gets generated as:

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

Notice, that I'm generating only the lower part (everything without the spaces). And I'm also generating them from bottom to top. This is done pretty straightforward.

Then I can use the .t method to append spaces to the strings, so that each string has an equal length. And afterwards I reverse the order and print.

\$\endgroup\$
2
  • \$\begingroup\$ As a note: If this is an actual output, you might have forgotten to add a trailing _ (underscore) after the last tree. \$\endgroup\$ Commented Dec 7, 2015 at 22:56
  • 1
    \$\begingroup\$ @insertusernamehere Thanks, completely overlooked the trailing _. \$\endgroup\$
    – Jakube
    Commented Dec 7, 2015 at 23:00
4
\$\begingroup\$

PHP, 231 277 bytes

This challenge has a beautiful output.

$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))."_";

Reads a comma separated list (whitespaces are optional) from 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))."_";

Edits

  • Saved 46 bytes. Discarded array initialization, replaced if/else with ternary operators and moved some of the variables around to save a few bytes.
\$\endgroup\$
2
\$\begingroup\$

Ruby, 157 156 153 characters

->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*''}*$/+?_}

Written just because initially Array.transpose looked like a good idea. Not anymore.

Sample run:

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]]
              ^     
             /|\    
  ^          /|\    
 / \         /|\    
 / \         /|\  ^ 
 / \      ^  /|\ / \
 / \     /|\ /|\ / \
__|_______|___|___|__
\$\endgroup\$
1
  • \$\begingroup\$ Collecting the pieces into a separate array instead of returning them from the first map should allow to avoid the use of reduce. \$\endgroup\$
    – manatwork
    Commented Dec 8, 2015 at 19:00
2
\$\begingroup\$

PowerShell, 167 bytes

$h=(($r=($args|%{$a,$x=$_,-$_-ge0
'_';'_'+'/'*$a;'|_'[!$_]+(' ','|')[$_-lt0]*$a+'^'*!!$_
'_'+'\'*$a})+'_')|% Le*|sort)[-1]
$z=$r|% *ht $h;--$h..0|%{-join($z|% Ch* $_)}

Try it online!

Explanation:

  1. Draw a rotated forest line by line

    Rotated forest

  2. Pad right and

  3. Rotate -90.

Unrolled:

# a rotated forest with underscore after the last tree
$rotatedForest=$args|%{
    $abs,$x=$_,-$_-ge0
    '_'
    '_'+'/'*$abs
    '|_'[!$_]+(' ','|')[$_-lt0]*$abs+'^'*!!$_
    '_'+'\'*$abs
}
$rotatedForest += '_'

# calc height
$height = ($rotatedForest|% Length|sort)[-1]

# PadRight all trees
$z = $rotatedForest|% PadRight $height

# Rotate -90
--$height..0|%{
    -join($z|% Chars $_)
}
\$\endgroup\$
2
\$\begingroup\$

JavaScript (V8), 157 156 bytes

f=(l,m=l.map(Math.abs),i=Math.max(...m))=>m.map((j,J)=>i<0?j?"__|_":"____":i<j?l[J]<0?" /|\\":" / \\":i==j&&j?"  ^ ":"    ").join``+(i<0?"_":`
`+f(l,m,i-1))

-1 byte thanks to emanresu A

Try it online!

Hello! First time posting here, I wanted to try to solve this problem as my first challenge, I saw that thejonymyster also answered it, but I was pretty happy with the answer I found, so I hope that I'm following the rules in this situation. Anyway, here's a prettier version of the code, mostly using a lot of ternaries and some recursion:

/* Line  1   ^   i: index of the line from the maximum absolute value to -1
   Line  0  / \  j: absolute value of each element
   Line -1  _|_  l[J]: non-absolute value (retrieved using the index) */

f=(l, m=l.map(Math.abs), i=Math.max(...m)) =>
    m.map((j, J) =>
        i<0
            ? j ? "__|_" : "____" :
        i<j
            ? l[J]<0 ? " /|\\" : " / \\" :
        i==j && j
            ? "  ^ " : "    "
    ).join`` + (i<0 ? "_" : `
` + f(l, m, i-1))
New contributor
WeirdGlyphs is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ Welcome to Code Golf, and nice first answer! You can save at least one byte with a literal newline `[newline]` instead of "\n". \$\endgroup\$
    – emanresu A
    Commented yesterday
  • \$\begingroup\$ @emanresuA Wow, nice trick! \$\endgroup\$ Commented yesterday
1
\$\begingroup\$

JavaScript (V8), 213 bytes

x=>{a=Math;b=a.abs;c=a.sign;e=x.map(b);d=a.max(...e)+1;f="";while(d--){e.map((g,h)=>f+=["    ",`  ${c(g)?"^":" "} `,` /${1+c(x[h])?" ":"|"}\\`][1+c(g-d)]);f+="\n"}return f+`_${x.map(i=>i?"_|_":"___").join("_")}_`}

Try it online!

Seems like the same as the other non-transposing answers, not all too many strategies to solve this. Transposing is probably shorter in js but I like this method better.

\$\endgroup\$
0
\$\begingroup\$

C#, 318 bytes

I tried transposing the array. I'm not sure if that was the best solution.

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;}

Indentation and newlines for clarity:

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;
}
\$\endgroup\$
0
\$\begingroup\$

Canvas, 41 bytes

H?¹⤢\ /*¹0<? /∙|/╋} v∔↕_|__¶∔↕]_4×}+}_;+↕

Try it here!

\$\endgroup\$
0
\$\begingroup\$

Setanta, 258 bytes

gniomh(l){s:=""h:=0f:=fad@l D:=dearbh@mata le i idir(0,f)h=uas(h,D(l[i]))ma h{le j idir(h,-1){s+=" "le i idir(0,f)s+=["   "," ^ ",["/ \\","/|\\"][l[i]<0|0&1]][l[i]&uas(0,ios(2,1+D(l[i])-j))]s+="\n"}}s+="_"le i idir(0,f)s+=["___","_|_"][l[i]|0&1]toradh s+"_"}

try-setanta.ie link

\$\endgroup\$
0
\$\begingroup\$

Perl 5 -MList::Util=max -a, 126 bytes

//&say map"  ^ "x($_&&$'==-abs)||($_<0?' /|\\':' / \\')x($'>-abs)||$"x4,@F for-(max map{abs}@F)..0;say'_',map$_?"_|__":____,@F

Try it online!

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.