It's almost Christmas!
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. ;)
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())
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