14
\$\begingroup\$

Because of this, families from all over the world are building Christmas trees.

But this normal tree can get boring after a while, so let's make an ASCII tree!

Leafs are represented by # and must be arranged as shown in the example output. We have 5 balls (O) and 5 candy canes (J), which we place randomly around the tree. We also have a candle on top.

Input: none

Output:

         ^
         |
        ###
       ##O##
      #######
       #####
      ####J##
     #########
    ####O######
   #############
      ###J###
     #########
    ####O###J##
   #######O#####
  ###J########O##
 ###########J#####
        ###
        ###

Rules (if it's not in the rules, assume you can)

  • Balls and candy canes must be randomly placed on the tree and must have at least one leaf between them, not counting diagonals.

  • Each leaf must have a non-zero chance of getting a ball or a candy cane.

  • There may be leading or trailing spaces on each line, as long as the tree has the proper shape.

  • This is , so shortest code in characters wins.

\$\endgroup\$
11
  • 2
    \$\begingroup\$ @Billywob it's a close one, this one has a randomised factor and a candle tho :P \$\endgroup\$
    – Grey
    Dec 16, 2016 at 10:06
  • 1
    \$\begingroup\$ Yeah, this is most certainly more difficult imo. \$\endgroup\$
    – Billywob
    Dec 16, 2016 at 10:06
  • 3
    \$\begingroup\$ “But this normal tree can get boring after a while.” Then why the old school candle and not something creative? \$\endgroup\$
    – manatwork
    Dec 16, 2016 at 10:56
  • 1
    \$\begingroup\$ Since no one else has mentioned, I'll recommend that you post future challenges to the Sandbox where you can get meaningful feedback and tweak challenges before you post them to Main. \$\endgroup\$ Dec 16, 2016 at 14:35
  • 1
    \$\begingroup\$ If you don't answers that look like this, I suggest scoring by bytes rather than characters. \$\endgroup\$
    – Dennis
    Dec 16, 2016 at 17:13

8 Answers 8

8
\$\begingroup\$

CS-Script - 306 bytes

var c=new string(' ',342).ToCharArray();var r=new Random();int e=18,i,j,w;for(;i<e;i++){c[i*e+e]='\n';w=i<5?i:i<10?i-2:i<16?i-6:2;for(j=1;j++<w*2;)c[i*e+8-w+j]='#';}for(i=0;i<10;){j=37+r.Next(288);if(c[j]=='#'&c[j+1]<42&c[j-1]<42&c[j+e]<42&c[j-e]<42)c[j]=i++<5?'J':'O';}c[8]='^';c[27]='|';Console.Write(c);

Once more with formatting and comments:

// create 'char bitmap' filled with spaces
var c=new string(' ',342).ToCharArray(); 
// Random for placing ornaments
var r=new Random();
int e=18,i,j,w;
// once for each row
for(;i<e;i++)
{
    // add new lines
    c[i*e+e]='\n';
    // determine width of tree for this row
    w=i<5?i:i<10?i-2:i<16?i-6:2;
    for(j=1;j++<w*2;)
        // add leaves
        c[i*e+8-w+j]='#';
}
for(i=0;i<10;)
{
    // select random location
    j=37+r.Next(288); 
    if( // check we have a leaf
        c[j]=='#' &
        // check surrounding to be leaf/space/new-line
        c[j+1]<42 & c[j-1]<42 & c[j+e]<42 & c[j-e]<42)
        // add ornament if location is valid
        c[j]=i++<5?'J':'O';
}
// light candle
c[8]='^';
c[27]='|';
// print
Console.Write(c);

It's basically C#, but using CS-Script allows me to skip all the boiler-plate.

Try it here!

Notes:

This currently outputs another line of white spaces below the tree to make sure the that 'checking for existing ornaments below' does not throw an IndexOutOfBoundsException. Other solutions would be:

  • Checking if it is the last line before checking below (adds a few more character)
  • Not adding ornaments to the 'stem' of the tree (Same byte count, but seems to me to be against rules)

I'll leave it to the OP if this should be changed.

Lastly, this is my first golf, so any feedback is appreciated. ;)

