1. ## Draw a triangle

My book has an exercise that wants me to draw a triangle. Here's the example shape.
Code:
```    *
***
*****
*******
*********```
But I have to get the height from the keyboard, so it can't aways be 5 lines. I got the right shape by drawing spaces, but I don't think that's the best way. I mean, it's a lot of code for something that simple. How can I make my program better? Here's the C++ code for it.
Code:
```#include <iostream>

using std::cout;

int main()
{
int lengthRow = 1;
int lengthLine;

cout << "Height of triangle? ";
std::cin >> lengthLine;

// loop includes 0, so take 1 away for right number of lines
--lengthLine;

// draw triangle with lengthLine lines
for (int line = lengthLine; line >= 0; --line)
{
// draw smaller number of spaces each time
for (int margin = 0; margin < line; ++margin)
{
cout << " ";
}

// draw greater number of stars each time
for (int row = 0; row < lengthRow; ++row)
{
cout << "*";
}

cout << "\n";
lengthRow += 2; // add one star to each side
}

return 0;
}```
Thank you!

2. > cout << "Height of triangle? ";
> std::cin >> lengthLine;
So why didn't you call your variable heightOfTriangle ?

Then derive from that another variable called lengthRow?

> How can I make my program better?
Both printing for loops do the same thing, so create a function, say
Code:
```void draw ( char ch, int len ) {
for ( int i = 0 ; i < len ; i++ ) cout << ch;
}```
Which would simplify your main loop to
Code:
```draw( ' ', line );
draw( '*', lengthRow );```
Better is subjective, and measured in many different ways rather than just counting how many characters are in your source file.

3. You can do with I/O manip too:
Code:
```#include <iomanip>
#include <iostream>
using namespace std;
int height;
int chrsk = 1;
int crntst = 0;
char chr;
int i = 0;
void resetVars(){
height = 0;
chr = 0;
i = 0;
crntst = 0;
chrsk = 1;
}
int main()
{
char endsequence='n';
do{
system("cls");
resetVars();
cout<<"Enter height: \n";
cin>>height;
cin.ignore();
cout<<"Enter symbol: \n";
cin>>chr;
cin.ignore();
cout<<"Generating triangle...\n";
do{
cout<<setfill(' ')<<setw(height-crntst)<<" "<<setfill(chr)<<setw(chrsk)<<chr<<endl;
crntst++;
chrsk = chrsk + 2;
i++;
}
while(i!=height);
cin.ignore();
cout<<"Again? y/n \n";
cin>>endsequence;
cin.ignore();
}
while (endsequence=='y');
}```

4. *cough* indent *cough*

5. You can look at the exercise from a conceptual manner too.

The first thing that can strike you is that you are being asked to draw spaces and asterisks. So in fact you are being asked to draw a rectangle. And you even already have one of the sizes; the number of lines gives you the height. You can then expand on this concept to devise the formula that will enable you to know the width. For that, you now need to look at the triangle itself.

You need to find a pattern you can use as a formula. For that, why not start with the last line and see what properties we can find as we move up the triangle? We could also start from the top. However, patterns are usually less challenging when working with bigger numbers and they can also break when we work with the number 1 or 0. e.q. More often than not we need to create an exception when the significant element of the formula (the element that grows or shrinks) is 1 or 0. So it's easier to start from the bottom where the bigger numbers are and then see if that exception needs to be created.

So... the last line in your example is line 5 and it has 9 asterisks. The height of your rectangle is 5 and the width is 9. Next...

Code:
```(line 5, height = 5, width = 9)
line 4, height = 4, width = 7
line 3, height = 3, width = 5
line 2, height = 2, width = 3
line 1, height = 1, width = 1```
What can we see as a pattern? Before you read further on, take some time to try and see it yourself...

Well, each line width is equal to line_height * 2 - 1. And it even works with 1! Although it will break with 0. You cannot have -1 asterisks.

So... with that formula you can now easily create your triangle with just one for loop. The best way is to first store the width in an integer before you enter the loop. Each line will be equal to:

(overall_width - line_width) / 2 in spaces concatenated to,
line_width in asterisks concatenated to,
(overall_width - line_width) / 2 in spaces.

The only other care you will need to have is to either not accept 0 as an input for the height of the triangle or accept it, but output an empty string.

6. Originally Posted by Salem
> cout << "Height of triangle? ";
> std::cin >> lengthLine;
So why didn't you call your variable heightOfTriangle ?

