Code Golf Christmas Edition: Cómo imprimir un árbol de Navidad de altura N

89

Dado un número N, ¿cómo puedo imprimir un árbol de navidad de altura Nusando la menor cantidad de caracteres de código? Nse supone restringido a un valor mínimo de 3, y un valor máximo de 30(no son necesarios los límites y la comprobación de errores). Nse proporciona como el único argumento de línea de comando para su programa o script.

Todos los idiomas son apreciados, si ve un idioma ya implementado y puede acortarlo, edite si es posible, comente lo contrario y espere que alguien limpie el desorden. Incluya nuevas líneas y espacios en blanco para mayor claridad, pero no los incluya en el recuento de caracteres.

Un árbol de Navidad se genera como tal, con su "tronco" que consiste solo en un "*" centrado

N = 3:

   *
  ***
 *****
   *

N = 4:

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

N = 5:

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

N define la altura de las ramas sin incluir el tronco de una línea.

Feliz Navidad PPCG!

TheSoftwareJedi
fuente

Respuestas:

46

J , 24 caracteres

(,{.)(}:@|."1,.])[\'*'$~

   (,{.)(}:@|."1,.])[\'*'$~5
    *    
   ***   
  *****  
 ******* 
*********
    *    

Explicación:

'*'$~5
*****

[\'*'$~5
*    
**   
***  
**** 
*****

Luego }:@|."1invierte cada fila y quita la última columna, y la ,.engrapa ].

Luego ,{.pega la primera columna en la parte inferior.

Entradas anteriores :

29 caracteres, sin espacios en absoluto.

   ((\: i. @ #),}.) "1 $ & '*'" 0>: 0, ~ i.3
  * *
 ***
*****
  * *
   ((\: i. @ #),}.) "1 $ & '*'" 0>: 0, ~ i.11
          * *
         ***
        *****
       *******
      *********
     ***********
    *************
   ***************
  *****************
 *******************
*********************
          * *

   NÓTESE BIEN. cuenta de 1 a n , luego 1 de nuevo
   >: 0, ~ i.3
1 2 3 1
   NÓTESE BIEN. replicar '*' x veces cada uno
   $ & '*' "0>: 0, ~ i.3
* *
** **
***
* *
   NÓTESE BIEN. invertir cada fila
   (\: i. @ #) "1 $ & '*'" 0>: 0, ~ i.3
  * *
 ** **
***
  * *
   NÓTESE BIEN. quitar la columna principal
   }. "1 $ & '*'" 0>: 0, ~ i.3

* *
** **

   NÓTESE BIEN. pegar juntos
   ((\: i. @ #),}.) "1 $ & '*'" 0>: 0, ~ i.3
  * *
 ***
*****
  * *
efímero
fuente
Con solo 9 caracteres más, puede darle un nombre a esta función:c=:[:((\:i.@#),}.)"1[:$&'*'"0[:>:0,~i.
ephemient
11
¿Ustedes usan algún tipo de biblioteca de documentación de J para entender el código? :)
92

Brainfuck, 240 caracteres

              ,
             >++
            +++++
           +[-<---
          --->],[>+
         +++++++[-<-
        ----->]<<[->+
       +++++++++<]>>]<
      [->+>+>>>>>>>+<<<
     <<<<<<]>>>>++++++++
    [-<++++>]>++++++[-<++
   +++++>]+>>>++[-<+++++>]
  <<<<<<[-[>.<-]<[-<+>>+<]<
 [->+<]>>>>>[-<.>>+<]>[-<+>]
>.<<++<<<-<->]>>>>>>>-[-<<<<<
           <.>>>
           >>>]<
           <<<<.

Todavía no está listo. Funciona, pero solo con números de un solo dígito.

EDITAR: ¡Listo! Funciona para intérpretes que usan 0 como EOF. Vea NOTEs en la fuente comentada para aquellos con -1.

EDITAR nuevamente: debo tener en cuenta que debido a que Brainfuck carece de un método estándar para leer argumentos de línea de comandos, usé stdin (entrada estándar) en su lugar. ASCII, por supuesto.

EDITAR una tercera vez: Oh querido, parece que eliminé .los caracteres (salida) al condensar el código. Fijo...

Aquí está la gestión básica de la memoria del bucle principal. Estoy seguro de que se puede optimizar mucho para reducir el recuento de caracteres en aproximadamente 30.

  1. Temporal
  2. Copia del mostrador
  3. Contador (cuenta hasta 0)
  4. Carácter de espacio (decimal 32)
  5. Asterisco (decimal 42)
  6. Número de asteriscos en la línea actual (1 + 2 * contador)
  7. Temporal
  8. Nuevo personaje de línea
  9. ¿Temporal?
  10. Número total de líneas (es decir, valor de entrada; almacenado hasta el final, al imprimir el tronco)

Versión condensada:

,>++++++++[-<------>],[>++++++++[-<------>]<<[->++++++++++<]>>]<[->+>+>>>>>>>+<<<<<<<<<]>>>>++++++++[-<++++>]>++++++[-<+++++++>]+>>>++[-<+++++>]<<<<<<[-[>.<-]<[-<+>>+<]<[->+<]>>>>>[-<.>>+<]>[-<+>]>.<<++<<<-<->]>>>>>>>-[-<<<<<<.>>>>>>]<<<<<.

Y la bonita versión:

ASCII to number
,>
++++++++[-<------>]  = 48 ('0')

Second digit (may be NULL)
,
NOTE:   Add plus sign here if your interpreter uses negative one for EOF
[ NOTE: Then add minus sign here
 >++++++++[-<------>]
 <<[->++++++++++<]>>  Add first digit by tens
]

Duplicate number
<[->+>+>>>>>>>+<<<<<<<<<]>>

Space char
>>++++++++[-<++++>]

Asterisk char
>++++++[-<+++++++>]

Star count
+

New line char
>>>++[-<+++++>]<<<

<<<

Main loop
[
Print leading spaces
-[>.<-]

Undo delete
<[-<+>>+<]
<[->+<]
>>

Print stars
>>>[-<.>>+<]

Add stars and print new line
>[-<+>]
>.<
<++

<<<

-<->
End main loop
]

Print the trunk
>>>>>>>
-[-<<<<<<.>>>>>>]
<<<<<.

Merry Christmas =)
jrtapsell
fuente
1
mi cerebro se siente ... enfermo
3
Oh Dios mío.
cobarde anónimo
63

Perl, 50 caracteres

(1 espacios relevantes)

perl: versión de una línea:

print$"x($a-$_),'*'x($_*2+1),$/for 0..($a=pop)-1,0

y ahora con más whitesapce:

print $"  x ( $a - $_ ),             #"# Syntax Highlight Hacking Comment
      '*' x ( $_ * 2  + 1),
      $/
for 0 .. ( $a = pop ) - 1, 0;

$ perl tree.pl 3
   *
  ***
 *****
   *
$ perl tree.pl 11
           *
          ***
         *****
        *******
       *********
      ***********
     *************
    ***************
   *****************
  *******************
 *********************
           *
$ 

Explicación ampliada para usuarios que no son de Perl.

# print $Default_List_Seperator ( a space )  
#     repeated ( $a - $currentloopiterationvalue ) times,
print $" x ( $a - $_ ), 
#"# print '*' repeated( $currentloopiteration * 2 + 1 ) times. 
  '*' x ( $_ * 2  + 1),
# print $Default_input_record_seperator ( a newline )
  $/
# repeat the above code, in a loop, 
#   iterating values 0 to ( n - 1) , and then doing 0 again
for 0 .. ( $a = pop ) - 1, 0;
# prior to loop iteration, set n to the first item popped off the default list, 
#   which in this context is the parameters passed on the command line. 
MkV
fuente
25
Santa mierda ... Perl realmente es ilegible.
8
@zenazn, también, debe tenerse en cuenta que la mayoría de los juegos de golf es un código MALO en cualquier idioma. Si esto fuera una competencia por el código más limpio, también podríamos ganarlo.
Kent Fredric
55
@zenazn: prueba, puedes vernos colaborando y mejorando el código de los demás arriba, esto demuestra que NOSOTROS podemos leer CADA UNO código perfectamente bien.
Kent Fredric
1
PD: Gracias por la explicación para los programadores que no son de Perl. Todavía es bastante ilegible, pero al menos tiene sentido. Supongo que te acostumbras después de un tiempo.
2
@RobH: J es el hijo de APL. En algunos sentidos, es más ilegible porque no utiliza el juego de caracteres de APL con un símbolo especial para cada operación; en cambio, sobrecarga los caracteres ASCII con múltiples significados. stackoverflow.com/questions/392788/1088931#1088931
ephemient el
26

Idioma: Python (a través de shell), recuento de caracteres: 64 (2 espacios significativos)

python -c "
n=w=$1
s=1
while w:
    print' '*w+'*'*s
    s+=2
    w-=1
print' '*n+'*'"

$ sh ax6 11
           *
          ***
         *****
        *******
       *********
      ***********
     *************
    ***************
   *****************
  *******************
 *********************
           *
tzot
fuente
8
Lo que más me gusta de esta solución es que Python hace que sea muy difícil escribir código oscuro, es una de las soluciones más legibles
Estás utilizando el shell para procesar el argumento, lo cual no está en el espíritu del código golf IMO. Usando "import sys" y "n = w = int (sys.argv [1])" y una sangría de 1 carácter para el cuerpo del bucle, se me ocurren 89 caracteres para esta versión.
44
Así es como lo hice antes. El espíritu de esta pregunta es divertirse y, además, no se especificó el uso de un solo idioma :) Vea la respuesta, por ejemplo; sin argumentos.
26

x86 asm de 16 bits, 50 bytes

¿Todavía no hay una versión de ensamblaje? :)

    bits 16
    org 100h

    mov si, 82h
    lodsb
    aaa
    mov cx, ax
    mov dx, 1
    push cx 
    mov al, 20h
    int 29h
    loop $-2
    push dx
    mov al, 2ah
    int 29h
    dec dx
    jnz $-3
    pop dx
    mov al, 0ah
    int 29h
    inc dx
    inc dx
    pop cx
    loop $-23
    shr dx, 1
    xchg cx, dx
    mov al, 20h
    int 29h
    loop $-2
    mov al, 2ah
    int 29h
    ret

(Nota: N está limitado a 1 - 9 en esta versión)

G:\>tree 9
         *
        ***
       *****
      *******
     *********
    ***********
   *************
  ***************
 *****************
         *

Descarga aquí

Jonas Gulle
fuente
24

Idioma: Windows Batch Script ( ¡impactante! )

@echo off
echo Enable delayed environment variable expansion with CMD.EXE /V

rem Branches
for /l %%k in (1,1,%1) do (
set /a A=%1 - %%k
set /a B=2 * %%k - 1
set AA=
for /l %%i in (1,1,!A!) do set "AA=!AA! "
set BB=
for /l %%i in (1,1,!B!) do set BB=*!BB!
echo !AA!!BB!
)

rem Trunk
set /a A=%1 - 1
set AA=
for /l %%i in (1,1,!A!) do set "AA=!AA! "
echo !AA!*

fuente
¡masoquista! Me gusta
Muy bien ... obtienes +1
2
La expansión variable retardada se puede habilitar con el setlocal enabledelayedexpansioncomando
Helen el
tipo. ¿seriamente?
No puedo hacer que funcione. Aunque la primera vez lo intento.
Fabinout
21

Ruby, 64 bytes

n=ARGV[0].to_i
((1..n).to_a+[1]).each{|i|puts' '*(n-i)+'*'*(2*i-1)}

n=$*[0].to_i
((1..n).to_a<<1).each{|i|puts' '*(n-i)+'*'*(2*i-1)}

Feliz Navidad a todos!

Editar: Mejoras agregadas según lo sugerido por Joshua Swink

jrtapsell
fuente
Dang esperaba que nadie lo haya intentado en rubí todavía. buen trabajo.
Esta es una muy buena línea de Ruby.
¿Parecía demasiado abrubt? Lo siento, no es mi intención! ¡Feliz Navidad! :)
No quise ser malo tampoco, ¡y por supuesto que tenías razón! ¡Feliz Navidad!
1
En 1.9, puede guardar algunos caracteres más: n=$*[0].to_i;puts [*1..n,1].map{|i|" "*(n-i)+"*"*(2*i-1)}lo reduce a 58.
14

Idioma: C #, recuento de caracteres: 120

static void Main(string[] a)
{
    int h = int.Parse(a[0]);

    for (int n = 1; n < h + 2; n++)
        Console.WriteLine(n <= h ?
            new String('*', n * 2 - 1).PadLeft(h + n) :
            "*".PadLeft(h + 1));
    }
}

Solo el código, sin formato (120 caracteres):

int h=int.Parse(a[0]);for(int n=1;n<h+2;n++)Console.WriteLine(n<=h?new String('*',n*2-1).PadLeft(h+n):"*".PadLeft(h+1));

Versión con 109 caracteres (solo el código):

for(int i=1,n=int.Parse(a[0]);i<n+2;i++)Console.WriteLine(new String('*',(i*2-1)%(n*2)).PadLeft((n+(i-1)%n)));

Resultado para altura = 10:

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

fuente
13

Idioma: dc (a través de shell) Recuento de caracteres: 83

Una versión de cc un poco más corta:

dc -e '?d1rdsv[d32r[[rdPr1-d0<a]dsaxszsz]dsbx1-rd42rlbx2+r10Plv1-dsv0<c]dscxszsz32rlbx[*]p' <<<$1

EDITAR: cambió la constante 10 a $ 1

Hynek -Pichi- Vychodil
fuente
11
Buen señor, ¿qué demonios es eso?
1
Acabo de leer la página de manual ;-)
12

python, truco "-c" ... @ 61 caracteres (y una línea)

python -c"for i in range($1)+[0]:print' '*($1-i)+'*'*(2*i+1)"

fuente
En realidad, son 57 caracteres, solo el espacio es significativo según las especificaciones de la pregunta.
10

Aquí hay una versión de Haskell razonablemente eficiente en espacio, con 107 caracteres:

main=interact$(\g->unlines$map(\a->replicate(g-a)' '++replicate(a*2-1)'*')$[1..g]++[1]).(read::[Char]->Int)

ejecutándolo

$ echo 6 | runhaskell tree.hs
     *
    ***
   *****
  *******
 *********
***********
     *

Feliz Navidad a todos :)


fuente
10

Idioma: dc (a través de shell), recuento de caracteres: 119 (1 espacio significativo)

Solo por la oscuridad :)

dc -e "$1dsnsm"'
[[ ]n]ss
[[*]n]st
[[
]n]sl
[s2s1[l2xl11-ds10<T]dsTx]sR
[lndlslRxlcdltlRxllx2+sc1-dsn0<M]sM
1sclMxlmlslRxltxllx
'

$ sh ax3 10
          *
         ***
        *****
       *******
      *********
     ***********
    *************
   ***************
  *****************
 *******************
          *
tzot
fuente
Uhm en serio, wtf? No entiendo una sola línea de eso: P
dc es una calculadora de pulido inverso. 'man dc' es el camino obvio para ir :)
6

Mejor C ++, alrededor de 210 caracteres:

#include <iostream>
using namespace std;
ostream& ChristmasTree(ostream& os, int height) {
    for (int i = 1; i <= height; ++i) {
        os << string(height-i, ' ') << string(2*i-1, '*') << endl;
    }
    os << string(height-1, ' ') << '*' << endl;
    return os;
}

Minimizado a 179:

#include <iostream>
using namespace std;ostream& xmas(ostream&o,int h){for(int i=1;i<=h;++i){o<<string(h-i,' ')<<string(2*i-1,'*')<<endl;}o<<string(h-1,' ')<<'*'<<endl;return o;}

fuente
usando std; ¿nadie?
extraño: cuando comencé solo había un par de std :: 'sy' usando namespace std; ' Fue mucho texto. Supongo que ahora serían menos personajes.
Su versión es más ineficiente que la mía, porque tiene que crear cadenas, mi versión solo imprime los caracteres que necesita. :)
pyon
6

Lenguaje: pitón, sin trucos, 78 caracteres

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

fuente
6

Groovy 62B

n=args[0]as Long;[*n..1,n].any{println' '*it+'*'*(n-~n-it*2)}

_ _

n = args[0] as Long
[*n..1, n].any{ println ' '*it + '*'*(n - ~n - it*2) }

fuente
5

Mejorando la respuesta de ΤΖΩΤΖΙΟΥ. No puedo comentar, así que aquí hay una nueva publicación. 72 caracteres.

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

Usando el truco "python -c", 61 caracteres.

python -c "
for i in range($1)+[0]:
   print ('*'*(2*i+1)).center(2*$1)
"

Aprendí la función central y que "python -c" puede aceptar más de un código de línea. Gracias ΤΖΩΤΖΙΟΥ.


fuente
5

C # usando Linq:

    using System;
    using System.Linq;
    class Program
        {
            static void Main(string[] args)
            {
                int n = int.Parse(args[0]);
                int i=0;
                Console.Write("{0}\n{1}", string.Join("\n", 
                   new int[n].Select(r => new string('*',i * 2 + 1)
                   .PadLeft(n+i++)).ToArray()),"*".PadLeft(n));
            }
       }

170 personajes.

int n=int.Parse(a[0]);int i=0;Console.Write("{0}\n{1}",string.Join("\n",Enumerable.Repeat(0,n).Select(r=>new string('*',i*2+1).PadLeft(n+i++)).ToArray()),"*".PadLeft(n));

fuente
5

AWK, 86 caracteres en una línea.

awk '{s="#";for(i=0;i<$1;i++){printf"%"$1-i"s%s\n","",s;s=s"##"}printf"%"$1"s#\n",""}'

echo "8" | awk '{s="#";for(i=0;i<$1;i++){printf"%"$1-i"s%s\n","",s;s=s"##"}printf"%"$1"s#\n",""}'
        #
       ###
      #####
     #######
    #########
   ###########
  #############
 ###############
        #

cat tree.txt
3
5

awk '{s="#";for(i=0;i<$1;i++){printf"%"$1-i"s%s\n","",s;s=s"##"}printf"%"$1"s#\n",""}' tree.txt
   #
  ###
 #####
   #
     #
    ###
   #####
  #######
 #########
     #

fuente
5

Idioma: Java, recuento de caracteres: 219

class T{ /* 219 characters */
  public static void main(String[] v){
    int n=new Integer(v[0]);
    String o="";
    for(int r=1;r<=n;++r){
      for(int s=n-r;s-->0;)o+=' ';
      for(int s=1;s<2*r;++s)o+='*';
      o+="%n";}
    while(n-->1)o+=' ';
    System.out.printf(o+"*%n");}}

Como referencia, pude afeitar la solución Java anterior, usando recursividad, hasta 231 caracteres, desde el mínimo anterior de 269. Aunque un poco más, me gusta esta solución porque Testá realmente orientada a objetos. Podría crear un pequeño bosque de Tinstancias de tamaño aleatorio . Aquí está la última evolución en esa táctica:

class T{ /* 231 characters */
  public static void main(String[] v){new T(new Integer(v[0]));}}
  String o="";
  T(int n){
    for(int r=1;r<=n;++r){
      x(' ',n-r);x('*',2*r-1);o+="%n";}
    x(' ',n-1);
    System.out.printf(o+"*%n");
  }
  void x(char c,int x){if(x>0){o+=c;x(c,x-1);}
 }
joel.neely
fuente
Tu nuevo recuento de personajes es 251 (1 espacio relevante)
deshacerse de "public static void main", usar un bloque estático y compilar con java 6;)
Fabinout
Sé que han pasado casi 9 años (risas ...) pero puedes jugar al golf algunas cosas: class T{public static void main(String[]v){long n=new Long(v[0]),r=1,s;String o="";for(;r<=n;r++){for(s=n-r;s-->0;)o+=' ';for(;++s<2*r;)o+='*';o+="\n";}while(n-->1)o+=' ';System.out.println(o+"*");}}(199 caracteres / bytes)
Kevin Cruijssen
5

