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\$ Commented Dec 16, 2016 at 10:06
  • 1
    \$\begingroup\$ Yeah, this is most certainly more difficult imo. \$\endgroup\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented Dec 24, 2016 at 18:08
  • \$\begingroup\$ That much is certain, yeah. :D \$\endgroup\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented 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\$ Commented Dec 19, 2016 at 10:28
  • \$\begingroup\$ Not anymore, sorry \$\endgroup\$ Commented 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\$

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.