Reputation: 393
I need to make a triangle of triangle pattern of *
depending on the integer input.
For example:
n = 2
*
***
* * *
*********
n = 3
*
***
*****
* * *
*** *** ***
***************
* * * * *
*** *** *** *** ***
*************************
I've already figured out the code for a single triangle, but I don't know how to duplicate them so they'll appear like a triangle of triangles.
Here's my code for one triangle:
rows = int(input())
for i in range(rows):
for j in range(i, rows):
print(" ", end="")
for j in range(i):
print("*", end="")
for j in range(i + 1):
print("*", end="")
print()
Upvotes: 25
Views: 6094
Reputation: 4585
Lots of interesting answers already, but I thought I'd add one that lets Python handle the string centering.
def print_fractal(n, char='*'):
# Width of single triangle
base = 2*n - 1
# Width of overall figure
width = base**2
# Lines containing single triangle padded to rectangle of width `base`
lines = [f'{(2*line + 1)*char:^{base}}' for line in range(n)]
for row in range(n):
# Print (2*row + 1) triangle blocks next to each other
for line in lines:
print(f'{(2*row + 1)*line:^{width}}')
>>> print_fractal(3)
*
***
*****
* * *
*** *** ***
***************
* * * * *
*** *** *** *** ***
*************************
A recursive solution also suggests itself, thanks to inspiration from @Lynn's answer:
def make_fractal(n, depth, block=['*']):
if not depth:
return block
width = (2*n - 1)*max(map(len, block))
lines = []
for row in range(n):
for line in block:
lines.append(f'{(2*row + 1)*line:^{width}}')
return make_fractal(n, depth - 1, lines)
>>> for line in make_fractal(3, 2): print(line)
*
***
*****
* * *
*** *** ***
***************
* * * * *
*** *** *** *** ***
*************************
>>> for line in make_fractal(2, 3): print(line)
*
***
* * *
*********
* * *
*** *** ***
* * * * * * * * *
***************************
>>> for line in make_fractal(2, 2, [' . ', '---']): print(line)
.
---
. . .
---------
. . .
--- --- ---
. . . . . . . . .
---------------------------
Upvotes: 1
Reputation: 71471
Using a helper function to build the sub-triangles:
def tri(n):
r = [(s:=(' '*(((2*n-1)-(2*i-1))//2)))+('*'*(2*i-1))+s for i in range(1, n+1)]
return r
def triangle(n):
v = [''.join(j) for i in range(n+1) for j in zip(*[tri(n) for _ in range(2*i-1)])]
return '\n'.join((s:=' '*((len(v[-1]) - len(i))//2))+i+s for i in v)
for i in range(1, 4):
print(triangle(i))
print('-'*25)
*
-------------------------
*
***
* * *
*********
-------------------------
*
***
*****
* * *
*** *** ***
***************
* * * * *
*** *** *** *** ***
*************************
-------------------------
Upvotes: 2
Reputation: 1925
I have simplified the following code so it should now look more clear easy to understand than it used to be.
n = int(input("n = "))
rows = n ** 2
base = n * 2 - 1
for row in range(rows):
triangle = row // n
level = row % n
a_space = " " * (n - triangle - 1) * base
b_space = " " * (n - level - 1)
line = (a_space + (b_space + "*" * (level * 2 + 1) + b_space)
* (triangle * 2 + 1)).rstrip()
print(line)
This approach prints out everything in one pass. In the following explanation, I will break down the components of the code, what these variables mean, and how they work.
The first variable that I should mention is n
, the number of levels, or the height of every triangle. It is also the number of triangles stacked on top of each other.
The second variable is rows
, the number of rows in the output. We can see a pattern that the number of rows is equal to n
squared.
The next variable is base
. It is the number of asterisks at the bottom level of the triangle. It also follows a pattern of odd numbers as we may have noticed.
After that, our loop begins, iterates through every row, and prints out the result.
These variables tell us which triangle and level of the triangle we are currently at. You can try it yourself by printing out triangle
and level
every iteration.
for row in range(rows):
triangle = row // n
level = row % n
print(triangle, level)
The next part is the indentation. Just to give you a brief idea of what a_space
and b_space
are, here is a visual representation that describes the spaces.
a_space
shrinks after every triangle, and b_space
shrinks after every level.
a_space = " " * (n - triangle - 1) * base
b_space = " " * (n - level - 1)
We multiply a_space
by base
because one a_space
has a length equal to the base.
Let's look at it step-by-step.
- First, we start our line with
a_space
.a_space
- Then, we print out the asterisks. The number of asterisks follows the pattern of odd numbers.
"*" * (level * 2 + 1)
- We open and close the asterisks with
b_space
.b_space + "*" * (level * 2 + 1) + b_space
- Then, we simply multiply the whole thing by the number of triangles stacked next to each other horizontally.
(b_space + "*" * (level * 2 + 1) + b_space) * (triangle * 2 + 1)
Putting everything together, we get the line, right-strip it, and print it out.
line = (a_space + (b_space + "*" * (level * 2 + 1) + b_space)
* (triangle * 2 + 1)).rstrip()
print(line)
Let's try it out with a few test cases.
n = 1
*
n = 2
*
***
* * *
*********
n = 3
*
***
*****
* * *
*** *** ***
***************
* * * * *
*** *** *** *** ***
*************************
n = 4
*
***
*****
*******
* * *
*** *** ***
***** ***** *****
*********************
* * * * *
*** *** *** *** ***
***** ***** ***** ***** *****
***********************************
* * * * * * *
*** *** *** *** *** *** ***
***** ***** ***** ***** ***** ***** *****
*************************************************
Upvotes: 55
Reputation: 10804
Here is what I think this exercise is trying to teach you.
Let's take your triangle code (there is nothing fundamentally wrong with it):
size = int(input())
for i in range(size):
for j in range(i, size):
print(" ", end = "")
for j in range(i):
print("*", end = "")
for j in range(i + 1):
print("*", end = "")
print()
and turn it into a function that returns a list of rows/lines:
def triangle(size):
rows = []
for i in range(size):
row = []
for j in range(i + 1, size):
row.append(" ")
for j in range(2 * i + 1): # i + (i+1) = 2*i+1.
row.append("*")
for j in range(i + 1, size): # Let's add spaces at the end, too.
row.append(" ") # It'll make sense in a moment!
rows.append("".join(row))
return rows
for row in triangle(5):
print(row)
# *
# ***
# *****
# *******
# *********
Now we can tweak it a little bit to work with any rectangular list-of-strings "building block" instead of *
:
def triangle(size, block):
rows = []
for i in range(size):
strip = [[] for _ in block]
for j in range(i + 1, size):
for s, b in zip(strip, block):
s.append(" " * len(b)) # Space as wide as the building block
for j in range(2 * i + 1):
for s, b in zip(strip, block):
s.append(b)
for j in range(i + 1, size):
for s, b in zip(strip, block):
s.append(" " * len(b))
for s in strip:
rows.append("".join(s))
return rows
# Make a triangle out of ["abc",
# "def"]:
for row in triangle(3, ["abc", "def"]):
print(row)
# abc
# def
# abcabcabc
# defdefdef
# abcabcabcabcabc
# defdefdefdefdef
This is somewhat tricky code! Try adding some print()
statements to this code to see how it works. zip()
loops over two lists in parallel. Actually, you should try rewriting this function yourself from scratch.
The payoff is very satisfying: 🙂
fractal = triangle(4, triangle(4, ["*"]))
for row in fractal:
print(row)
# *
# ***
# *****
# *******
# * * *
# *** *** ***
# ***** ***** *****
# *********************
# * * * * *
# *** *** *** *** ***
# ***** ***** ***** ***** *****
# ***********************************
# * * * * * * *
# *** *** *** *** *** *** ***
# ***** ***** ***** ***** ***** ***** *****
# *************************************************
You can of course also now create a "triangle of triangles of triangles":
for row in triangle(2, triangle(2, triangle(2, ["()"]))):
print(row)
# ()
# ()()()
# () () ()
# ()()()()()()()()()
# () () ()
# ()()() ()()() ()()()
# () () () () () () () () ()
# ()()()()()()()()()()()()()()()()()()()()()()()()()()()
The lesson here is that of generalizing a problem: on the face of it, it's hard to make a triangle of triangles (of triangles). But it's relatively easy to make a triangle out of whatever.
If we write some code that can make triangles out of anything (like our abc def
example), we can use that code to make a triangle out of triangles.
Unlike the other answers, we don't need separate logic for the two layers of "triangle" at play here.
Upvotes: 18
Reputation: 85
The program you made to print a single triangle is not helpful in this case as that would mean you have to print these triangles side by side aligned on stdout. It can only be printed line by line, and it's fairly simple to do so. Here's a naive approach not involving any serious mathematics.
rows = int(input())
p = 2 * rows *(rows - 1) # Variable to print the left most spaces
x = " "
for i in range(rows): # For every row
space = 2 * (rows - 1) # Space variable to print spaces after an asterisk when needed
for j in range(rows): # For every row inside the row
print(p * x, end="") # print the left most spaces
for k in range(2*(i + 1) - 1):
print((2*(j + 1) - 1) * "*", end = "") # Print the asterisk(s) based on the row number
print(space * x, end = "") # Print spaces(s) after the asterisk(s)
space -= 2 # Decrement the number of spaces to be printed after an asterisk for every row
p -= 1 # Every row has one lesser space on the left
print() # Print a new line after every row
p -= (rows - 1) # Update the number of spaces to be printed on the left most side for every outer row
Go through the comments above for details. The outputs:
n = 4
*
***
*****
*******
* * *
*** *** ***
***** ***** *****
*********************
* * * * *
*** *** *** *** ***
***** ***** ***** ***** *****
***********************************
* * * * * * *
*** *** *** *** *** *** ***
***** ***** ***** ***** ***** ***** *****
*************************************************
n = 5
*
***
*****
*******
*********
* * *
*** *** ***
***** ***** *****
******* ******* *******
***************************
* * * * *
*** *** *** *** ***
***** ***** ***** ***** *****
******* ******* ******* ******* *******
*********************************************
* * * * * * *
*** *** *** *** *** *** ***
***** ***** ***** ***** ***** ***** *****
******* ******* ******* ******* ******* ******* *******
***************************************************************
* * * * * * * * *
*** *** *** *** *** *** *** *** ***
***** ***** ***** ***** ***** ***** ***** ***** *****
******* ******* ******* ******* ******* ******* ******* ******* *******
*********************************************************************************
And so on. As mentioned already, this is a naive approach for intuition.
Upvotes: 4
Reputation: 7361
Just another alternative with a function to draw the inner triangle and a main function to print the final result
import sys
n = int(sys.argv[1])
def drawtriangle(num_lines):
# prepares the inner triagle in a list and return it together with its width (size).
size = (2*num_lines)-1
triangle = []
for i in range(num_lines):
white_side = num_lines - i - 1
asterisks = 2*i + 1
triangle.append(" "*white_side + "*"*asterisks + " "*white_side)
return triangle, size
def main(num_lines):
tr, tr_size = drawtriangle(num_lines)
for j in range(num_lines):
for line in tr:
white_triangles = n - j - 1
white_size = tr_size * white_triangles
line_repeat = (2*j) + 1
print(" "*white_size + line*line_repeat + " "*white_size)
main(n)
Output:
*
*
***
* * *
*********
*
***
*****
* * *
*** *** ***
***************
* * * * *
*** *** *** *** ***
*************************
*
***
*****
*******
* * *
*** *** ***
***** ***** *****
*********************
* * * * *
*** *** *** *** ***
***** ***** ***** ***** *****
***********************************
* * * * * * *
*** *** *** *** *** *** ***
***** ***** ***** ***** ***** ***** *****
*************************************************
Upvotes: 3