Then derive from that another variable called lengthRow?
I added keyboard input after getting the loops to work. I like your name better.
Originally Posted by Salem
Both printing for loops do the same thing, so create a function, say
Code:
```void draw ( char ch, int len ) {
for ( int i = 0 ; i < len ; i++ ) cout << ch;
}```
Which would simplify your main loop to
Code:
```draw( ' ', line );
draw( '*', lengthRow );```
I think I understand. But doesn't that still do the same thing? I thought that there would be a way to choose where to draw on the screen. Drawing spaces doesn't seem very clean.
You can do with I/O manip too:
Sorry, but I don't understand any of that.
Well, each line width is equal to line_height * 2 - 1. And it even works with 1! Although it will break with 0. You cannot have -1 asterisks.

So... with that formula you can now easily create your triangle with just one for loop. The best way is to first store the width in an integer before you enter the loop. Each line will be equal to:

(overall_width - line_width) / 2 in spaces concatenated to,
line_width in asterisks concatenated to,
(overall_width - line_width) / 2 in spaces.

The only other care you will need to have is to either not accept 0 as an input for the height of the triangle or accept it, but output an empty string.
I see the pattern, but I couldn't figure out how to draw the triangle like you said with just one loop. I remembered reading something about strings in my book, and with the pattern you found, I did this. I had to copy a bunch of stuff from the book though, and I'm not sure I really understand how it works...
Code:
```#include <iostream>
#include <string>

using std::cout;
using std::string;

int main()
{
int heightTriangle;

cout << "Height of triangle? ";
std::cin >> heightTriangle;

// draw triangle with heightTriangle lines
for (int line = 1; line <= heightTriangle; ++line)
{
// Create a string with less spaces each time
string spaces(heightTriangle - line, ' ');

// Create a string with more stars each time
string stars(line * 2 - 1, '*');
string lineToPrint = spaces + stars;

cout << lineToPrint << "\n";
}

return 0;
}```
It's not really a square. Is that okay? It also doesn't have any problems with 1 or 0, but how would I not accept 0 if it did?

7. Use append(), for instance, and work with the formulas you discovered.

Code:
```int height = 5 // this value you get from the user input
int width = height * 2 - 1  // this is the formula you discovered

std::string yourString = "";  // initialize the string
for(int i = 1; i <= height; ++i ) {
yourString.append(spaces_formula_result, ' ')
yourString.append(asterisks_formula_result, '*')
yourString.append(spaces_formula_result, ' ')
yourString.append('\n')
}```
I'm not writing it all to you on purpose. But do let me know if there is anything specific you didn't understand on my previous post.

EDIT: you don't need to use strings if you don't want to. You can still use std::cout.

Code:
```#include <iomanip>

for(int i = 1; i <= height; ++i ) {
std::cout << setw(spaces_formula_result) << setfill(' ');
std::cout << setw(asterisks_formula_result) << setfill('*');
std::cout << setw(spaces_formula_result) << setfill(' ');
std::cout << std::endl;
}```

8. > But doesn't that still do the same thing?
Of course it does, the point was to show that you can extract similarity in duplicate code by adding parameters.

> I thought that there would be a way to choose where to draw on the screen
But where do you stop?
- position on screen
- change the font
- change colours
- animation / sound
Yes you can add all these things (and more), but the code will grow to do this.

Book exercises test understanding of fundamental ideas, and this one is about loops.

9. I understand, and now I have tons of new stuff to look up. Thank you everyone for your help.

p.s. I finally managed to get the iomanip stuff to work. Here's what I came up with.
Code:
```#include <iomanip>
#include <iostream>

using std::cout;
using std::setw;
using std::setfill;

int main()
{
int heightTriangle;

cout << "Height of triangle? ";
std::cin >> heightTriangle;

// highest possible number of spaces
const int width = (heightTriangle * 2 - 1) / 2;

for (int line = 1; line <= heightTriangle; ++line)
{
// number of stars in this line
const int widthLine = line * 2 - 1;

cout << setw(width - widthLine / 2) << setfill(' ') << "";
cout << setw(widthLine) << setfill('*') << "";
cout << "\n";
}

return 0;
}```
The only way I could get it to work is by drawing empy strings. If I didn't do that then nothing would happen or the shape would be wrong. Can anyone point me to something that explains why? Thanks!