103
\$\begingroup\$

Given a number N, how can I print out a Christmas tree of height N using the least number of code characters? N is assumed constrained to a minimum value of 3, and a maximum value of 30 (bounds and error checking are not necessary). N is given as the one and only command line argument to your program or script.

All languages appreciated, if you see a language already implemented and you can make it shorter, edit if possible - comment otherwise and hope someone cleans up the mess. Include newlines and White Spaces for clarity, but don't include them in the character count.

A Christmas tree is generated as such, with its "trunk" consisting of only a centered "*"

N = 3:

   *
  ***
 *****
   *

N = 4:

    *
   ***
  *****
 *******
    *

N = 5:

     *
    ***
   *****
  *******
 *********
     *

N defines the height of the branches not including the one line trunk.

Merry Christmas PPCG!

\$\endgroup\$
0

111 Answers 111

3
\$\begingroup\$

05AB1E, 9 bytes

LĆ'*×j€û»

Try it online or verify all Christmas trees in the range [3, 30].

€û» can alternatively be ».º for the same byte-count: try it online.

9 bytes alternative:

·ÅÉĆ'*×.c

Try it online or verify all Christmas trees in the range [3, 30].

Explanation:

L          # Create a list in the range [1, (implicit) input]
           #  i.e. 3 → [1,2,3]
 Ć         # Enclose; appending its own head
           #  → [1,2,3,1]
  '*×     '# For each value, repeat the "*" that many times as string
           #  → ["*","**","***","*"]
     j     # Prepend spaces to make all items of a length equal to the (implicit) input
           #  → ["  *"," **","***","  *"]
      €û   # Palindromize each string
           #  → ["  *  "," *** ","*****","  *  "]
        »  # Join the list by newlines
           #  → "  *  \n *** \n*****\n  *  "
           # (after which it is output implicitly as result)

·          # Double the (implicit) input-integer
           #  i.e. 3 → 6
 ÅÉ        # Pop and push a list of all odd numbers <= this integer
           #  → [1,3,5]
   Ć       # Enclose; appending its own head
           #  → [1,3,5,1]
    '*×   '# For each value, repeat the "*" that many times as string
           #  → ["*","***","*****","*"]
       .c  # Centralize it by adding leading spaces (which implicitly joins by newlines)
           #  → "  *\n ***\n*****\n  *"
           # (after which it is output implicitly as result)
\$\endgroup\$
3
\$\begingroup\$

K (oK), 33 29 bytes

