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\$
  • 2
    \$\begingroup\$ @Billywob it's a close one, this one has a randomised factor and a candle tho :P \$\endgroup\$ – Grey Dec 16 '16 at 10:06
  • 1
    \$\begingroup\$ Yeah, this is most certainly more difficult imo. \$\endgroup\$ – Billywob Dec 16 '16 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 '16 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\$ – AdmBorkBork Dec 16 '16 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 '16 at 17:13
4
\$\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\$
  • \$\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 '16 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 '16 at 14:10
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\$
  • \$\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 '16 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 '16 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 '16 at 18:08
  • \$\begingroup\$ That much is certain, yeah. :D \$\endgroup\$ – amulware Dec 24 '16 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\$ – TheLethalCoder Dec 19 '18 at 10:57
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\$
  • 1
    \$\begingroup\$ why are you counting \n as 1 byte? \$\endgroup\$ – Daniel Shillcock Dec 19 '16 at 10:28
  • \$\begingroup\$ Not anymore, sorry \$\endgroup\$ – Washington Guedes Dec 19 '16 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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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