Hacker Challenge: Printing a Star Pattern 2

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.

Press + to interact
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

  1. We can write an outer for loop that runs till the height of the star.

  2. 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 if ln <= h/4 (ln >= h/2 and ln <= h_t) where h_t = 3 * h/4.

  3. 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 and ln <= h/2) or if ln >= h_t where h_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:

Press + to interact
for (int ln = 1; line <= h; line++)
{
// printing upper triangle
if (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/4Here 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.

Press + to interact
#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 3
int 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:

Press + to interact
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;
}





Complete solution of star printing

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)
Press + to interact
#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 here
int 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;
}