{(x+1)#(-x+!x)$(1+2*!x)#'"*"}

-4 thanks to streetser!

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ 29 bytes - {(x+1)#(-x+!x)$(1+2*!x)#'"*"} \$\endgroup\$
    – mkst
    May 9 '20 at 21:16
  • \$\begingroup\$ @streetster, thanks. updated \$\endgroup\$
    – scrawl
    May 18 '20 at 11:51
  • \$\begingroup\$ Can drop another byte by forgoing the $ pad: {" *"(x+1)#(|!x)(&,)'1+2*!x} \$\endgroup\$
    – coltim
    Dec 8 '20 at 19:21
3
\$\begingroup\$

Charcoal, 9 bytes

G↗↘←N*M↓*

Try it online!

Verbose

Polygon(:UpRight, :DownRight, :Left, InputNumber(), "*")
Move(:Down)
Print("*")

Try it online!

\$\endgroup\$
3
  • 1
    \$\begingroup\$ 8 bytes \$\endgroup\$
    – Neil
    Apr 13 '20 at 18:00
  • \$\begingroup\$ Why is this non-competing? \$\endgroup\$ Sep 23 '20 at 14:42
  • \$\begingroup\$ this was before the rule change to allow languages made after the question; feel free to edit it \$\endgroup\$
    – ASCII-only
    Sep 24 '20 at 15:47
2
\$\begingroup\$

Here's how I would do it in Python, very straightforward, only 103 characters:

import sys
n=int(sys.argv[1])
for i in range(n): print ('*'*(2*i+1)).center(2*n)
print '*'.center(2*n)
\$\endgroup\$
2
\$\begingroup\$

PHP, 111 chars

(The very last char should be a newline.)

<?php $n=$argv[1];for($r='str_repeat';$i<$n;$i++)echo $r(' ',$n-$i).$r('*',$i*2+1)."\n";echo $r(' ',$n).'*' ?>

Readable version:

<?php

$n = $argv[1];

for ($r = 'str_repeat'; $i < $n; $i++)
    echo $r(' ', $n - $i) . $r('*' , $i * 2 + 1) . "\n";

echo $r(' ', $n) . '*'

?>
\$\endgroup\$
5
  • \$\begingroup\$ You can save several characters by building the string, then echoing it. I think. Try that out. \$\endgroup\$
    – strager
    Dec 26 '08 at 0:10
  • \$\begingroup\$ Good idea, but I tried it and it only makes it longer. '$t.=(...)' is only one char shorter than 'echo (...)', and then you'd have to 'echo $t' at the end as well. \$\endgroup\$
    – Jeremy Ruten
    Dec 26 '08 at 0:19
  • \$\begingroup\$ Shortened it by 4 chars by removing the '$i = 0;' first part of the for statement. PHP assumes that nonexistent variables used in an integer context are 0 already! :P \$\endgroup\$
    – Jeremy Ruten
    Dec 26 '08 at 0:24
  • \$\begingroup\$ Saved a char by putting $r=.. inside the for. Also, I say newline characters should be one byte, not two. =] \$\endgroup\$
    – strager
    Dec 26 '08 at 0:46
  • \$\begingroup\$ Yeah I just realized I miscounted by one because I counted using the column number in my text editor. I use linux so the newline char is one byte. \$\endgroup\$
    – Jeremy Ruten
    Dec 26 '08 at 0:53
2
\$\begingroup\$

Common Lisp, 117 essential characters:

(defun x (n)
  (dotimes (v n)
    (format t "~v:@<~v{*~}~>~%"
            (1- (* 2 n))
            (1+ (* 2 v))
            '(())))
  (format t "~v:@<*~>~%" (1-(* 2 n)))

Are there any format gurus out there who know a better way to get repeating arbitrary characters?

\$\endgroup\$
2
\$\begingroup\$

Java version. 189 character

class P
{
	static String p(int n, String s) 
	{
		return --n < 1 ? s : p(n, s) + s;
	}

	public static void main(String[] a) 
	{
		for (int N = new Integer(a[0]), i = -1; i++ < N;) 
			System.out.println(p(N - i % N, " ") + p(i % N * 2 + 1, "*"));
	}
}
\$\endgroup\$
2
\$\begingroup\$

Windows Batch File

Windows batch files have poor support for string operations: they can concatename, extract and replace strings, but generation of arbitrary-length strings according to a certain pattern AFAIK can only be done via loops. This is how Zach Scrivena's solution works.

However, one can notice that the N+1-th tree line can be generated from the N-th line by cutting one leading space off and adding two traling asterisks, which pretty much simplifies the task. Also, the tree truck repeats the tree top so we can re-use that string to get rid of a few extra loops. So, here's my batch file that uses these two tricks (165 characters):

@echo off
setlocal enableextensions enabledelayedexpansion
set s=
for /l %%i in (1,1,%1)do set s= !s!
set t=!s!*
for /l %%i in (1,1,%1)do echo !t!&set t=!t:~1!**
echo %s%*

Assuming that echo is already off and command extensions and delayed variable expansion are on, we can drop the first two lines and shorten the code down to 108 characters.

Usage:

> xmastree.bat 7 & pause
       * 
      *** 
     ***** 
    ******* 
   ********* 
  *********** 
 ************* 
       *
\$\endgroup\$
2
\$\begingroup\$

C# - Recursion

using System;

class A
{
    static string f(int n, int r)
    {
        return "\n".PadLeft(2 * r, '*').PadLeft(n + r) 
            + (r < n ? f(n, ++r) : "*".PadLeft(n));
    }

    static void Main(string[] a)
    {
        Console.WriteLine(f(int.Parse(a[0]), 1));
    }
}

177 chars (not as short the other C# method posted, but a different way of doing it).

\$\endgroup\$
2
\$\begingroup\$

Haskell - 105 95 characters - 3 Relevant spaces

Improved on the other Haskell solution (https://codegolf.stackexchange.com/a/4267/7353) by 2 12 strokes.

  • Updated take x$cycle "*" into replicate x '*'
  • Removed unnecessary brackets

Updated version:

r=replicate;main=(\x->mapM_ putStrLn[r(x-l)' '++r(l+l-1)'*'|l<-[1..x]++[1]])=<<(readLn::IO Int)

Previous version:

c=cycle;main=(\x->mapM_ putStrLn[(take(x-l)$c" ")++(take(l+l-1)$c"*")|l<-[1..x]++[1]])=<<(readLn::IO Int)

Readable (updated) version:

main=(\ size->
          mapM_
               putStrLn
               [replicate (size - count) ' ' ++ replicate (count + count - 1) '*' | count <- [1..size] ++ [1]]
     ) =<< ( readLn :: IO Int )

Haskell is such an elegant language.

\$\endgroup\$
2
\$\begingroup\$

K 33

q)k)f:{{(|:'x),'1_'x}x$(1+(!x),0)#'"*"}
q)f 4
"   *   "
"  ***  "
" ***** "
"*******"
"   *   "
\$\endgroup\$
2
\$\begingroup\$

Python - 104 / 94 characters

Alright, so I have two solutions here. One of them is, I guess, a bit "trickier", placing all of the code on one line, while the other solution is actually shorter.

import sys
c=int(sys.argv[1])
for i in range(c+2):print" "*(c-1)+"*"if i==c+1 else" "*(c-i)+"*"*(2*i-1)

That's the 104-char version. Who said python is always readable? It doesn't use any "tricks" though, which is a plus, I guess? If we split the if/else statement onto a seperate line like so:

import sys
c=int(sys.argv[1])
for i in range(c+1):print" "*(c-i)+"*"*(2*i-1)
print" "*(c-1)+"*"

...this is much neater and is actually a few characters shorter.

\$\endgroup\$
2
\$\begingroup\$

JavaScript (ES6), 58 bytes

f=(n,s=`*
`,l)=>n?(k=' '.repeat(--n)+s)+f(n,'**'+s,l||k):l

Demo

f=(n,s=`*
`,l)=>n?(k=' '.repeat(--n)+s)+f(n,'**'+s,l||k):l

console.log(f(7))

\$\endgroup\$
2
\$\begingroup\$

Python 2 - 62 Bytes:

i,x=input()*2,1
exec"print('*'*(x%i)).center(i);x+=2;"*(i/2+1)

Multiplying the input by two saves a byte because of the need for extra brackets.
There may be a way to further golf the operations.

\$\endgroup\$
2
\$\begingroup\$

Python 2, 56 bytes

i=n=input()
exec"i=~-i%n;print' '*i+'*'*(n*2-i+~i);"*-~n

Try it online!

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

Perl 6, 39 bytes

{say " "x$^a-$_,\*x$_*2-1 for 1...$a,1}

Try it online!

It's one of those questions, where it's easier to just print the lines in the code block.

Explanation:

{say " "x$^a-$_,\*x$_*2-1 for 1...$a,1}
{                                     }   # Anonymous code block
                          for 1...$a,1    # Loop over 1 to n and 1 again
 say                                      # Print
     " "x$^a-$_                           # Leading spaces
               ,\*x$_*2-1                 # And then the amount of asterisks
\$\endgroup\$
2
\$\begingroup\$

05AB1E (legacy), 16 10 bytes

L·<'**Ć.c»

Try it online!

Explanation:

L·<'**Ć.c»
L          : Create a range [1..input]
 ·<        : 2n-1 every element
   '**     : Multiply every element with "*"
      Ć    : Append the first element to the end
       .c  : Centralize elements
         » : Print out with newlines

Previous solution:

µ¾·>'**¼})Ć.c»

Try it online!

Explanation:

µ¾·>'**I¾-ú¼})Ć»
 ¾·>'**I¾-ú      : Create the row with padding and push to stack
           ¼     : Increment the counter
µ           }    : Loop until the counter reaches the input
             )   : Enclose stack to a list
              Ć  : Append the head to the end
               » : Print out the stack with newlines
\$\endgroup\$
1
  • 2
    \$\begingroup\$ No need to mark as noncompeting \$\endgroup\$
    – ASCII-only
    Dec 23 '18 at 4:21
2
\$\begingroup\$

Bash: 126120

As there is no purpose, there is one:

for((z=$1-1;z;z--)){ printf -v s "%$((($1-z)*2-1))s" ""
printf "%$((2*$1-z))s\n" "${s// /*}";};printf "%$((1+$1))s\n" \*

This could be written:

#!/bin/bash
               #
              for\
            ((z=$1-
          1;z;z--));do
        printf -v s "%$((
     ($1-z)*2-1))s" "" #fil
   printf "%$((2*$1-z))s\n" \
 "${s// /*}";done;printf "%$((1
          +$1))s\n"\
              \*
              ##