Idioma: PowerShell, recuento de caracteres: 41 (incluido 1 espacio)

1..$args[0]+1|%{" "*(30-$_)+"*"*($_*2-1)}
Jaykul
fuente
5

21 personajes con dyalog APL.

m,⍨⌽0 1↓m←↑'*'\¨⍨1,⍨⍳

⍳ da un vector de enteros que comienzan con 1.

1, ⍨ agrega uno al final del vector. Este será el pie del árbol.

'*' \ ¨⍨ da un vector de * cadenas con longitudes dadas por el vector anterior.

↑ transforma el vector en una matriz y agrega espacios a la derecha.

m ← almacena la matriz en m.

0 1 ↓ elimina cero filas y la primera columna.

⌽ invierte la matriz.

m, ⍨ se concatena con m en el lado derecho.

usuario10639
fuente
m,⍨⌽0 1↓m←->(⌽,0 1↓⊢)
ngn
4

Idioma: C, recuento de caracteres: 133

Mejora de la versión C.

char s[61];

l(a,b){printf("% *.*s\n",a,b,s);}

main(int i,char**a){
  int n=atoi(a[1]);memset(s,42,61);
  for(i=0;i<n;i++)l(i+n,i*2+1);l(n,1);
}

Funciona e incluso toma la altura del árbol como argumento. Necesita un compilador que tolere el código de estilo K y R.

