Can't see the forest for the trees

29

4

Write a program or function that draws a tree of trees, thus constructing a forest.

The trees are drawn like stacking a pyramid. The first (top) row contains 1 tree, the next row down contains 2 (for a total of 3), the next contains 3 (for a total of 6), and so on. If there aren't enough trees to complete a full row, fill it to the left and leave the spots on the right empty. Additionally, lower-level trees slightly overlap upper-level trees due to their placement.

This is a forest of size 1

  /\
 //\\
///\\\
  ||
  ||

This is a forest of size 2

      /\
     //\\
  /\///\\\
 //\\ ||
///\\\||
  ||
  ||

This is a forest of size 3

      /\
     //\\
  /\///\\\/\
 //\\ || //\\
///\\\||///\\\
  ||      ||
  ||      ||

This is a forest of size 4

          /\
         //\\
      /\///\\\/\
     //\\ || //\\
  /\///\\\||///\\\
 //\\ ||      ||
///\\\||      ||
  ||
  ||

This is a forest of size 5 (note the top of the fifth tree is covering the trunk of the first tree)

          /\
         //\\
      /\///\\\/\
     //\\ || //\\
  /\///\\\/\///\\\
 //\\ || //\\ ||
///\\\||///\\\||
  ||      ||
  ||      ||

(skip a few)
This is a forest of size 8 (extending the pattern)

              /\
             //\\
          /\///\\\/\
         //\\ || //\\
      /\///\\\/\///\\\/\
     //\\ || //\\ || //\\
  /\///\\\/\///\\\||///\\\
 //\\ || //\\ ||      ||
///\\\||///\\\||      ||
  ||      ||
  ||      ||

and so on.

Input

A single positive integer in any convenient format, n > 0.

Output

An ASCII-art representation of the forest, following the above rules. Leading/trailing newlines or other whitespace are optional, provided that the trees all line up appropriately.

Rules

  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

AdmBorkBork

Posted 2017-02-10T17:46:07.147

Reputation: 41 581

I'm not sure what the pattern is regarding the order in which the trees are drawn. That is, given n, what are the positions of the trees? – Luis Mendo – 2017-02-10T21:29:47.413

@LuisMendo As I understand, they are filled in reading order. So, each row is filled in turn, and if there's not enough trees for the whole row, the remainder are placed as far left as possible in that row. – xnor – 2017-02-10T21:34:37.140

@LuisMendo xnor has it right. If I can re-word that to make it more clear, please ping me in chat. – AdmBorkBork – 2017-02-10T21:35:07.840

@xnor Thanks, it's totally clear to me now – Luis Mendo – 2017-02-10T21:59:46.547

@Adm Actually it was written right there in the challenge. Apparently I can't read :-) – Luis Mendo – 2017-02-10T22:01:14.783

Answers

5

Haskell 310 bytes

w i=putStr$unlines$reverse$b i 0 0[][]
b 0 _ _ w r=e w r
b c l 0 w r=b c(l+1)l(e w r)[]
b c l p w r=b(c-1)l(p-1)w(n(++)["  ||    ","  ||    ","///\\\\\\  "," //\\\\   ","  /\\    "]r)
e w r=t++n(n d)(map(\t->"    "++t)w)c where(t,c)=splitAt 2 r
n f(a:c)(b:d)=f a b:n f c d
n _ a[]=a
n _ _ a=a
d d ' '=d
d _ d=d

Call it with w 5, for example.

Here the uncompressed code:

-- TreeTree
-- by Gerhard
-- 12 February 2017

module TreeTree (wood,test) where

type Tree = [String]

-- Test cases
test = do
 wood 0
 wood 1
 wood 2
 wood 3
 wood 4
 wood 5

-- build wood
wood :: Int -> IO ()
wood i = printTree $ buildWood i 0 0 [] []

-- Prints the trees
printTree :: Tree -> IO ()
printTree = putStr . unlines . reverse

-- build wood
buildWood :: Int -> Int -> Int -> Tree -> Tree -> Tree
buildWood 0 _ _ w r = concatTree w r 
buildWood c l 0 w r = buildWood c (l+1) l (concatTree w r) []
buildWood c l p w r = buildWood (c-1) l (p-1) w (addTree r)

-- indent definition
space :: String
space = "    "

-- tree definition
tree :: Tree
tree = reverse [
 "  /\\    ",
 " //\\\\   ",
 "///\\\\\\  ",
 "  ||    ",
 "  ||    "]

-- Add a Tree on the left side
addTree :: Tree -> Tree
addTree = match (++) tree

-- add tree row at the bottom of the wood
concatTree :: Tree -> Tree -> Tree
concatTree w r = trunk ++ matched
 where
  wood = grow w
  (trunk, crown) = splitAt 2 r 
  matched = matchTree wood crown

-- elnarge forrest on the left side to match next tree line
grow :: Tree -> Tree
grow = map (\t -> space ++ t)

-- match
match :: (a -> a -> a) -> [a] -> [a] -> [a]
match f (a:az) (b:bz) = f a b : match f az bz
match _ a [] = a
match _ _ a  = a