In use:

set -- 12
for((z=$1-1;z;z--)){ printf -v s "%$((($1-z)*2-1))s" ""
printf "%$((2*$1-z))s\n" "${s// /*}";};printf "%$((1+$1))s\n" \*
            *
           ***
          *****
         *******
        *********
       ***********
      *************
     ***************
    *****************
   *******************
  *********************
            *

Or into the script:

./chrismas.sh 6
      *
     ***
    *****
   *******
  *********
      *
\$\endgroup\$
3
  • \$\begingroup\$ another bash solution squished down to 69 bytes :) \$\endgroup\$
    – roblogic
    Aug 22 '19 at 14:48
  • 2
    \$\begingroup\$ nice! Publish, I will give you my upvote! \$\endgroup\$
    – F. Hauri
    Aug 22 '19 at 22:16
  • 1
    \$\begingroup\$ (U could save 1 char by using \** instead of "**"! ;) \$\endgroup\$
    – F. Hauri
    Aug 22 '19 at 22:20
2
\$\begingroup\$

Intel 4004 machine code, 59 bytes

This 4-bit chip was the first commercial microprocessor, introduced in 1971. Multiplication and division were performed in software, and the accumulator could not be copied to one of the 16 registers except by swapping values.

40 33 50 0F A0 F8 B0 A0 1C 02 A1 B0 50 0F C0 24
20 A0 F8 50 2B 24 2A A1 90 F5 50 2B 24 20 A0 F8
50 2B 24 0C 53 E0 24 0D 53 E0 C0 14 32 53 E0 F8
40 2B C0 53 F0 B3 B0 A0 B1 50 02

