Hacker Challenge: Printing a Star Pattern 2
Let's look at another approach to displaying a star pattern.
Printing a star pattern using nested loops
In this lesson, we’ll look at another approach to creating the star pattern.
Problem statement
Write a program that takes the height
(has to be a multiple of 4) as the input from the user and prints a star, as the shown below. The following shape is of height 12:
*
***
*****
*****************
***************
*************
*************
***************
*****************
*****
***
*
Before we look at another solution, let’s first recall what our first solution was.
In the previous lesson, we divided the star into four segments and wrote code for each segment.
Alternative approach
Note that we can also view the star pattern as two triangles. Let’s call them the upper and lower triangle.
Look at the image below to see what we mean. For our current approach, let’s focus on the star that’s on the right in the illustration below.
Below is a breakdown of the pattern, which can help us understand it.
Height: 12--------* //8 spaces and 1 asterisk-------*** //7 spaces and 3 asterisks------***** //6 spaces and 5 asterisks***************** //0 spaces and 17 asterisks-*************** //1 space and 15 asterisks--************* //2 spaces and 13 asterisks--************* //2 spaces and 13 asterisks-*************** //1 space and 15 asterisks***************** //0 space and 17 asterisks------***** //6 spaces and 5 asterisks-------*** //7 spaces and 3 asterisks--------* //8 spaces and 1 asterisk
Also, if we look at the number of asterisks, they are odd. We can also see the pattern of spaces (where a space is replaced by -
so that we can count it quickly).
So let’s begin!
Discussion of the approach
In this second approach, we’ll begin by using five for
loops.Then using the function, we will transform it into two loops only!
Instead of writing code to print each segment separately, we can print the upper and lower triangles.
Idea
-
We can write an outer
for
loop that runs till the height of the star. -
Then, since the upper triangle should be printed in the first and third segments, we can write an
if
condition that executes the body only ifln <= h/4
(ln >= h/2
andln <= h_t
) whereh_t = 3 * h/4
. -
Similarly, to print the lower triangle (the second and fourth segments), we can again write an
if
condition that executes the body only if (ln >= h/4
andln <= h/2
) or ifln >= h_t
whereh_t = 3 * h/4
.
As these two are the only possibilities, we can write the code for the lower triangle in the else
part instead of a separate if
condition. This way, it would be even more efficient.
So the main flow of this function would be as follows:
for (int ln = 1; line <= h; line++){// printing upper triangleif (line <= h / 4.0 || (line > h / 2.0 && line <= triHeight)){// code to print spaces and asterisks}// printing lower triangle//if ((line > h / 4.0 && line < h / 2.0) || line > triHeight)else // instead, use else{// code to print spaces and asterisks}}
Then, inside the if
statements, we can write for
loops to print spaces and asterisks. To observe the number of spaces and asterisks required in each line of each segment, we can write conditions inside the for
loops.
Let us once again look at the star illustration.
Let’s call the starting point of the upper triangle upperln
, which is equal to ln
.
Let the starting point of the lower triangle be lowerln
which would then be equal to ln - h/4
Here the first line of the lower triangle would be ln = h/4+1
and the second line of the lower triangle would be ln = h/4+2
and so on.
Before we figure out the pattern for both the triangles, first note that there is a transformation needed from the ln
of the star to the line number of the upper triangle, which we call upperln
, and to the line number of the lower triangle called lowerln
. It’s not hard to see that upperln = ln
.However the lowerln
is shifted by ln-h_s
This means that ln=h/4+1
is basically the first line of the lower triangle and ln=h/4+2
is the second line of the lower triangle. Hence ln-h_s
.
Now let us make the pattern in terms of upperln
, h_t
, and lowerln
.
Look at the tables below.
Upper triangle
Line # | Space (' ') | Asterisks ('*') |
1 | h_t - 1 | 1 |
2 | h_t - 2 | 2 |
3 | h_t - 3 | 3 |
. | . | . |
. | . | . |
upperln | h_t - upperln | 2*upperln-1 |
The pattern for the lower triangle is as below.
Lower triangle
Line # | Space (' ') | Asterisks ('*') |
1 | 0 | 2*h_t - 1 |
2 | 1 | 2*h_t - 2 |
3 | 2 | 2*h_t - 3 |
. | . | . |
. | . | . |
lowerln | lowerln - 1 | 2*h_t - n |
So, the conditions inside the for
loops can be written as per the observed patterns in the tables above.
Let’s add all the code inside the printStar()
function and click Run
.
#include <iostream>using namespace std;void printStar(int h){int h_t = 3*h/4;for(int ln=1; ln<=h; ln++){if(ln<=h/4 || (ln>h/2 && ln<=3*h/4)){ // get activated in segment 1 and 3int upperln =ln;for(int sp=1; sp<= h_t - upperln ; sp++)cout << " ";for(int sym = 1; sym<= upperln*2-1; sym++)cout << "*";}else // get activated in segment 2 and 4{int lowerln = ln-h/4;for(int sp=1; sp<=lowerln-1; sp++)cout << " ";for(int sym = 1; sym<= 2*h_t - (lowerln*2-1); sym++)cout << "*";}cout << endl;}}int main(){printStar(8);return 0;}
Solution (revisited): Simplifying using a print
function
Let’s refine our code a bit. The idea is that if you look at all the shape printing tasks we have performed so far, they require a nested loop; the outer loop is going over each line and, inside the loop, we have several nested loops for printing several printing tasks for each line. All the nested inside loops can get too much and can be completely avoided and replaced by general function calls.
We can make a generic function that takes a character symbol
and a value k
as parameters and it prints the symbol
k times.
Here is its implementation:
void printASymbolKTimes(char symbol, const int k){for (int t = 1; t <= k; t++)cout << symbol;}
Now, using this function we can very easily avoid each nested inner loop by a call to this function which can be used to print any symbol, be it a space *
or any other symbol.
Look at this much simplified and elegant implementation of the same star printing code:
#include <iostream> using namespace std; void printASymbolKTimes(char symbol, const int k) { for (int t = 1; t <= k; t++) cout << symbol; } void printStar(char symbol, int h) { int h_t = 3*h/4; for(int ln=1; ln<=h; ln++) { if(ln<=h/4 || (ln>h/2 && ln<=3*h/4)) { int upperln =ln; printASymbolKTimes(' ', h_t - upperln); // for(int sp=1; sp<= h_t - upperln ; sp++) // cout << " "; printASymbolKTimes(symbol, upperln*2-1); // for(int sym = 1; sym<= upperln*2-1; sym++) // cout << symbol; } else { int lowerln = ln-h/4; printASymbolKTimes(' ', lowerln-1); // for(int sp=1; sp<=lowerln-1; sp++) // cout << " "; printASymbolKTimes(symbol, 2*h_t - (lowerln*2-1)); // for(int sym = 1; sym<= 2*h_t - (lowerln*2-1); sym++) // cout << symbol; } cout << endl; } } int main() { int height; char symbol; cout << "Symbol of the star: "; symbol='*';//cin >> symbol; cout << "Height of the star (should be a multiple of 4): \n"; height=12;//cin >> height; printStar(symbol, height); return 0; }
Instruction: Execute the above implementation code line-by-line and observe that the code is doing the same task. printASymbolKTimes()
call has just made the implementation looks cleaner and easily comprehensible.
In the upcoming lessons, we will further use this simplification and exercise several other shapes printing based on this idea.
Before moving forward, take a small pause and mentally exercise your brain on how will the implementations of shape printing, which we did in the previous lessons can be much more easily replaced by one loop and the call to printASymbolKTimes()
.
Practice Exercise: Using the helper function
Write the logic of the given patterns on paper and think about how we can improve/optimize the implementation.
Height: 6
Symbol: *
* ****** ****** *
** ***** ***** **
*** **** **** ***
**** *** *** ****
***** ** ** *****
****** * * ******
(A) (B) (C) (D)
#include <iostream>using namespace std;void printASymbolKTimes(char sym, int K){for(int i=1; i<=K; i++)cout << sym;}void TA(int H){for(int ln=1; ln<=H; ln++){// Write code here}}void TB(int H){for(int ln=1; ln<=H; ln++){// Write code here}}void TC(int H){for(int ln=1; ln<=H; ln++){// Write code here}}void TD(int H){for(int ln=1; ln<=H; ln++){// Write code here}}int main() {// your code goes hereint H = 10;cout << "Triangle A"<<endl;TA(H);cout << "\n\nTriangle B"<<endl;TB(H);cout << "\n\nTriangle C"<<endl;TC(H);cout << "\n\nTriangle D"<<endl;TD(H);cout << endl;return 0;}