-- match trees
matchTree :: Tree -> Tree -> Tree
matchTree = match matchLine

-- match lines
matchLine :: String -> String -> String
matchLine = match matchChar

-- match chars
matchChar :: Char -> Char -> Char
matchChar c ' ' = c
matchChar _ c   = c

-- End

Gerhard

Posted 2017-02-10T17:46:07.147

Reputation: 161

Welcome to PPCG! – AdmBorkBork – 2017-02-13T13:17:22.217

4

C++ (on Windows), 330 312 308 304 303 bytes

#import<cstdio>
#import<windows.h>
#define P(x,y,s)SetConsoleCursorPosition(GetStdHandle(-11),{X+x,Y+y});puts(s);
int X,Y,R,r,c;t(){P(2,-2,"/\\")P(1,-1,"//\\\\")P(0,0,"///\\\\\\")P(2,1,"||")P(2,2,"||")}f(int n){for(c=R=r=1;c<n;c+=++R);for(;r;r++)for(c=0;++c<r+1;){X=(R-r-2)*4+c*8;Y=r*2;t();r=--n?r:-1;}}

Call with:

int main()
{
    f(8);
}

Steadybox

Posted 2017-02-10T17:46:07.147

Reputation: 15 798

4

JavaScript (ES6), 357 297 276 bytes

f=
n=>{a=`  /\\`;d=`///\\\\\\`;b=d+`/\\`;c=` //\\\\ ||`;d+=`||`;e=`
`;r=`repeat`;s=``;for(i=1;n>i;n-=i++)s=(s+a+b[r](i-1)+e+c[r](i)).replace(/^/gm,`    `)+e;return(s+a+b[r](n-1)+d[r](i-=n)+e+c[r](n)+(s=`      ||`[r](i))+e+d[r](n)+s+(s=e+`  ||    `[r](n))+s).replace(/\|.$/gm,``)}
<input type=number min=1 oninput=o.textContent=f(this.value)><pre id=o>

Edit: Saved 21 bytes thanks to @KritixiLithos.

Neil

Posted 2017-02-10T17:46:07.147

Reputation: 95 035

For the first repeat, you can change blah.repeat(val) to blah[w="repeat"](val) and then you can change the subsequent occurences of repeat to just [w](val) instead to save bytes – user41805 – 2017-02-12T07:46:11.043

@KritixiLithos I can't quite do that because the first repeat is inside the for loop and won't run for n=1, but I was still able to save 21 bytes. – Neil – 2017-02-12T10:53:09.527

0

Javascript 418 377 bytes

Thanks to @Kritixi Lithos for helping golf off 39 bytes

x=>{s='';for(t=0;++t<x;x-=t);q='//\\\\';z="///\\\\\\";h="/\\";t--;for(i=0;i<t;i++){a=4*(t-i)+1;s+=" "[w="repeat"](a+1)+h+(z+h)[w](i)+`
`+" "[w](a)+q+(" || "+q)[w](i)+`
`}c=t-x+1>0?t-x+1:0;return x?s+"  "+(h+z)[w](--x)+h+(c?(z+"||")[w](c-1)+z:'')+`
 `+q+(" || "+q)[w](x)+" ||     "[w](c)+`
`+(z+"||")[w](x)+z+(c?"||"+"      ||"[w](c-1):'')+`
`+("  ||    "[w](x+1)+`
`)[w](2):''}

Try it Online

fəˈnɛtɪk

Posted 2017-02-10T17:46:07.147

Reputation: 4 166

2For the first repeat, you can change blah.repeat(val) to blah[w="repeat"](val) and then you can change the subsequent occurences of repeat to just [w](val) instead to save bytes – user41805 – 2017-02-11T07:16:28.127

0

C (on Windows), 297 295 294 bytes

#import<windows.h>
#define P(x,y,s)C.X=X+x;C.Y=Y+y;SetConsoleCursorPosition(GetStdHandle(-11),C);puts(s);
COORD C;X,Y,R,r,c;t(){P(2,-2,"/\\")P(1,-1,"//\\\\")P(0,0,"///\\\\\\")P(2,1,"||")P(2,2,"||")}f(n){for(c=R=r=1;c<n;c+=++R);for(;r;r++)for(c=0;++c<r+1;){X=(R-r-2)*4+c*8;Y=r*2;t(r=--n?r:-1);}}

Similar to my C++ answer, but I posted this because it's somewhat shorter in C.

Steadybox

Posted 2017-02-10T17:46:07.147

Reputation: 15 798

@DLosc It's C. #import is a (deprecated) GCC extension. Fit for golfing, though. – Steadybox – 2017-02-11T22:29:30.907

Huh, interesting. Now I see that there's a tip for that. You might mention that in your answer.

– DLosc – 2017-02-11T22:33:54.743

@DLosc Perhaps, but I think it's quite widely used in golfing, along with some other GCC (though not limited to GCC) extensions like omitting <stdio.h> and automatically assuming a global variable to be int or a function to return int. – Steadybox – 2017-02-11T22:42:06.140