Me siento tan sucia ahora. Este código es feo.


fuente
Esto tiene el mismo problema que mi primer corte en Java; ¡no es un programa completo con el uso de un argumento de línea de comandos!
¿Oh? ¿Se requiere esto? No hay problema. Lo arreglaré
Son 138 caracteres cuando se eliminan todas las nuevas líneas innecesarias.
¿Puede Berk Güder el
4

R (62 bytes)

Todavía no vi la solución R. Corrígeme si me lo perdí.

for(i in c(1:N,1))cat(rep(" ",N-i),rep("*",2*i-1),"\n",sep="")

Salida:

> N <- 3
> for(i in c(1:N,1))cat(rep(" ",N-i),rep("*",2*i-1),"\n",sep="")
  *
 ***
*****
  *
> 
> N <- 4
> for(i in c(1:N,1))cat(rep(" ",N-i),rep("*",2*i-1),"\n",sep="")
   *
  ***
 *****
*******
   *
> 
> N <- 5
> for(i in c(1:N,1))cat(rep(" ",N-i),rep("*",2*i-1),"\n",sep="")
    *
   ***
  *****
 *******
*********
    *
djhurio
fuente
3

Idioma: C, recuento de caracteres: 176 (2 espacios relevantes)

#include <stdio.h>
#define P(x,y,z) for(x=0;x++<y-1;)printf(z);
main(int c,char **v){int i,j,n=atoi(v[1]);for(i=0;i<n;i++){P(j,n-i," ")P(j,2*i+2,"*")printf("\n");}P(i,n," ")printf("*\n");}
Can Berk Güder
fuente
3

