# Triangle of triangles

Given an integer $$\n \geq 2\$$, print a triangle of height $$\n\$$ of (triangles of height $$\n\$$ of asterisks), as in this SO question.

For $$\n=2\$$, print:

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


For $$\n=3\$$, print:

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


For $$\n=4\$$, print:

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


And so on. Some rules:

• I write "print", but a function returning a string or list of lines is fine too.
• Trailing whitespace on each line is allowed, but not leading whitespace.
• Trailing blank lines are allowed.
• This is : write the shortest program you can, measured in bytes.
• This is a bit classic, as far as code golf problems go. But I liked the "single layer of fractal nature", and the solutions offered on the SO question are so wildly different that I'm actually quite curious which is golfiest.
– lynn
Commented Nov 2, 2021 at 13:15
• I like it. A fun variation would be to take the number of times to iterate as a parameter. So you could have a triangle of triangles of triangles, etc... Commented Nov 2, 2021 at 14:30
• Yeah, I can see that argument for why it's a better CG question as is... my comment wasn't meant as a criticism in any way. Just a thought.... Commented Nov 2, 2021 at 16:02
• Can we change * to for example #? Commented Nov 2, 2021 at 17:56
• @LuisMendo no, you can not
– lynn
Commented Nov 2, 2021 at 20:20

# Python 3 with numpy, 79 74 bytes

lambda n:where(kron(*[c_[:n]>=abs(r_[1-n:n])]*2),*'* ')
from numpy import*


Try it online!

-5 thanks to ovs, with the use of where.

Step-by-step example of how it works:

>>> from numpy import*
>>> (n:=2)
2
>>> (Y:=c_[:n])
array([[0],
[1]])
>>> (X:=r_[1-n:n])
array([-1,  0,  1])
>>> (Z:=Y>=abs(X))    # Broadcasts.
array([[False,  True, False],
[ True,  True,  True]])
>>> (A:=kron(*[Z]*2))    # Listify, double, and unpack to give the same argument twice.
array([[False, False, False, False,  True, False, False, False, False],
[False, False, False,  True,  True,  True, False, False, False],
[False,  True, False, False,  True, False, False,  True, False],
[ True,  True,  True,  True,  True,  True,  True,  True,  True]])
>>> (B:=where(A,*"* "))    # Select asterisk for true and space for false.
array([[' ', ' ', ' ', ' ', '*', ' ', ' ', ' ', ' '],
[' ', ' ', ' ', '*', '*', '*', ' ', ' ', ' '],
[' ', '*', ' ', ' ', '*', ' ', ' ', '*', ' '],
['*', '*', '*', '*', '*', '*', '*', '*', '*']], dtype='<U1')

• Using where instead on indexing saves a few bytes: TIO
– ovs
Commented Nov 2, 2021 at 14:29

# J, 37 31 bytes