The assembly code requires this python emulator for meaningful output.

jun start

mainloop:
    jms printline
    ld r0
    dac
    xch r0
    ld r0
    jcn an mainloop
    ld r1
    xch r0
    jms printline
    bbl 0

printline:
    fim r2 32
    ld r0
    dac
    jms printx

    fim r2 42
    ld r1
    sub r0
    ral
    jms printx

    fim r2 32
    ld r0
    dac
    jms printx

    ;carriage return
    fim r2 12
    jms $3e0
    fim r2 13
    jms $3e0

    bbl 0

printx: 
    jcn az ditch
    jms $3e0
    dac
    jun printx
ditch:
    bbl 0

start:
    jms $3f0 ; input
    xch r3
    xch r0 ; running total
    ld r0
    xch r1 ; permanent total
    jms mainloop

Sample run:

$ python intel4004-emu/main.py tree.4004 
8
       *       
      ***      
     *****     
    *******    
   *********   
  ***********  
 ************* 
***************
       *       
\$\endgroup\$
2
\$\begingroup\$

Python-3x, 119 bytes

N = int(input())
print(' '*N+'\n','\n'.join(['\t'+' '*(N-i)+'*'*(i*2+1) for i in range(N)]) + '\n', ' '*(N+3)+'*'+'\n')

result:-

enter N value
3
   *
  ***
 *****
   *



 4
        *
       ***
      *****
     *******
        *

9
             *
            ***
           *****
          *******
         *********
        ***********
       *************
      ***************
     *****************
             *
\$\endgroup\$
3
  • 2
    \$\begingroup\$ Welcome to PPCG! The point of challenges like this one is to provide a solution in as few bytes as possible, so you should include in the title how long it is. (I'd recommend pasting it into this byte counter.) Speaking of which, you could shave off 25 bytes by removing the print statement at the beginning and removing the spaces around the = sign. \$\endgroup\$
    – hallo
    Jun 17 '15 at 22:40
  • \$\begingroup\$ Ok, but this is not Python 2.7 anymore, but Python 3. ;) The remaining issue is that your code generates one size smaller tree than specified. \$\endgroup\$
    – manatwork
    Jun 18 '15 at 14:14
  • \$\begingroup\$ I mentioned it as python-2.7 because in my systems library I have python-2.7 and in my virtualenvironment I have python 3.4. When I execute python 2.7 in the editor I get errors for example if I try end=' ' in the print function if I want to print anything in single line. I import from future to enable print functions which are active in python 3.x versions. Also I have made minor change to represent correct size of tree. \$\endgroup\$
    – Praneeth
    Jun 18 '15 at 15:11
2
\$\begingroup\$

Batch, 132 129 bytes