\$\endgroup\$
5
  • \$\begingroup\$ Nice solution. It think you might need to include using System; in your byte count though, as you can't use Random or Console without it. meta.codegolf.stackexchange.com/questions/10081/… Sorry to add 13 bytes :( \$\endgroup\$
    – Erresen
    Dec 23, 2016 at 10:41
  • \$\begingroup\$ @Erresen: Thanks for the link! As far as I can tell, it only talks about imports necessary for execution though, and for cs-script using System; is not needed (it automatically imports common namespaces). But maybe I'm splitting hairs. ¯_(ツ)_/¯ \$\endgroup\$
    – amulware
    Dec 24, 2016 at 13:40
  • \$\begingroup\$ who knows! I only started playing the other day myself. Didn't know about cs script before seeing your answer. Really useful for avoiding some C# disadvantages in golfing. Whatever the answer is, I don't think a c# script's gonna win any time soon. \$\endgroup\$
    – Erresen
    Dec 24, 2016 at 18:08
  • \$\begingroup\$ That much is certain, yeah. :D \$\endgroup\$
    – amulware
    Dec 24, 2016 at 22:23
  • \$\begingroup\$ If you compile to a function, if possible in CS-Script, you could reduce the byte count i.e. _=>{var c=... return c;} \$\endgroup\$ Dec 19, 2018 at 10:57
5
\$\begingroup\$

JavaScript (ES6), 148 bytes

Hopefully, this should comply with the 'random enough' condition.