Versión de shell, 134 caracteres:

#!/bin/sh
declare -i n=$1
s="*"
for (( i=0; i<$n; i++ )); do
    printf "%$(($n+$i))s\n" "$s"
    s+="**"
done
printf "%$(($n))s\n" "*"

fuente
golfed a 70 bytes :)
roblogic
3

Idioma: Python, Cantidad de caracteres significativa: 90

Es feo pero funciona:

import sys
n=int(sys.argv[1])
print"\n".join(" "*(n-r-1)+"*"*(r*2+1)for r in range(n)+[0])

...

$ python tree.py 13
            *
           ***
          *****
         *******
        *********
       ***********
      *************
     ***************
    *****************
   *******************
  *********************
 ***********************
*************************
            *

fuente
Tu número de personajes es 98 (2 espacios significativos, entre comillas)
3

Como se trata de un CW: no me gusta que los códigos de golf siempre estén organizados en términos de "número de caracteres" o algo así. ¿No podrían organizarse en términos de número de instrucciones para el compilador / intérprete (o algún criterio similar)? Aquí está la solución Ruby nuevamente , y es básicamente la misma, pero ahora también para consumo humano:

SPACE = " "
ASTERISK = "*"
height_of_tree=ARGV[0].to_i
tree_lines = (1..height_of_tree).to_a
tree_lines.push 1 # trunk
tree_lines.each do | line |
   spaces_before = SPACE*(height_of_tree-line)
   asterisks = ASTERISK*(2*line-1) 
   puts spaces_before + asterisks