@!! 2>nul||cmd/q/v/c%0 %1&&exit/b
for /l %%X in (1 1 %1)do set[= ![!
set]=![!*
:*
echo%]%
set]=%]:~1%**
2>x goto:*%]:~1%&echo%[%*

I shamelessly copied Golfing Delayed Expansion Variables in Batch to my batch script.
Uses the bizarre ability of GOTO :NUL to

allow execution of concatenated commands in the context of the caller

Edit 2020/5/1: Abused token delimiters to shorten variable names

\$\endgroup\$
2
\$\begingroup\$

Vyxal C, 7 bytes

ʁd›×*×J

Try it Online!

Vyxal, 13 bytes

ɾ×*§↵vøm:⁋₴h,

Try it Online!

\$\endgroup\$
2
\$\begingroup\$

jq -r, 47 41 39 bytes

-2 bytes thanks to Michael Chatiskatzi

. as$n|range(.),0|" "*($n-.)+"**"*.+"*"

Try it online! Add 2 bytes if a leading space is not acceptable.

. as$n                                   Store the input number in $n
      |                                  With that number as .
       range(.)                           Numbers from 0 up to one less than .
               ,0                         and also another 0
                 |                       With each of those numbers as .
                     *($n-.)              $n minus . copies of
                  " "                     space
                            +             Concatenate
                                 *.       . copies of
                             "**"         that string
                                   +"*"   Concatenate one more asterisk

The -r flag outputs each of those strings on a separate line without wrapping it in quotes.

\$\endgroup\$
1
  • \$\begingroup\$ range(.),0 will save 2 bytes. \$\endgroup\$ Sep 4 at 18:27
1
\$\begingroup\$

Language: Erlang, Char count: 183 (2 relevant spaces)

Here is an Erlang version, ~181chars:

-module (x).
-export ([t/1]).

t(N) ->
	t(N,0).
t(0,N) ->
	io:format("~s~s~n",[string:copies(" ",N),"*"]);
t(H,S) ->
	io:format("~s~s~n",[string:copies(" ",H),string:copies("*",(S*2)+1)]),
	t(H-1,S+1).

(btw, happy Christmas to everyone!)

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

Language: Scala, Char count: 128 (1 relevant space)

My Scala version. I'm glad I have found the * operator for strings (String implicitly promoted to RichString).

  def tree(n:Int) {
    def vals(n:Int,k:Int) = ((1 to n) map { i => (k - i, (i * 2) - 1) }).toList
    for(j <- vals(n,n) ::: vals(1,n)) 
      println(" " * j._1 + "*" * j._2)
  }
\$\endgroup\$
1
\$\begingroup\$

Language: Nemerle+Nextem, Char count: 129 (1 relevant space)

Nemerle with Nextem:

type s=string;
module t {
    public Main(a : array[s]) : void {
    	def t = int.Parse(a[0]);
    	def x(i) { print s(' ',t-i) + s('*',i*2+1) }
    	$[0..t].Iter(x);
    	x(0)
    }
}

Char count: 128

Edit: Made it take an arg Edit2: Imperative now

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

Language: C, Char count: 433 (1 relevant space)

C version. Not short, not pretty, but it works.

#include <stdio.h>

void printLevel(int level, int width)
{
    int i;
    int count = level + (level - 1);
    int spaces = width - count;
    int lowerBound = spaces / 2;
    int upperBound = width - lowerBound;
    for (i = 0; i < width; i++) {
        if (i >= lowerBound && i < upperBound) {
            printf("*");
        } else {
            printf(" ");
        }
    }
    printf("\n");
}

void makeTree(int level)
{
    int i;
    int width = level * 2 - 1;
    for (i = 1; i <= level; i++) {
        printLevel(i, width);
    }
    printLevel(1, width);
}

int main(int argc, char **argv)
{
    int level = atoi(argv[1]);
    makeTree(level);
}
\$\endgroup\$
1
\$\begingroup\$

Language: Python, Char count: 104

Another take at python. Note that the question requested for a script, not a function.

import sys
n= int(sys.argv[1])
c= lambda s: s.center(2*n)
print "\n".join(c("*"*(2*i+1)) for i in range(n)); print c("*")

$ py ax 11
          *
         ***
        *****
       *******
      *********
     ***********
    *************
   ***************
  *****************
 *******************
*********************
          *
\$\endgroup\$
1
\$\begingroup\$

PHP (133 relevant characters):

function xmastree($h) {
    for($i=0;$i<$h;++$i)
        echo str_repeat(' ',$h-$i-1).str_repeat('*',2*$i+1)."\n";
    echo str_repeat(' ',$h-1)."*\n";
}
\$\endgroup\$
1
\$\begingroup\$

Language: Pike

101 Relevant characters

int main (int c, array a) {
    int n=(int)a[1], i,l;
    for(;i<=n; l = ++i < n ? i : 0)
        write(" " *(n-l) + "*" * (l*2+1) +"\n");
}
\$\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.