' *'{~[:,./^:2[:*/~i.>:/|@i:@<:


Try it online!

-6 after seeing the phrase "Kronecker product" in m90's python answer, realizing that's what I was doing, and finding a golfier implementation in this essay.

# MATL, 2916 15 bytes

ZvG:!<~PtX*42*c


Try it online!

### How it works

Consider input 3 as an example. The stack is shown upside down, with the most recent element below.

Zv    % Implicit input. Symmetric range
% STACK: [1 2 3 2 1]
G:    % Push input again. Range
% STACK: [1 2 3 2 1],
[1 2 3]
!     % Transpose
% STACK: [1 2 3 2 1],
[1
2
3]
<~    % Less than?, negate; element-wise with broadcast
% STACK: [1 1 1 1 1
0 1 1 1 0
0 0 1 0 0]
P     % Flip vertically
% STACK: [0 0 1 0 0
0 1 1 1 0
1 1 1 1 1]
tX*   % Duplicate. Kronecker product
% STACK: [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0
0 0 0 0 0 0 1 1 1 0 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0
0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0
0 1 1 1 0 0 1 1 1 0 0 1 1 1 0 0 1 1 1 0 0 1 1 1 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
42*   % Multiply by 42 (ASCII for '*'). Convert to char
% Implicit display. Char 0 is displayed as space
% STACK: ['            *            '
'           ***           '
'          *****          '
'       *    *    *       '
'      ***  ***  ***      '
'     ***************     '
'  *    *    *    *    *  '
' ***  ***  ***  ***  *** '
'*************************']

• You could maybe port the python + numpy answer? Should be less than 20 bytes, I think. Commented Nov 2, 2021 at 18:38
• @Giuseppe I was working precisely on this edited version using the Kronecker product. Thanks! Commented Nov 2, 2021 at 18:41

# C (gcc), 160 153 148 bytes

p(c,n){n&&p(putchar(c),n-1);}r;t;l;i;f(n){for(r=0;r<n*n;p(10,1))for(t=r/n,l=r++%n,p(32,(n+~t)*(n*2-1)),i=t-~t;i--;p(32,n+~l))p(32,n+~l),p(42,l-~l);}


Try it online!

Saved 7 bytes thanks to ceilingcat!!!

# C (gcc), 107 bytes

m,x,y;f(n){for(y=n*n;y--;)for(x*=x=m=2*n-1;x--;)putchar(abs(x%m-n+1)+y%n<n&abs(x/m-n+1)+y/n<n?42:x?32:10);}


Try it online!

-1 byte by ceilingcat

# Python 3.8, 9186 84 bytes

-2 bytes thanks to Lynn!

lambda n:[f"{(o%n*'**'+'*').center(w:=2*n-1)*(o//n*2+1):^{w*w}}"for o in range(n*n)]


Try it online!

• You can save two bytes using f-strings for the outer centering: lambda n:[f"{(o%n*'**'+'*').center(w:=2*n-1)*(o//n*2+1):^{w*w}}"for o in range(n*n)]
– lynn
Commented Nov 3, 2021 at 17:28
• @Lynn thanks a lot, for some reason I discarded that idea after noticing that this can't be used for both centerings.
– ovs
Commented Nov 5, 2021 at 13:27

# Ruby, 76 bytes

->n{(0...n*n).map{|i|((?**(i%n*2+1)).center(j=n*2-1)*(i/n*2+1)).center j*j}}


Try it online!

# Charcoal, 25 bytes

ＮθＦθＦ⊕⊗ι«Ｊ×⊖⊗θ⁻κι×θιＧ↗↘θ*


Try it online! Link is to verbose version of code. Explanation:

Ｎθ


Input n.

Ｆθ


Loop over each row.

Ｆ⊕⊗ι«


Loop over each of the 2i+1 triangles in each row.

Ｊ×⊖⊗θ⁻κι×θι


Jump to the (bottom left of the) triangle.

Ｇ↗↘θ*


Draw the triangle.

24 bytes if a leading blank line is allowed:

ＮθＦθ«Ｍ×⊖⊗θ⊗ιθＦ⊕⊗ι«Ｇ↖↙θ*←


Try it online! Link is to verbose version of code. Explanation:

Ｎθ


Input n.

Ｆθ«


Loop over each row.

Ｍ×⊖⊗θ⊗ιθ


Jump to the end of the row.

Ｆ⊕⊗ι«


Loop over each of the 2i+1 triangles in each row.

Ｇ↖↙θ*


Draw the triangle.

←


Move to the next triangle.

# Ruby, 82 74 bytes

->n{(r=1.step n+=n-1,2).map{|x|r.map{|y|((?**y).center(n)*x).center n*n}}}


Try it online!

Good golfers copy, great golfers steal.

• I saw your now deleted comment on my answer but I was at work. I acknowledge that my answer was similar to your original answer but I didn't copy - there's a comment in my TIO with the expansion of (2x-1)**2 which was originally part of my code. We just converged on similar solutions. I see you've removed the g function and inlined the centers so it now looks superficially even more like mine. I congratulate you on your improved looping. Commented Nov 3, 2021 at 18:33
• @LevelRiverSt No problem, the comment was meant as a joke, but reading it twice it looked too serious and I had to remove it. The real improvement was not inlining the g function, but nesting 2 maps, which is a different approach. I tried to remove one of the 2 center() but it's no improvement.
– G B
Commented Nov 3, 2021 at 20:56

# Vyxalj, 25 bytes

d‹£²ʁƛ?%›‛***Ḣ¥⋏n?ḭd›*¥²⋏


Try it Online!

I think mirroring might help, but cannot think of how

# VyxalC, 15 bytes

ƛd‹?ɾ×*vømøĊ*;f


Try it Online!

ƛ            ;  # Map 1...n to...
?ɾ           # 1...input...
×*         # Asterisks
vøm      # Each palindromised
øĊ    # Centered
*   # Repeated...
d‹             # (2 * value) - 1 times
f # Flatten
# (C flag) output centered


17 bytes without the flag by appending a øĊ.

# Japt, 18 17 16 bytes

ÇÑÄ
ïÈçYçÑ ûUÌÃû


Try it

o_ÑÄ         - range [0..input] *2+1
ï          - pair each with itself
È         - then pass pairs by f(X,Y)
ç        - repeat result X times
YçÑ    - repeat '*' Y times
ûNÑÉ       - centre pad
Ãû         - centre pad all


# Python 3.8 (pre-release), 111 100 bytes

f=lambda n,b=['*'],p=1:p>2 and b or f(n,[f'{2*r*l+l:^{(2*n-1)**p}}'for r in range(n)for l in b],p+1)


Try it online!

Nowhere near the best Python 3 answers, but it's got recursion. See my answer on the source SO question for an ungolfed version with the same mechanisms.

-11 bytes thanks to @ovs

• You can do all the string formatting with a single f-string: Try it online! (The f= has to be included in the byte count because the recursive function relies on being assigned to that name)
– ovs
Commented Nov 5, 2021 at 13:30
• Cheers, I had wanted for something like that to work. Good point about the f=.
– Seb
Commented Nov 5, 2021 at 13:32

# R, 82 bytes

function(n)write(c(" ","*")[1+(z=outer(c(n:1,2:n),1:n,"<="))%x%z],1,(2*n-1)^2,,"")


Try it online!

# Pip, 39 bytes

YPZ0Xa-_.1X_M\,a(J*Z_M_*^yMMy)TRt"* "Jn


Replit! Or, here's a 41-byte equivalent in Pip Classic: Try it online!

### Explanation

We create a structure out of 0's and 1's and then use it for both the micro- and macro-structure of the desired output.

YPZ0Xa-_.1X_M\,a
a  First command-line argument
\,   Inclusive range from 1 to that number
M     To each element of that range, map this function:
a-_           a minus the function argument
0X              That many 0's
_       Function argument
1X        That many 1's
.          Concatenate those two strings
PZ                Palindromize
Y                 Yank the resulting list of strings into the y variable


For example, with an input of 3, y is [00100; 01110; 11111].

(J*Z_M_*^yMMy)TRt"* "Jn
MMy            Map this function to each character of each string in y:
y                Take another copy of y
^                 Split it into a list of lists of characters
_*                  Multiply each character by the function argument
M                   To each sublist of the resulting list, map this function:
Z_                     Transpose
J*                       Join each sublist of the transposition into a single string
(            )TR         Transliterate the result:
t         Replace characters "10"
"* "     with characters "* "
Jn  Join on newlines


# Julia 1.0, 68 bytes

~n=2n-1
!n=[' '^(2n^2-j*~n-i)*rpad('*'^~i,~n)^~j for i=1:n,j=1:n][:]


Try it online!

I wish Julia had a center function

output is a list of lines

# Kotlin, 186 bytes

val p={n:Int->for(p in n downTo 1)for(l in n downTo 1)for(g in n-1 downTo 1-n)for(c in n-1 downTo 1-n)print(when{p+Math.abs(g)<=n&&l+Math.abs(c)<=n->'*'
g!=1-n||c!=1-n->' '
else->'\n'})}


Try it online!

# 05AB1E, 19 bytes

·ÅÉεIL'*×.Bí€û×}˜.c


Explanation:

·                # Double the (implicit) input-integer
ÅÉ              # Push a list of all odd numbers smaller than or equal to this 2*input
ε             # Map over each odd integer:
IL           #  Push a list in the range [1,input] again
'*×       '#  Repeat "*" each integer amount of times as string
.B      #  Box this list of strings, adding trailing spaces to make them all of
#  equal length
í     #  Reverse each so the spaces are leading
€û   #  Palindromize each string
×  #  Repeat each the current odd integer amount of times
}˜            # After the map: flatten the list of lists
.c          # Join this list of strings by newlines, and centralize it
# (after which it is output implicitly as result)


# 05AB1E, 16 bytes

L'*×j.ºиøā·<×˜.C


Try it online!

L                -- range from 1 to n
'*×             -- repeat "*" that many times
j            -- pad to length n with spaces to the left
.º          -- self-intersected mirror
и         -- for each string, make a list of n copies
​ ø        -- transpose to get the rows of the big triangle
​​         ā       -- get the range from 1 to the number of rows (n)
​·<     -- double and decrement to get a list of the first n odd numbers
​×    -- repeat each string in the i-th row 2*i-1 times
​˜   -- flatten into a list of lines
​.C -- center and join by newlines


Try it with step-by-step output!