end
Comunidad
fuente
Estoy de acuerdo con la primera declaración. En tales términos, idiomas como perl tienen una ventaja inicial. Debería ser algo así como el número de estados o similares.
gracias ... ayer hice una pregunta sobre el golf y la forma de hacerlo podría ser con "tokens" ... de esa manera el nombre y la longitud no se penalizan.
2

PHP, 111 caracteres

(El último carácter debería ser una nueva línea).

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

Versión legible:

<?php

$n = $argv[1];

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

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

?>

fuente
Puede guardar varios caracteres construyendo la cadena y luego haciéndola eco. Yo creo que. Prueba eso.
Buena idea, pero lo probé y solo lo hace más largo. '$ t. = (...)' es solo un carácter más corto que 'echo (...)', y luego tendrías que 'echo $ t' al final también.
Se acortó en 4 caracteres al eliminar '$ i = 0;' primera parte de la declaración for. PHP asume que las variables inexistentes utilizadas en un contexto entero ya son 0. : P
Se guardó un carácter poniendo $ r = .. dentro del for. Además, digo que los caracteres de nueva línea deben ser un byte, no dos. =]
Sí, me di cuenta de que contaba mal por uno porque conté usando el número de columna en mi editor de texto. Yo uso Linux, por lo que el carácter de nueva línea es de un byte.