_=>[...'887656543254321077'].map(n=>' '.repeat(n)+'#'.repeat(17-2*n)).join`
`.replace(/#/g,_=>'OJ^|#'[++i<4?i:i>133|++j%13?4:j/13&1],i=1,j=new Date)

Demo

let f =

_=>[...'887656543254321077'].map(n=>' '.repeat(n)+'#'.repeat(17-2*n)).join`
`.replace(/#/g,_=>'OJ^|#'[++i<4?i:i>133|++j%13?4:j/13&1],i=1,j=new Date)

console.log(f())

\$\endgroup\$
2
  • \$\begingroup\$ I've tested and got a tree that brokes 'and must have at least one leaf (#) inbetween them, not counting diagonals' \$\endgroup\$
    – user2216
    Dec 16, 2016 at 14:00
  • \$\begingroup\$ @user2216 Unless I somehow missed or misunderstood something, the modulo was chosen in such a way that it can't possibly happen -- except along diagonals. (There are 13 distinct patterns that you can test by replacing j=new Date with j=0 to j=12.) \$\endgroup\$
    – Arnauld
    Dec 16, 2016 at 14:10
4
\$\begingroup\$

TSQL, 556 532 494 476 bytes

This script needs to be executed on the master database

Golfed:

DECLARE @ varchar(max)='',@h INT=0,@w INT=0WHILE @h<18SELECT
@+=space(9-@w)+REPLICATE(char(IIF(@h<2,94+30*@h,35)),@w*2+1)+space(9-@w)+CHAR(10),@h+=1,@w+=CHOOSE(@h,0,1,1,1,-1,1,1,1,1,-2,1,1,1,1,1,-8,0)WHILE
@h>7WITH C as(SELECT*,substring(@,number,1)v,number/20r,number%20c
FROM spt_values WHERE type='P'and number<358)SELECT @=stuff(@,number,1,CHAR(74+@h%2*5)),@h-=1FROM
c d WHERE v='#'and not exists(SELECT*FROM c WHERE abs(d.c-c)+abs(d.r-r)<2and'A'<v)ORDER BY newid()PRINT @

Ungolfed:

DECLARE @ varchar(max)='',@h INT=0,@w INT=0

WHILE @h<18
  SELECT @+=
    space(9-@w)+REPLICATE(char(IIF(@h<2,94+30*@h,35)),@w*2+1)
      +space(9-@w)+CHAR(10),
    @h+=1,
    @w+=CHOOSE(@h,0,1,1,1,-1,1,1,1,1,-2,1,1,1,1,1,-8,0)

WHILE @h>7
  WITH C as
  (
    SELECT*,substring(@,number,1)v,number/20r,number%20c
    FROM spt_values
    WHERE type='P'and number<358
  )
  SELECT @=stuff(@,number,1,CHAR(74+@h%2*5)),@h-=1
  FROM c d
  WHERE v='#'and not exists(SELECT*FROM c WHERE abs(d.c-c)+abs(d.r-r)<2and'A'<v)
  ORDER BY newid()

PRINT @

Try it out

\$\endgroup\$
1
\$\begingroup\$

Python 3 - 450 427 bytes

I know 450 is too much for python. But, but.....

from random import randint as r
t=lambda o,g:(o*g).center(19,' ')+';';s,z='','#';s+=t(z,3)*2
for h,w in zip([6,5,3],[17,13,7]):
 for i in range(h):s+=t(z,w);w-=2
s+=t('|',1)+t('^',1);s=[list(i)for i in s.split(';')]
for o in'O'*5+'J'*5:
 while 1:
  h,w=r(2,15),r(1,16)
  m=s[h]
  C,m[w]=m[w],o
  P=s[h-1][w]+s[h+1][w]+m[w-1]+m[w+1]
  if not('O'in P or'J'in P)and C!=' ':break
  m[w]=C
print (*[''.join(i)+'\n'for i in s][::-1])

If the for i in'O'*... is turned into a better recursive function then lots of bytes can be cut down.

Try it here

Edit:

Saved 2 bytes by using ; as delimiter and several bytes by taking newline byte count as 1 byte.

\$\endgroup\$
1
\$\begingroup\$

JavaScript, 204 bytes

f=(s='^|1232345634567811'.replace(/./g,x=>(y=x|0,' '.repeat(8-y)+(y?'#'.repeat(y*2+1):x)+`
`)),o=5,j=5,r=(Math.random()*56|0)*4,k)=>j?f(s.replace(/###/g,(_,i)=>i-r?_:k=o?'#O#':'#J#'),k?o-!!o:o,k?j-!o:j):s

console.log(f());
.as-console-wrapper{max-height:100%!important;top:0}

\$\endgroup\$
2
  • 1
    \$\begingroup\$ why are you counting \n as 1 byte? \$\endgroup\$ Dec 19, 2016 at 10:28
  • \$\begingroup\$ Not anymore, sorry \$\endgroup\$ Dec 19, 2016 at 10:58
1
\$\begingroup\$

PHP, 200 bytes

might be shorter with a more sophisticated approach; but I´m in a hurry.

for(;$c="^|2343456745678922"[$i++];)$s.=str_pad(+$c?str_pad("",2*$c-1,"#"):$c,17," ",2)."
";for(;$n++<10;)$s[$p=rand(0,288)]!="#"|($s[$p-18]|$s[$p+18]|$s[$p-1]|$s[$p+1])>A?$n--:$s[$p]=OJ[$n&1];echo$s;

requires PHP 5.6 or 7.0. Run with -nr or try it online.

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

Scala, 329 bytes

var r=scala.util.Random;var z=r.nextInt(2);def t{print(new StringBuilder({"^|234345645678922".map(x=>{val t=if(x>57)8 else(57-x);" "*t+{if(x>57)""+x else "#"}*(17-(t*2))+" "*t+" \n"})}.mkString)match{case e=>{var w=0;while(w<10){{val b=(r.nextInt(e.size/2)*2)+z;if(e.charAt(b)=='#'){e.setCharAt(b,if(w<5)'O'else'J');w+=1}}};e}})}
\$\endgroup\$
0
\$\begingroup\$

APL (Dyalog Unicode), 101 bytes

↑¯9↑¨'^|'
f←{⍵×(≢⍵)⍴2?2}
{(5/'OJ')@(x[10?≢x←⍸↑f¨f¯2↓↓'#'=⍵])⊢⍵}↑{' #'/⍨⍵,17-2×⍵}¨⍎¨'7656543254321077'

Try it online!

A full program which returns the tree.

Tree creation algorithm borrowed from Arnauld's answer.

Explanation

Displaying the top

↑¯9↑¨'^|'
     '^|' string
 ¯9↑¨     pad each with 8 spaces
↑         convert to matrix

Distancing the ornaments

f←{⍵×(≢⍵)⍴2?2} store the following lambda as f:
          2?2  generate 0 1 or 1 0 (random)
     (≢⍵)⍴     reshape to the length of the input
   ⍵×          multiply the input with it(vectorizes)

Display the tree

↑{' #'/⍨⍵,17-2×⍵}¨⍎¨'7656543254321077'
                  ⍎¨'7656543254321077' create an array of digits from the string
 {              }¨                     for each digit x:
        ⍵,17-2×⍵                       array [x,17-2*x]
  ' #'/⍨                               replicate spaces and hashes as per that
↑                                      convert to matrix

Add the ornaments:

{(5/'OJ')@(x[10?≢x←⍸↑f¨f¯2↓↓'#'=⍵])⊢⍵} apply the following to the tree:
                            '#'=⍵      boolean matrix for the tree
                           ↓           convert to 2d array
                        ¯2↓            remove trunk rows
                     f¨f               convert to swiss cheese with function f
                   ⍸↑                  get the indices of all 1s
                 x←                    and store in x
             10?≢                      pick 10 random indices in length(x) range
           x[                    ]     and take those from x
         @(                       )⊢⍵  replace those coordinates with:
 (5/'OJ')                              5 instances of 'O' and 5 instances of 'J'
\$\endgroup\$

Your Answer

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

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